【问题标题】:In Joda-Time, set DateTime to start of month在 Joda-Time 中,将 DateTime 设置为月初
【发布时间】:2010-02-14 14:56:10
【问题描述】:

我的 API 允许库客户端传递日期:

method(java.util.Date date)

使用Joda-Time,从这个日期开始,我想提取月份并遍历这个月包含的所有日期。

现在,传递的日期通常是 new Date() - 表示当前时刻。我的问题实际上是将新的 DateMidnight(jdkDate) 实例设置为月初。

有人可以用Joda-Time 演示这个用例吗?

【问题讨论】:

  • 问题标题应该提到Joda Time。
  • 它确实“有人可以用 joda-time 演示这个用例。”我添加了另一个注释,以更清楚地表明这是一个 joda time 问题。
  • @MaximVeksler Lachlan Roche 说 title 应该提到 Joda-Time。我进行了编辑。

标签: java date jodatime


【解决方案1】:

当月第一天开始时的午夜由下式给出:

// first midnight in this month
DateMidnight first = new DateMidnight().withDayOfMonth(1);

// last midnight in this month
DateMidnight last = first.plusMonths(1).minusDays(1);

如果从 java.util.Date 开始,则使用不同的 DateMidnight 构造函数:

// first midnight in java.util.Date's month
DateMidnight first = new DateMidnight( date ).withDayOfMonth(1);

Joda Time java doc - https://www.joda.org/joda-time/apidocs/overview-summary.html

【讨论】:

  • 顺便说一句,关于那个“最后”为什么不:DateMidnight last = first.plusMonths(1).minusDays(1);一样的,只是更干净。
  • 这个答案是正确的,但现在已经过时了。并非每个时区的每一天都有午夜。 Joda-Time 2 添加了一个方法 withTimeAtStartOfDay 来代替“午夜”功能。
  • DateMidnight 现已弃用。来自 JavaDoc:“在夏令时向前移动跳过午夜时间的某些时区中不存在午夜时间。使用 LocalDate 表示没有时区的日期。或者使用 DateTime 表示完整的日期和时间,也许使用 DateTime.withTimeAtStartOfDay() 获取一天开始时的瞬间。”
  • DateMidnight 已弃用。
【解决方案2】:

一天的第一刻

answer by ngeek 是正确的,但未能将时间放在一天的第一刻。要调整时间,请向withTimeAtStartOfDay 添加呼叫。

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.

org.joda.time.DateTime startOfThisMonth = new org.joda.time.DateTime().dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
org.joda.time.DateTime startofNextMonth = startOfThisMonth.plusMonths( 1 ).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();

System.out.println( "startOfThisMonth: " + startOfThisMonth );
System.out.println( "startofNextMonth: " + startofNextMonth );

在美国西雅图跑步时……

startOfThisMonth: 2013-11-01T00:00:00.000-07:00
startofNextMonth: 2013-12-01T00:00:00.000-08:00

注意这两行控制台输出的区别:-7 与 -8 因为Daylight Saving Time


通常应该始终指定时区,而不是依赖默认值。为简单起见,此处省略。应该像这样添加一行,并将时区对象传递给上面示例中使用的构造函数。

// Time Zone list: http://joda-time.sourceforge.net/timezones.html  (Possibly out-dated, read note on that page)
// UTC time zone (no offset) has a constant, so no need to construct: org.joda.time.DateTimeZone.UTC
org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );

java.time

以上内容正确但已过时。 Joda-Time 库现在被 Java 8 及更高版本中内置的 java.time 框架所取代。

LocalDate 表示没有时间和时区的仅日期值。时区对于确定日期至关重要。对于任何特定时刻,日期都会因全球区域而异。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

使用其中一个TemporalAdjusters 来获取月份的第一天。

LocalDate firstOfMonth = today.with( TemporalAdjusters.firstDayOfMonth() );

LocalDate 可以生成一个ZonedDateTime,代表一天中的第一刻。

ZonedDateTime firstMomentOfCurrentMonth = firstOfMonth.atStartOfDay( zoneId );

【讨论】:

    【解决方案3】:

    获取当月第一天的另一种方法(不考虑 DateMidnight)是使用:

      DateTime firstDayOfMonth = new DateTime().dayOfMonth().withMinimumValue();
    

    【讨论】:

    • 虽然日期是每月的第一天,但​​时间仍然是中午。将 .withTimeAtStartOfDay() 添加到末尾将解决此问题。
    • 您也可以添加 .dayOfMonth().withMaximumValue().hourOfDay().withMaximumValue() 并且可以添加相同的分钟数...更精确
    【解决方案4】:

    DateMidnight 现已弃用。相反,您可以这样做:

    LocalDate firstOfMonth = new LocalDate(date).withDayOfMonth(1);
    LocalDate lastOfMonth = firstOfMonth.plusMonths(1).minusDays(1);
    

    如果您知道时区,请改用new LocalDate(date, timeZone) 以获得更高的准确度。

    你也可以用.dayOfMonth().withMinimumValue()代替.withDayOfMonth(1)

    编辑:

    这将为您提供12/1/YYYY 00:0012/31/YYYY 00:00。如果您希望本月的最后一天实际上是下个月的第一天(因为您正在执行 between 子句),请从 lastOfMonth 计算中删除 minusDays(1)

    【讨论】:

    • @Xylian 我想这取决于对问题的解释。对于任何一天,它都会给您每月第一天的午夜和该月最后一天的午夜。如果您想要下个月第一天的午夜,只需从第二天删除“.minusDays(1)。如果您仍然认为我的答案不正确,请详细说明,因为我的单元测试说它有效。
    【解决方案5】:

    哦,我没有看到这是关于 jodatime。无论如何:

    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);
    
    int min = c.getActualMinimum(Calendar.DAY_OF_MONTH);
    int max = c.getActualMaximum(Calendar.DAY_OF_MONTH);
    for (int i = min; i <= max; i++) {
        c.set(Calendar.DAY_OF_MONTH, i);
        System.out.println(c.getTime());
    }
    

    或者使用 commons-lang:

    Date min = DateUtils.truncate(date, Calendar.MONTH);
    Date max = DateUtils.addMonths(min, 1);
    for (Date cur = min; cur.before(max); cur = DateUtils.addDays(cur, 1)) {
        System.out.println(cur);
    }
    

    【讨论】:

    • 感谢 java 基本 api 说明。我也从中吸取了教训。
    【解决方案6】:

    您可以使用以下方法获取月份的开始日期和结束日期:

    DateTime monthStartDate = new DateTime().dayOfMonth().withMinimumValue();
    DateTime monthEndDate = new DateTime().dayOfMonth().withMaximumValue();
                            
    

    【讨论】:

      猜你喜欢
      • 2011-06-27
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 2013-05-03
      • 2011-05-23
      • 2015-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多