【问题标题】:Java: check if a given date is within current monthJava:检查给定日期是否在当前月份内
【发布时间】:2014-11-09 01:34:28
【问题描述】:

我需要检查给定日期是否在当前月份,我编写了以下代码,但 IDE 提醒我 getMonth()getYear() 方法已过时。我想知道如何在较新的 Java 7 或 Java 8 中做同样的事情。

private boolean inCurrentMonth(Date givenDate) {
    Date today = new Date();

    return givenDate.getMonth() == today.getMonth() && givenDate.getYear() == today.getYear();
}

【问题讨论】:

  • 阅读每种方法的 JavaDoc,它会告诉您应该改用什么。 (Java 7 的剧透:Calendar.get(Calendar.MONTH)Calendar.get(Calendar.YEAR)

标签: java date java-time java.util.date


【解决方案1】:
//Create 2 instances of Calendar
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();

//set the given date in one of the instance and current date in the other
cal1.setTime(givenDate);
cal2.setTime(new Date());

//now compare the dates using methods on Calendar
if(cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)) {
    if(cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH)) {
        // the date falls in current month
    }
}

【讨论】:

    【解决方案2】:

    java.time (Java 8)

    使用新的java.time API (tutorial) 可以通过多种方式实现此目的。你可以用.get(ChronoField.XY) 来做,但我觉得这个更漂亮:

    Instant given = givenDate.toInstant();
    Instant ref = Instant.now();
    return Month.from(given) == Month.from(ref) && Year.from(given).equals(Year.from(ref));
    

    为了更好的可重用性,您还可以将此代码重构为“临时查询”:

    public class TemporalQueries {
      //TemporalQuery<R> { R queryFrom(TemporalAccessor temporal) }
      public static Boolean isCurrentMonth(TemporalAccessor temporal) {
             Instant ref = Instant.now();
             return Month.from(temporal) == Month.from(ref) && Year.from(temporal).equals(Year.from(ref));           
      }
    }
    
    Boolean result = givenDate.toInstant().query(TemporalQueries::isCurrentMonth); //Lambda using method reference
    

    【讨论】:

    • 看到 java.time 的运行非常有趣。也许添加时区?人们很少想要UTC 的日期/月份/年份。
    • YearMonth 参考 = YearMonth.from(LocalDate.now()); return Month.from(temporal) == Month.from(ref) && Year.from(temporal).equals(Year.from(ref));请使用 YearMonth 作为参考。
    • @Arundev 请注意,YearMonth 可以直接使用.equals() 进行比较,而不是单独比较属性,而且它还有自己的now() 方法:YearMonth ref = YearMonth.now(); return YearMonth.from(temporal).equals(ref);
    【解决方案3】:

    时区

    其他答案忽略了时区的关键问题。巴黎的新一天比蒙特利尔更早。所以在同一时刻,日期是不同的,“明天”在巴黎,而“昨天”在蒙特利尔。

    乔达时间

    与 Java 捆绑在一起的 java.util.Date 和 .Calendar 类是出了名的麻烦、混乱和缺陷。避开他们。

    改用 Joda-Time 库或 Java 8 中的 java.time 包(受 Joda-Time 启发)。

    这是 Joda-Time 2.5 中的示例代码。

    DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
    DateTime dateTime = new DateTime( yourJUDate, zone );  // Convert java.util.Date to Joda-Time, and assign time zone to adjust.
    DateTime now = DateTime.now( zone );
    // Now see if the month and year match.
    if ( ( dateTime.getMonthOfYear() == now.getMonthOfYear() ) && ( dateTime.getYear() == now.getYear() ) ) {
        // You have a hit.
    }
    

    要查看某个时刻是否属于任何时间跨度(不仅仅是一个月)的更通用解决方案,请在 StackOverflow 中搜索“joda”、“interval”和“contain”。

    【讨论】:

      【解决方案4】:

      java.time (Java 8)

      Java 8 提供了YearMonth 类,它表示给定年份(例如 2018 年 1 月)中的给定月份。这可用于与给定日期的YearMonth 进行比较。

      private boolean inCurrentMonth(Date givenDate) {
          ZoneId timeZone = ZoneOffset.UTC; // Use whichever time zone makes sense for your use case
          LocalDateTime givenLocalDateTime = LocalDateTime.ofInstant(givenDate.toInstant(), timeZone);
      
          YearMonth currentMonth = YearMonth.now(timeZone);
      
          return currentMonth.equals(YearMonth.from(givenLocalDateTime));
      }
      

      请注意,这种方法适用于任何同时具有月份和日期部分(LocalDateZonedDateTime 等)的 Java 8 时间类,而不仅仅是LocalDateTime

      【讨论】:

      • 好答案。但是使用LocalDateTime 会产生误导。那个类不能代表片刻。最好用ZonedDateTime替换,否则保持你的代码不变。
      • 您应该添加一个说明,说明在适合业务场景的任何时区使用ZoneId
      • @BasilBourque 超出我现有的// Use whichever time zone makes sense for your use case 评论?
      • 好。我仍然建议用LocalDateTime 替换ZonedDateTime。您当前的代码解决方案恰好适用于这一特定情况,它具有误导性和混淆性。如果使用LocalDateTime 而不是ZonedDateTime,扩展该代码的人可能会遇到错误的结果。
      • @BasilBourque 我没有看到LocalDateTime 可能是个问题。实际上,我们只关心它是同时具有年和月的 Java 8 类型之一,并且我们使用相同的区域进行日期转换和确定当前月份。 LocalDateTime.ofInstant 将为我们提供特定时刻的正确年份和月份(以及我们实际上并不关心的日期和时间)。如果有从InstantYearMonth 的直接转换,我会改用它。
      【解决方案5】:

      据我所知,Calendar 类和所有从它派生的都使用 get() 返回日期。请参阅documentation for this class。这里还有一个取自here的例子:

      SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd HH:mm:ss");    
      Calendar calendar = new GregorianCalendar(2013,1,28,13,24,56);
      
      int year       = calendar.get(Calendar.YEAR);
      int month      = calendar.get(Calendar.MONTH); // Jan = 0, dec = 11
      int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); 
      int dayOfWeek  = calendar.get(Calendar.DAY_OF_WEEK);
      int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);
      int weekOfMonth= calendar.get(Calendar.WEEK_OF_MONTH);
      
      int hour       = calendar.get(Calendar.HOUR);        // 12 hour clock
      int hourOfDay  = calendar.get(Calendar.HOUR_OF_DAY); // 24 hour clock
      int minute     = calendar.get(Calendar.MINUTE);
      int second     = calendar.get(Calendar.SECOND);
      int millisecond= calendar.get(Calendar.MILLISECOND);
      
      System.out.println(sdf.format(calendar.getTime()));
      
      System.out.println("year \t\t: " + year);
      System.out.println("month \t\t: " + month);
      System.out.println("dayOfMonth \t: " + dayOfMonth);
      System.out.println("dayOfWeek \t: " + dayOfWeek);
      System.out.println("weekOfYear \t: " + weekOfYear);
      System.out.println("weekOfMonth \t: " + weekOfMonth);
      
      System.out.println("hour \t\t: " + hour);
      System.out.println("hourOfDay \t: " + hourOfDay);
      System.out.println("minute \t\t: " + minute);
      System.out.println("second \t\t: " + second);
      System.out.println("millisecond \t: " + millisecond);
      

      哪个输出

      2013 Feb 28 13:24:56
      year        : 2013
      month       : 1
      dayOfMonth  : 28
      dayOfWeek   : 5
      weekOfYear  : 9
      weekOfMonth : 5
      hour        : 1
      hourOfDay   : 13
      minute      : 24
      second      : 56
      millisecond : 0
      

      我认为它已被替换,因为新方法使用单个函数提供了更简单的处理,更容易记住。

      【讨论】:

        猜你喜欢
        • 2015-02-13
        • 1970-01-01
        • 2016-02-15
        • 2014-01-20
        • 2011-08-16
        • 2013-02-03
        • 2012-08-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多