【问题标题】:last day of month calculation一个月的最后一天计算
【发布时间】:2012-03-12 22:09:03
【问题描述】:

我在计算预定发送通知的下一个月最后一天的时间时遇到问题。

这是我的代码:

RecurrenceFrequency recurrenceFrequency = notification.getRecurrenceFrequency();
Calendar nextNotifTime = Calendar.getInstance();

我认为这是导致问题的原因:

nextNotifTime.add(recurrenceFrequency.getRecurrencePeriod(), 
                  recurrenceFrequency.getRecurrenceOffset());

如何使用日历正确设置通知的下个月的最后一天?

【问题讨论】:

  • 设置为下个月的第一天,然后回滚一天。
  • A SSCCE 会更容易回答这个问题。你真正看到了什么问题?

标签: java datetime calendar


【解决方案1】:
Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH);

这将返回当前月份的实际最大值。例如现在是闰年的二月,所以它返回 29 作为int

【讨论】:

  • 谢谢,我需要获得下个月的最大值,但它仍然必须工作,它也可以是本月的第一天,因为该部分现在可以工作。再次感谢您的时间和精力
  • 每个日期获取ActualMaximum 都不是问题。只需在调用getActualMaximum 之前将日历实例滚动到所需日期。第一个日期可以通过getActualMinimum()获取
  • 好的,非常感谢 Alex,所以如果我希望将实例提前一个月并找出该月的 getActualMaximum,我该怎么做?欢呼
  • 这会是亚历克斯吗? nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH);
  • 我在此之后设置了就绪日期时间:nextNotification.setReadyDateTime(nextNotifTime.getTime()); 因此我不应该这样做:nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); 吗?
【解决方案2】:

查看 Calendar 对象的getActualMaximum(int field) 方法。

如果您将日历对象设置为您正在寻找最后日期的月份,那么getActualMaximum(Calendar.DAY_OF_MONTH) 将为您提供最后一天。

【讨论】:

    【解决方案3】:

    您可以将日历设置为下个月的第一天,然后减去一天。

    Calendar nextNotifTime = Calendar.getInstance();
    nextNotifTime.add(Calendar.MONTH, 1);
    nextNotifTime.set(Calendar.DATE, 1);
    nextNotifTime.add(Calendar.DATE, -1);
    

    运行此代码后,nextNotifTime 将设置为当月的最后一天。请记住,如果今天是该月的最后一天,则此代码的最终效果是 Calendar 对象保持不变。

    【讨论】:

      【解决方案4】:

      并将最后一天作为 Date 对象:

      Calendar cal = Calendar.getInstance();
      cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
      
      Date lastDayOfMonth = cal.getTime();
      

      【讨论】:

      • 会是答案!
      【解决方案5】:

      以下总是会给出正确的结果:

          Calendar cal = Calendar.getInstance();
          cal.set(Calendar.MONTH, ANY_MONTH);
          cal.set(Calendar.YEAR, ANY_YEAR);
          cal.set(Calendar.DAY_OF_MONTH, 1);// This is necessary to get proper results
          cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
          cal.getTime();
      

      【讨论】:

      • 为什么有必要?你能告诉我吗:)
      • 是的,只是因为上面的这个确切原因而导致测试失败。问题是除非设置了 DAY_OF_MONTH,否则它将默认为当前。
      • 你应该先设置(DAY_OF_MONTH, 1)。如果您在 1 月 31 日并将月份设置为 2 月,它将跳到 3 月,因为 2 月 31 日不存在。 Calendar cal = DateUtils.getCalendar(2021, 1, 31); // DateUtils is custom. cal.set(Calendar.MONTH, Calendar.FEBRUARY); System.out.println(cal.getTime()); >>> 2021 年 3 月 3 日星期三 00:00:00 CET @mike
      【解决方案6】:

      java.time.temporal.TemporalAdjusters.lastDayOfMonth()

      使用Java 8 内置的java.time 库,您可以使用TemporalAdjuster 接口。我们在TemporalAdjusters 实用程序类中找到了一个可以使用的实现:lastDayOfMonth

      import java.time.LocalDate;
      import java.time.temporal.TemporalAdjusters;
      
      LocalDate now = LocalDate.now(); //2015-11-23
      LocalDate lastDay = now.with(TemporalAdjusters.lastDayOfMonth()); //2015-11-30
      

      如果您需要添加时间信息,您可以使用任何可用的LocalDateLocalDateTime 转换,如

      lastDay.atStartOfDay(); //2015-11-30T00:00
      

      【讨论】:

      • 好答案。但是最后一部分很弱,建议使用LocalDateTime。该类缺乏任何时区或与 UTC 偏移的概念。因此它无法确定特定地点的特定一天何时真正开始。该课程仅适用于普通的 24 小时工作日,而不适用于现实世界的日子。对于实际日期,请指定时区:ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;。由于夏令时 (DST) 等异常情况,某些地方的某些日子可能会在不同的时间开始,例如 01:00。
      【解决方案7】:

      在这里使用最新的java.time 库是最好的解决方案:

      LocalDate date = LocalDate.now();
      LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
      

      或者,您可以这样做:

      LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
      

      【讨论】:

        【解决方案8】:
                SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
                Date date = sdf.parse("11/02/2016");
        
                Calendar calendar = Calendar.getInstance();  
                calendar.setTime(date);  
        
                System.out.println("First Day Of Month : " + calendar.getActualMinimum(Calendar.DAY_OF_MONTH));  
                System.out.println("Last Day of Month  : " + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 
        

        【讨论】:

          【解决方案9】:

          使用java.util.Calendar 实现 Kotlin 日期扩展

          fun Date.toEndOfMonth(): Date {
              return Calendar.getInstance().apply {
                  time = this@toEndOfMonth
              }.toEndOfMonth().time
          }
          
          fun Calendar.toEndOfMonth(): Calendar {
              set(Calendar.DAY_OF_MONTH, getActualMaximum(Calendar.DAY_OF_MONTH))
              return this
          }
          

          您可以在每个 Date 对象上调用toEndOfMonth 函数,例如Date().toEndOfMonth()

          【讨论】:

          • 这些糟糕的类在几年前被现代 java.time 类所取代,并采用了 JSR 310。在 2019 年建议这些遗留类是很糟糕的建议。
          • 这不是一个坏建议。现代 java.time 仅适用于 API 26+ 的 Android。在支持(不是那么)旧设备时,我们仍然依赖 java.util.*
          【解决方案10】:

          您也可以使用 YearMonth。

          喜欢:

          YearMonth.of(2019,7).atEndOfMonth()
          YearMonth.of(2019,7).atDay(1)
          

          https://docs.oracle.com/javase/8/docs/api/java/time/YearMonth.html#atEndOfMonth--

          【讨论】:

            猜你喜欢
            • 2010-09-18
            • 1970-01-01
            • 2016-03-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-22
            • 2010-09-16
            • 1970-01-01
            相关资源
            最近更新 更多