Java Calendar.set(Calendar.DAY_OF_WEEK,Calendar.SUNDAY),它会向后滚动,转发还是未知?

假设以下代码在2009年8月22日(星期六)执行

Calendar c = Calendar.getInstance(); c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); 

c.get(Calendar.DAY_OF_MONTH)将返回23.我感兴趣的条件是将返回14(上周日,而不是下周日)。

是否有任何与方向相关的规则当设置DAY_OF_WEEK时,日历将滚动DAY_OF_MONTH/YEAR ? 如果是这样,他们是什么?

它应始终保持相同的WEEK_OF_MONTHhttp://java.sun.com/j2se/1.4.2/docs/api/java/util/Calendar.html#WEEK_OF_MONTH )。 从文档:

设置或获取WEEK_OF_MONTH或WEEK_OF_YEAR字段时,日历必须将月份或年份的第一周确定为参考点。 一个月或一年的第一周定义为从getFirstDayOfWeek()开始并且至少包含该月或年的getMinimalDaysInFirstWeek()天的最早七天。 周数在第一周之前编号为……,-1,0; 周数为2,3,……跟随它。 请注意,get()返回的规范化编号可能不同。 例如,特定的Calendar子类可以将一年的第1周之前的一周指定为前一年的第n周。

以下公式在[0; 6]范围内的一周内返回“当前”日

 (d + numberOfDaysInAWeek - firstDayOfWeek) % numberOfDaysInAWeek 

如果你想要范围,可以加1 [1; 7]

 (d + numberOfDaysInAWeek - firstDayOfWeek) % numberOfDaysInAWeek + 1 

dCalendar.get(Calendar.DAY_OF_WEEK)返回的内容

获取一周中的第一天,从当前日期中减去公式的结果。 以下代码执行此操作:

 final int currentDayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) + 7 - cal.getFirstDayOfWeek()) % 7; cal.add(Calendar.DAY_OF_YEAR, -currentDayOfWeek); 

实际上,这取决于。 请考虑以下Java代码。 它实际上很简单,我希望它打印出2011-09-18之前的星期一,即2011-09-12:

 Calendar calendar = Calendar.getInstance(Locale.GERMANY); System.out.printf("First day of week: %d%n%n", calendar.getFirstDayOfWeek()); calendar.set(2011, Calendar.SEPTEMBER, 18); System.out.printf("Starting day: %tF%n", calendar); calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); System.out.printf("Last monday: %tF%n%n", calendar); calendar.set(2011, Calendar.SEPTEMBER, 18); System.out.printf("Starting day: %tF (week %d)%n", calendar, calendar.get(Calendar.WEEK_OF_YEAR)); calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); System.out.printf("Last monday: %tF (week %d)%n", calendar, calendar.get(Calendar.WEEK_OF_YEAR)); 

但实际上结果有点不同:

 First day of week: 2 Starting day: 2011-09-18 Last monday: 2011-09-19 Starting day: 2011-09-18 (week 37) Last monday: 2011-09-12 (week 37) 

换句话说,结果取决于我的日历是否知道我可能对本周感兴趣。 如果我查询WEEK_OF_YEAR ,结果实际上会改变!

来自Javadoc :

如果日历字段值中存在任何冲突,则日历会优先考虑最近设置的日历字段。 以下是日历字段的默认组合。 将使用由最近设置的单个字段确定的最新组合。

对于日期字段:

  YEAR + MONTH + DAY_OF_MONTH YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK YEAR + DAY_OF_YEAR YEAR + DAY_OF_WEEK + WEEK_OF_YEAR 

我认为这意味着,假设您正在设置星期几,它将最终与一周中的一周或一周中的一周相结合,以产生实际的日期和时间。

使用java.time

现代方法是使用java.time类来取代麻烦的旧遗留日期时间类。

java.time类更容易使用。 特别是,它们消除了问题中提出的模糊性。 您可以明确询问早期星期日或晚些星期日。

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

Month enum提供了十几个预定义的对象,一年中的每个月都有一个。 这些枚举对象使用起来更安全,但您可以使用月份的普通数字。 与传统课程不同,这几个月的编号很合理,1月至12月为1-12。

 LocalDate localDate = LocalDate.of( 2009 , Month.AUGUST, 22 ); 

TemporalAdjuster接口提供对日期时间值的操作。 TemporalAdjusters类(注意复数s )提供了几个方便的实现。

previousnext调整者不考虑日期本身。 previousOrSamenextOrSame方法返回有问题的日期,如果它确实是所需的星期几。

DayOfWeek枚举提供了七个预定义的对象,一个对应于一周中的每一天。

 LocalDate previousSunday = localDate.with( TemporalAdjusters.previous ( DayOfWeek.SUNDAY )); LocalDate previousOrSameSunday = localDate.with( TemporalAdjusters.previousOrSame ( DayOfWeek.SUNDAY )); LocalDate nextSunday = localDate.with( TemporalAdjusters.next ( DayOfWeek.SUNDAY )); LocalDate nextOrSameSunday = localDate.with( TemporalAdjusters.nextOrSame ( DayOfWeek.SUNDAY )); 

转储到控制台。

 System.out.println ("localDate: " + localDate + " ( " + localDate.getDayOfWeek ().getDisplayName ( TextStyle.FULL, Locale.US ) + " )"); System.out.println ("previousSunday: " + previousSunday ); System.out.println ("nextSunday: " + nextSunday ); 

localDate:2009-08-22(星期六)

previousSunday:2009-08-16

nextSunday:2009-08-23


关于java.time

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

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。

从哪里获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • ThreeTenABP项目特别适用于Android的ThreeTen-Backport (如上所述)。
    • 请参见如何使用ThreeTenABP ….

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如IntervalYearWeekYearQuarter等。

您还应该检查一周中的第一天。 我也认为它总是星期天,但这取决于当地的设置,在我的情况下,星期一是一周的第一天。 将星期日设置为一周的第一天解决了我的问题。

取决于一周的第一天:

  /** * Gets what the first day of the week is; eg, SUNDAY in the US, * MONDAY in France. * * @return the first day of the week. * @see #setFirstDayOfWeek(int) * @see #getMinimalDaysInFirstWeek() */ public int getFirstDayOfWeek() { return firstDayOfWeek; } 

你可以使用这种方法。

 public Integer whichDayOfWeek(Calendar calendar) { if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { return 1; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY) { return 2; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY) { return 3; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) { return 4; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) { return 5; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) { return 6; } else if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { return 7; } else { return null; } }