【问题标题】:Get first next Monday after certain date?在特定日期之后的下周一获得第一个?
【发布时间】:2014-06-12 06:09:10
【问题描述】:

我知道here 有同样的问题,但我已经尝试了提供的答案,它返回了一个我不明白的输出。我对答案感到困惑,我认为输出不正确。

我需要帮助,谢谢:)

GregorianCalendar date1 = new GregorianCalendar( 2014, 05, 12 ); //05 is june as month start from 0 -11

while( date1.get( Calendar.DAY_OF_WEEK ) != Calendar.MONDAY )
    date1.add( Calendar.DATE, 1 );  

System.out.println(date1);

这是输出:

java.util.GregorianCalendar[time=1405267200000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Singapore",offset=28800000,dstSavings=0,useDaylight=false,transitions=9,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=6,WEEK_OF_YEAR=29,WEEK_OF_MONTH=3,DAY_OF_MONTH=14,DAY_OF_YEAR=195,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=28800000,DST_OFFSET=0]

我应该提取输出的哪个位置来检索星期一的日期?

【问题讨论】:

  • System.out.println(date1.getTime());
  • DAY_OF_WEEK=2 - 输出看起来正确(虽然不适合人类)。
  • 如果您能够使用 Java 8,我建议您使用 java.time 类。否则,我建议您使用 Joda Time。请注意,当前您正尝试在系统时区中查找下周一(或今天 - 即使已经是周一,您的 while 循环也不会迭代一次)在系统时区中。这就是你想要的吗?
  • Calendar 月份被 0 索引,您指定的是 7 月而不是 6 月...
  • @beNice 如果可以的话,我仍然会考虑使用 JodaTime

标签: java date calendar


【解决方案1】:

Java 8+

LocalDate ld = LocalDate.of(2014, Month.JUNE, 12);
System.out.println(ld);
ld = ld.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println(ld);

哪些打印...

2014-06-12
2014-06-16

因为我的实际日期可能是星期一,所以您也可以使用...

ld = ld.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));

Java

您应该使用ThreeTen Backport,它为您提供 Java 8 日期/时间 API 的支持

原答案

System.out.println(date1.getTime());代替System.out.println(date1);

getTime 返回一个Date 的实例,代表Calendar 的当前状态

这将输出Mon Jul 14 00:00:00 EST 2014

System.out.println(date1) 相当于使用 System.out.println(date1.toString()),在这种情况下,它正在转储一堆关于 Calendar 对象状态的有用信息,但不是真正的人类可读数据。

System.out.println(date1.getTime()) 将使用DatetoString 的方法来显示一个日期值,其格式基于当前的本地设置,这将提供更多有用的信息。

更新

不要使用GregorianCalendar,而应该使用系统Calendar,例如...

Calendar date1 = Calendar.getInstance();
date1.set(2014, 06, 12);

此外,月份是 0 索引的,这意味着 Janurary 实际上是 0 而不是 1,因此在您的示例中,您将月份指定为 7 月,而不是 6 月。

所以,相反,使用...

Calendar date1 = Calendar.getInstance();
date1.set(2014, 05, 12);

while (date1.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
    date1.add(Calendar.DATE, 1);
}

System.out.println(date1.getTime());

哪个输出了...

Mon Jun 16 16:22:26 EST 2014

从今天开始是下周一...或多或少 ;)

【讨论】:

【解决方案2】:

tl;博士

LocalDate.of( 2014 , Month.JUNE , 12 )                    // Represent a date-only value, without time-of-day and without time zone.
         .with(                                           // Move from one date to another by passing an implementation of the `TemporalAdjuster` interface. 
             TemporalAdjusters.next( DayOfWeek.MONDAY )   // Use an existing implementation found on utility class `TemporalAdjusters` (plural versus singular).
         )                                                // Returns another fresh `LocalDate` object rather than altering the original, per immutable objects design.

使用 java.time

您正在使用麻烦的旧日期时间类,这些类现在是遗留的,被 java.time 类所取代。

LocalDate 类表示没有时间和时区的仅日期值。

LocalDate ld = LocalDate.of( 2014 , Month.JUNE , 12 ) ;

要获得下一个星期一,请使用 TemporalAdjusters 类中的 TemporalAdjuster 实现。

LocalDate nextMonday = ld.with( TemporalAdjusters.next( DayOfWeek.MONDAY ) ) ;

如果您想使用原始日期(如果它本身是星期一),请使用 nextOrSameadjuster。

LocalDate nextOrSameMonday = ld.with( TemporalAdjusters.nextOrSame( DayOfWeek.MONDAY ) ) ;

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案3】:

    对您的代码稍作改动:

        GregorianCalendar date1 = new GregorianCalendar(2014, 6, 12);
    
        while (date1.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
            date1.add(Calendar.DATE, 1);
        }
    
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        System.out.println(sdf.format(date1.getTime()));
    

    产量:

     14-07-2014
    

    编辑:根据JavaDoc 文档,您使用的构造函数期望基于 0 的月份索引,因此对于 6 月份,您需要传入 5 而不是 6 的值。

    【讨论】:

    • 为什么new Date(date1.getTimeInMillis()))date1.getTime() 返回一个Date 对象
    • @MadProgrammer:谢谢,已修复。
    【解决方案4】:

    只是一个建议 - 您可以像这样使用 switch 语句和 Calendar.add() 来代替循环:

    int weekdayNum = c.get(Calendar.DAY_OF_WEEK);
    
        switch (weekdayNum) {
        case 1: {
            c.add(Calendar.DAY_OF_MONTH, 1);
            break;
        }
        case 3: {
            c.add(Calendar.DAY_OF_MONTH, 6);
            break;
        }
        case 4: {
            c.add(Calendar.DAY_OF_MONTH, 5);
            break;
        }
        case 5: {
            c.add(Calendar.DAY_OF_MONTH, 4);
            break;
        }
        case 6: {
            c.add(Calendar.DAY_OF_MONTH, 3);
            break;
        }
        case 7: {
            c.add(Calendar.DAY_OF_MONTH, 2);
            break;
        }
        default:
            break;
        }
    

    【讨论】:

      【解决方案5】:

      或者只是做一些简单的数学运算。由于Calender.Monday等于2,所以很容易计算出当前日期需要加上的天数。

      Calendar date1 = Calendar.getInstance();
      date1.set(2014, 05, 12);
      int dayOfWeek = date1.get(Calendar.DAY_OF_WEEK);
      date1.add(Calendar.DATE, (9 - dayOfWeek) % 7);
      

      【讨论】:

      • 我没有看到你在哪里找到星期一等于 2 的信息。你能解释一下吗?
      • 仅供参考,麻烦的旧日期时间类,如 java.util.Datejava.util.Calendarjava.text.SimpleTextFormat 现在是 legacy,被 java.time 类取代。见Tutorial by Oracle
      • @Yunnosch Calendar.MONDAY 确实是documented as being a constant of type int with a value of 2。这种编号是北美和其他通常将星期日视为一周的第一天的地区所特有的。 ISO 8601 标准将星期一定义为第一天。避免这个麻烦的旧遗留类,而是使用现代 java.time 类,如遵循标准的 DayOfWeek 枚举的众多原因之一。
      • 谢谢,我在考虑完全不同的错误路线。
      猜你喜欢
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-14
      • 2013-06-18
      • 1970-01-01
      相关资源
      最近更新 更多