Упростите замену объекта даты строками «сегодня» и «вчера» в статическом методе Java - PullRequest
9 голосов
/ 27 ноября 2010

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

Метод сильфона берет объект даты, форматирует его ("EEE чч: ммма ммм, гггг") и затем выясняет, является ли дата сегодня или вчера и чем, если, она возвращает форматированную строку "(Вчера | Сегодня) чч: мма".

    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 ]

40 голосов
/ 27 ноября 2010

Вот как вы можете улучшить его с помощью стандартного 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;
    }
}
3 голосов
/ 09 мая 2011

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

Я фанат отображения даты и времени в краткой и умной манере недавних звонков iPhone (аналогично сообщениям Google Wave).Это "чч: мм" если сегодня, "вчера" или название дня недели , если <7 дней, иначе <strong>гггг-мм-дд .

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, хотя другие методы будут работать так же хорошо.:)

2 голосов
/ 07 февраля 2016

часовой пояс

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

Locale

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

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

Лучше указать желаемый / ожидаемый язык.

java.time

В Вопросе и других Ответах используются старые классы даты и времени, которые оказались плохо продуманными и проблемными. Java 8 и более поздние версии имеют встроенную инфраструктуру java.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.time.

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.time автоматически форматировать выходную строку в соответствии с культурными нормами локали вместо жесткого кодирования формата. 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:00 | выходной: сегодня 11:23 | outputPerLocale: 6 февраля 2016 г. 11:23:00 Кстати, я предлагаю поставить ПРОБЕЛ перед AM или PM для удобства чтения.

2 голосов
/ 04 марта 2015

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

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;
}
2 голосов
/ 26 ноября 2013

Другой способ сравнения дат помимо принятого выше ответа с использованием java.util.Date.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";
}

<% = days%> вернется:

СЕГОДНЯ

ВЧЕРА

x ДНЕЙ НАЗАД

2 голосов
/ 04 сентября 2013

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

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;
}
1 голос
/ 27 ноября 2010

Посмотрите на йодатиме: http://joda -time.sourceforge.net /

это пример кода из документа:

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);
}
0 голосов
/ 22 декабря 2017

Я знаю, что опоздал на эту вечеринку.Но у меня есть кратчайшее решение этой проблемы.Если вы хотите показать «Сегодня» или «Вчера» на основе Дата , вам просто нужно использовать эту

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

, здесь переменная дата - Дата объект.

0 голосов
/ 04 декабря 2014

Это расширенная версия реализации Balus 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();
    }
}
...