【问题标题】:Simplify replacement of date object with "today" and "yesterday" strings in Java static method在 Java 静态方法中用“今天”和“昨天”字符串简化日期对象的替换
【发布时间】:2010-11-27 14:34:05
【问题描述】:

我有以下方法,如果没有别的,我想缩短或更快。欢迎所有的cmets:

Bellow 方法获取一个日期对象,将其格式化(“EEE hh:mma MMM d, yyyy”),然后确定日期是今天还是昨天,如果是,则返回“(昨天 | 今天) hh:mma" 格式化字符串。

    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;
}

【问题讨论】:

  • 嗯..你愿意采用Jodatime吗?
  • 首先告诉我们该方法应该做什么可能很有用。看起来它测试格式化的字符串是今天的日期还是昨天的日期,如果是,则返回一个特殊的字符串?
  • 以后请使用@nickname 通知其他人有关帖子中不是他们自己的评论回复。另见meta.stackexchange.com/questions/43019/…

标签: java date replace simplify


【解决方案1】:

以下是使用标准 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;
    }
}

【讨论】:

  • 对不起,我收回了。我以为昨天是前一年的 12 月 31 日,calendar.get(Calendar.YEAR) == yesterday.get(Calendar.YEAR) 会评估为 false。然而这不是它的工作方式,因为日历当然也是前一年。
  • 你的 DateTime 类是来自 JodaTime 库吗?
  • 如果我们知道日期,即日期格式为 MM/dd/yyyy,如何更改
  • @LOG_TAG:只需在代码中相应地更改模式即可。
  • @BalusC 谢谢 setTime() 让我这么想! +1 希望明天实施 tomorrow.add(Calendar.DATE, +1); 我猜会起作用!
【解决方案2】:

您写了“欢迎所有 cmets”,所以这是我使用 joda-time 的方式。 :)

我喜欢以简短而智能的方式显示 iPhone 最近通话的日期和时间(类似于 google wave 帖子)。如果是今天,则为 "hh:mm",如果 "yesterday" 或工作日名称,否则为 yyyy-MM-dd

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-time 类。

在这些情况下,两个 DateTime:s 之间经过的天数与人们如何定义谈论它的时间无关。 DateMidnight 在这里派上用场,而不是像我看到的一些人那样计算天数(或毫秒),尽管其他方法也可以。 :)

【讨论】:

    【解决方案3】:

    我对这个问题的理解是提供一种简单的方法来产生如下输出:

    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;
    }
    

    【讨论】:

      【解决方案4】:

      时区

      问题和其他答案忽略了时区的关键问题。该输入字符串缺少任何时区或offset-from-UTC。因此,该字符串将被解析,同时假设它代表 JVM 当前默认时区中的日期时间。有风险的业务,因为 (a) 该假设可能是错误的,并且 (b) 该默认值可能随时更改,即使在运行时

      语言环境

      问题和其他答案忽略了另一个关键问题: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,我们可以使用指定的语言环境生成其日期时间值的文本表示,以翻译日期名称和月份名称。

      要确定日期时间是今天还是昨天,我们只关心日期部分而不关心一天中的时间。为此,我们可以使用 java.time 中的LocalDate 类。

      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 根据 Locale 的文化规范自动格式化输出字符串,而不是硬编码格式。

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

      转储到控制台。

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

      输入:2016 年 2 月 6 日星期六上午 11:23 | zdt: 2016-02-06T11:23-05:00[美国/纽约] |即时:2016-02-06T16:23:00Z |输出:今天上午 11:23 | outputPerLocale:2016 年 2 月 6 日上午 11:23:00

      顺便说一句,我建议在AMPM 之前放置一个空格,以便于阅读。

      【讨论】:

        【解决方案5】:

        除了上面接受的答案之外,另一种比较日期的方法是使用 java.util.Date.getTime() (注意:应该使用 long 而不是 int):

        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 天前

        【讨论】:

          【解决方案6】:

          今天,昨天,明天的这个

          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;
          }
          

          【讨论】:

            【解决方案7】:

            看看jodatime: 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);
            }
            

            【讨论】:

            • 仅供参考,Joda-Time 项目现在处于维护模式。该团队建议迁移到 Java 8 及更高版本中内置的 java.time 类。
            【解决方案8】:

            这是Balusc 实现的扩展版本。

            试试这个,我使用 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();
                }
            }
            

            【讨论】:

            • 仅供参考,Joda-Time 项目现在处于维护模式。该团队建议迁移到 Java 8 及更高版本中内置的 java.time 类。
            【解决方案9】:

            我知道我参加这个聚会迟到了。但我有这个问题的最短解决方案。 如果你想根据Date 显示“今天”或“昨天”,那么你只需要使用这个

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

            这里的可变日期是Date对象。

            【讨论】:

            • (A) 此答案忽略了时区在确定日期并因此确定今天和昨天的关键问题。旧的 Date 类始终采用 UTC。 (B) 这个答案也不精确,因为不是每天都是 24 小时。由于夏令时等异常情况,日期可以运行 23 或 25 小时或其他一些持续时间。
            猜你喜欢
            • 2013-06-02
            • 2023-04-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多