Упрощение замены объекта date строками" сегодня "и" вчера " в статическом методе Java

У меня есть следующий метод, который я хотел бы сделать короче или быстрее, если ничего другого. Пожалуйста, все комментарии приветствуются:

метод Bellow принимает объект date, формирует его ("EEE hh:mma MMM d, yyyy"), а затем вычисляет, является ли дата сегодня или вчера, и чем, если это так, она возвращает" (вчера | сегодня) HH:MMA " formated string.

    public static String formatToYesterdayOrToday(String date) {
    SimpleDateFormat sdf = new SimpleDateFormat("EEE hh:mma MMM d, yyyy");
    Date in = null;

    try {
        in = sdf.parse(date);
    } catch (ParseException e) {
        log.debug("Date parsing error:", e);
    }

    Calendar x = Calendar.getInstance();
    x.setTime(in);

    String hour = Integer.toString(x.get(Calendar.HOUR));
    String minute = Integer.toString(x.get(Calendar.MINUTE));
    String pm_am = x.get(Calendar.AM_PM) == Calendar.AM ? "AM" : "PM";

    x.set(Calendar.HOUR, 0);
    x.set(Calendar.HOUR_OF_DAY, 0);
    x.set(Calendar.MINUTE, 0);
    x.set(Calendar.SECOND, 0);
    x.set(Calendar.MILLISECOND, 0);

    Calendar today = Calendar.getInstance();
    today.set(Calendar.HOUR, 0);
    today.set(Calendar.HOUR_OF_DAY, 0);
    today.set(Calendar.MINUTE, 0);
    today.set(Calendar.SECOND, 0);
    today.set(Calendar.MILLISECOND, 0);

    Calendar yesterday = Calendar.getInstance();
    yesterday.set(Calendar.HOUR, 0);
    yesterday.set(Calendar.HOUR_OF_DAY, 0);
    yesterday.set(Calendar.MINUTE, 0);
    yesterday.set(Calendar.SECOND, 0);
    yesterday.set(Calendar.MILLISECOND, 0);
    yesterday.add(Calendar.DATE, -1);

    if (x.compareTo(today) == 0) {
        return "Today " + hour + ":" + minute + pm_am;
    }
    if (x.compareTo(yesterday) == 0) {
        return "Yesterday " + hour + ":" + minute + pm_am;
    }
    return date;
}

9 ответов


вот как вы могли бы улучшить его со стандартным API:

public static String formatToYesterdayOrToday(String date) throws ParseException {
    Date dateTime = new SimpleDateFormat("EEE hh:mma MMM d, yyyy").parse(date);
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(dateTime);
    Calendar today = Calendar.getInstance();
    Calendar yesterday = Calendar.getInstance();
    yesterday.add(Calendar.DATE, -1);
    DateFormat timeFormatter = new SimpleDateFormat("hh:mma");

    if (calendar.get(Calendar.YEAR) == today.get(Calendar.YEAR) && calendar.get(Calendar.DAY_OF_YEAR) == today.get(Calendar.DAY_OF_YEAR)) {
        return "Today " + timeFormatter.format(dateTime);
    } else if (calendar.get(Calendar.YEAR) == yesterday.get(Calendar.YEAR) && calendar.get(Calendar.DAY_OF_YEAR) == yesterday.get(Calendar.DAY_OF_YEAR)) {
        return "Yesterday " + timeFormatter.format(dateTime);
    } else {
        return date;
    }
}

вот как вы могли бы сделать это с Jodatime:

public static String formatToYesterdayOrToday(String date) {
    DateTime dateTime = DateTimeFormat.forPattern("EEE hh:mma MMM d, yyyy").parseDateTime(date);
    DateTime today = new DateTime();
    DateTime yesterday = today.minusDays(1);
    DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("hh:mma");

    if (dateTime.toLocalDate().equals(today.toLocalDate())) {
        return "Today " + timeFormatter.print(dateTime);
    } else if (dateTime.toLocalDate().equals(yesterday.toLocalDate())) {
        return "Yesterday " + timeFormatter.print(dateTime);
    } else {
        return date;
    }
}

вы написали "все комментарии приветствуются", поэтому вот мой способ использования joda-time. :)

Я поклонник отображения дат и времени коротким и умным способом последних вызовов iPhone (подобно сообщениям Google wave). Это "чч:мм" если сегодня "вчера" или название дня недели если гггг-ММ-ДД.

private static boolean isToday (DateTime dateTime) {
   DateMidnight today = new DateMidnight();
   return today.equals(dateTime.toDateMidnight());
}

private static boolean isYesterday (DateTime dateTime) {
   DateMidnight yesterday = (new DateMidnight()).minusDays(1);
   return yesterday.equals(dateTime.toDateMidnight());
}

private static String getDayString(Date date) {
    String s;

    if (isToday(new DateTime(date)))
        s = "Today";
    else if (isYesterday(new DateTime(date)))
        s = "Yesterday";
    else
        s = weekdayFormat.format(date);

    return s;
}

public static String getDateString_shortAndSmart(Date date) {
    String s;

    DateTime nowDT = new DateTime();
    DateTime dateDT = new DateTime(date);
    int days = Days.daysBetween(dateDT, nowDT).getDays();

    if (isToday(new DateTime(date)))
        s = getHourMinuteString(date);
    else if (days < 7)
        s = getDayString(date);
    else
        s = getDateString(date);

    return s;
}

где я использую набор SimpleDateFormat (как weekdayFormat выше) для форматирования времени до нужных строк и где DateTime и DateMidnight-это классы времени joda.

в этих случаях количество дней, прошедших между двумя DateTime: s менее важно, чем то, как люди будут определять время, говоря об этом. Вместо того, чтобы считать дни (или миллисекунды, как я видел некоторых людей) DateMidnight пригодится здесь, хотя другие методы будут работать так же хорошо. :)


другой способ сравнения дат, кроме принятого ответа выше, используя java.утиль.Дата.getTime () (Примечание: вместо int следует использовать long):

Date today=new Date();
Date dateObj=null;
long diff=0;
try{
    dateObj= formater1.parse(date);
    diff=(today.getTime()-dateObj.getTime())/(86400000);
}catch(Exception e){}
String days="TODAY";
if(diff==1){
    days = "YESTERDAY";
}else if(diff>1){
    days = String.valueOf(diff) + " " +"DAYS AGO";
}

вернет:

x дней назад


мое понимание вопроса заключается в том, чтобы предоставить простой метод для получения следующего результата:

Today at 20:00
Today at 20:30
Today at 21:00
Tomorrow at 06:45
Tomorrow at 07:00
Tomorrow at 08:15

код ниже работал для меня, но я новичок в android, и, возможно, другие могли бы указать, если код не является надежным. в коде ниже 'timeLong' - время события-время (в миллисекундах).

public String convertFromEpochTime (long timeLong) {
    long timeNow = System.currentTimeMillis();

    // get day in relative time
    CharSequence timeDayRelative;
    timeDayRelative = DateUtils.getRelativeTimeSpanString(timeLong, timeNow, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);

    // get hour in 24 hour time
    Format hourFormatter = new SimpleDateFormat("HH:mm");
    String timeHour = hourFormatter.format(timeLong);

    // Log.d(DEBUG_TAG, "time of event: " + timeDayRelative + " at " + timeHour);

    String timeDayHour = timeDayRelative + " at "+ timeHour;

    return timeDayHour;
}

это на сегодня, вчера, завтра

String formatDate(String fecha){

    String Rfecha=new String();
     SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
     //SimpleDateFormat formatter2 = new SimpleDateFormat("EEEE d MMM");
     SimpleDateFormat formatter2 = new SimpleDateFormat("E, d MMM ");
        try {
           Date hoy=new Date();

            Date date = formatter.parse(fecha);


            String pref="";
           Log.d("hoy long", ""+(hoy.getTime()/ (1000*60*60*24)));
           Log.d("date long", ""+ (date.getTime()/ (1000*60*60*24)));

           int ihoy=(int) (hoy.getTime()/ (1000*60*60*24));
           int idate=(int) (date.getTime()/ (1000*60*60*24));
           int dif=idate-ihoy;



           if(dif==0)
               pref="Today";
           if(dif==1)
               pref="Tomorrow";
           if(dif==-1)
               pref="Yesterday";

            Rfecha=pref+" "+formatter2.format(date);


        } catch (Exception e) {
            e.printStackTrace();
        }

    return Rfecha;
}

посмотрите на jodatime: http://joda-time.sourceforge.net/

Это пример кода из doc:

public boolean isAfterPayDay(DateTime datetime) {
  if (datetime.getMonthOfYear() == 2) {   // February is month 2!!
    return datetime.getDayOfMonth() > 26;
  }
  return datetime.getDayOfMonth() > 28;
}

public Days daysToNewYear(LocalDate fromDate) {
  LocalDate newYear = fromDate.plusYears(1).withDayOfYear(1);
  return Days.daysBetween(fromDate, newYear);
}

public boolean isRentalOverdue(DateTime datetimeRented) {
  Period rentalPeriod = new Period().withDays(2).withHours(12);
  return datetimeRented.plus(rentalPeriod).isBeforeNow();
}

public String getBirthMonthText(LocalDate dateOfBirth) {
  return dateOfBirth.monthOfYear().getAsText(Locale.ENGLISH);
}

Часовой Пояс

вопрос и другие ответы игнорируют важную проблему часового пояса. В этой входной строке отсутствует часовой пояс или смещение от-UTC. Таким образом, эта строка будет проанализирована, предполагая, что она представляет дату-время в текущем часовом поясе JVM по умолчанию. Рискованный бизнес, как (А), что предположение может быть ложным, и (Б), что по умолчанию может измениться в любой момент, даже во время во время выполнения.

Locale

Вопрос и другие ответы игнорируют еще один важный вопрос:Locale. Локаль определяет человеческий язык, используемый для перевода имени дня и имени месяца из входной строки во время синтаксического анализа (и генерации).

если не указано, текущая Локаль JVM по умолчанию будет использоваться для перевода. Как и в часовом поясе, Локаль по умолчанию вашего JVM может измениться в любой момент, даже во время во время выполнения.

лучше указать желаемое / ожидаемое Место действия.

java.время

вопрос и другие ответы используют старые классы даты-времени, которые оказались плохо разработаны и хлопотно. Java 8 и более поздние версии имеют java.время встроенный фреймворк, классы которого вытесняют старые.

метод разбора строки при создании новой строки должен быть разбит на два метода. Один метод должен анализировать для получения объектов date-time. Второй должен принимать объекты date-time и генерировать желаемый вывод строки. Затем каждый можно использовать отдельно. И этот подход уводит нас от мысли о строках как значениях даты и времени. Строки-это текстовые представления значений даты и времени. Ваша бизнес-логика должна фокусироваться на манипулировании этими значениями даты и времени как объектами, а не на строках.

извлечение

private ZonedDateTime parseLengthyString ( String input , ZoneId zoneId , Locale locale ) {
    // FIXME: Check for nulls.

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" );
    formatter = formatter.withZone ( zoneId );
    formatter = formatter.withLocale ( locale );
    ZonedDateTime zdt = null;
    try {
        zdt = ZonedDateTime.parse ( input , formatter );
    } catch ( DateTimeParseException e ) {
        // FIXME: handle exeption.
        System.out.println ( "ERROR - e: " + e );
    }
    return zdt; // FIXME: Check for null.
}

формирование

дали ZonedDateTime в руке от метода выше, мы можем произвести текстовое представление своего значение даты-времени с использованием указанной локали для перевода имени дня и имени месяца.

чтобы определить, является ли дата-время сегодня или вчера, мы заботимся только о части даты без времени суток. Для этого мы можем использовать LocalDate класс на java.время.

private String generateLengthyString ( ZonedDateTime zdt , Locale locale ) {
    // FIXME: Check for nulls.

    // Compare the date-only value of incoming date-time to date-only of today and yesterday.
    LocalDate localDateIncoming = zdt.toLocalDate ();

    Instant instant = Instant.now ();
    ZonedDateTime now = ZonedDateTime.now ( zdt.getZone () ); // Get current date-time in same zone as incoming ZonedDateTime.
    LocalDate localDateToday = now.toLocalDate ();
    LocalDate localDateYesterday = localDateToday.minusDays ( 1 );

    DateTimeFormatter formatter = null;
    if ( localDateIncoming.isEqual ( localDateToday ) ) {
        formatter = DateTimeFormatter.ofPattern ( "'Today' hh:mma" , locale ); // FIXME: Localize "Today".
    } else if ( localDateIncoming.isEqual ( localDateYesterday ) ) {
        formatter = DateTimeFormatter.ofPattern ( "'Yesterday' hh:mma" , locale ); // FIXME: Localize "Yesterday".
    } else {
        formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" , locale );
    }

    String output = zdt.format ( formatter );
    return output; // FIXME: Check for null.
}

пример

используйте эти два метода.

произвольно выбирая часовой пояс America/New_York поскольку вопрос не указывать.

String input = "Sat 11:23AM Feb 6, 2016";
ZoneId zoneId = ZoneId.of ( "America/New_York" );
Locale locale = Locale.US;
ZonedDateTime zdt = this.parseLengthyString ( input , zoneId , locale );

String output = this.generateLengthyString ( zdt , locale );

кстати, вы можете спросить java.время для автоматического форматирования выходной строки в соответствии с культурными нормами стандарта вместо жесткого кодирования в формат.

String outputPerLocale = zdt.format ( DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ) );

дамп в консоли.

System.out.println ( "input: " + input + " | zdt: " + zdt + " | Instant: " + zdt.toInstant () + " | output: " | output + " + outputPerLocale: " + outputPerLocale );

вход: Сб 11:23 утра 6 февраля, 2016 | ЗДТ: 2016-02-06T11:23-05:00[Америка/Нью-Йорк] | мгновенный: 2016-02-06T16:23:00Z | выход: сегодня 11:23 утра | outputPerLocale: февраля 6, 2016 11:23:00 АМ

кстати, Я предлагаю поставить пробел перед AM или PM для более легкого чтения.


это расширенный версино Балусареализация c.

попробуйте это, я реализовал его с помощью joda-datatime2.2.jar и SimpleDateFormat

import java.text.SimpleDateFormat;
import java.util.Date;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Days;
public class SmartDateTimeUtil {
private static String getHourMinuteString(Date date){
    SimpleDateFormat hourMinuteFormat = new SimpleDateFormat(" h:m a");
    return hourMinuteFormat.format(date);
}

private static String getDateString(Date date){
    SimpleDateFormat dateStringFormat = new SimpleDateFormat("EEE',' MMM d y',' h:m a");
    return dateStringFormat.format(date);
}

private static boolean isToday (DateTime dateTime) {
       DateMidnight today = new DateMidnight();
       return today.equals(dateTime.toDateMidnight());
}

private static boolean isYesterday (DateTime dateTime) {
       DateMidnight yesterday = (new DateMidnight()).minusDays(1);
       return yesterday.equals(dateTime.toDateMidnight());
}

private static boolean isTomorrow(DateTime dateTime){
    DateMidnight tomorrow = (new DateMidnight()).plusDays(1);
       return tomorrow.equals(dateTime.toDateMidnight());
}
private static String getDayString(Date date) {
        SimpleDateFormat weekdayFormat = new SimpleDateFormat("EEE',' h:m a");
        String s;
        if (isToday(new DateTime(date)))
            s = "Today";
        else if (isYesterday(new DateTime(date)))
            s = "Yesterday," + getHourMinuteString(date);
        else if(isTomorrow(new DateTime(date)))
            s = "Tomorrow," +getHourMinuteString(date);
        else
            s = weekdayFormat.format(date);
        return s;
}

public static String getDateString_shortAndSmart(Date date) {
        String s;
        DateTime nowDT = new DateTime();
        DateTime dateDT = new DateTime(date);
        int days = Days.daysBetween(dateDT, nowDT).getDays();   
        if (isToday(new DateTime(date)))
            s = "Today,"+getHourMinuteString(date);
        else if (days < 7)
            s = getDayString(date);
        else
            s = getDateString(date);
        return s;
}

}

простые случаи для использования и тестирования класса Util:

import java.util.Calendar;
import java.util.Date;

public class SmartDateTimeUtilTest {
    public static void main(String[] args) {
        System.out.println("Date now:"+SmartDateTimeUtil.getDateString_shortAndSmart(new Date()));
        System.out.println("Date 5 days before :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(-5)));
        System.out.println("Date 1 day before :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(-1)));
        System.out.println("Date last month:"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureMonth(-1)));
        System.out.println("Date last year:"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDate(-1)));
        System.out.println("Date 1 day after :"+SmartDateTimeUtil.getDateString_shortAndSmart(getFutureDay(1)));
    }
    public static Date getFutureDate(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.YEAR, numberOfYears); 
        return c.getTime();
    }
    public static Date getFutureMonth(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, numberOfYears); 
        return c.getTime();
    }

    public static Date getFutureDay(int numberOfYears){
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.DATE, numberOfYears); 
        return c.getTime();
    }
}

дата тогда вам просто нужно использовать это

String strDate = "";
if (DateUtils.isToday(date.getTime()))
    strDate = "Today";
else if (DateUtils.isToday(date.getTime() + DateUtils.DAY_IN_MILLIS))
    strDate = "Yesterday";

здесь переменной является дата "объект".