在本地机器上日历不同的一年的第一周

Calendar different first week of year on local machine

下面给出了我在笔记本电脑上与其他任何地方不同的结果(之后)。

private static void prindStartOfWeek() 
{
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    System.out.println(" --------- Before : " + cal.getTime());

    cal.set(Calendar.YEAR, 2015);
    cal.set(Calendar.WEEK_OF_YEAR, 1);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    System.out.println(" --------- After : " + cal.getTime());
}

我正在使用 Eclipse KeplerWindows 7 64bitJava jdk1.7.0_65。我也在 Eclipse Junocmd (executable jar) 上进行了测试。同样适用。

我已经在我的笔记本电脑上测试了上面的代码,它打印了

 --------- Before : Fri Nov 20 14:04:07 EET 2015
 --------- After : Sun Jan 04 14:00:00 EET 2015

我已经在 Microsoft Server 2008 运行 Java 7 上进行了测试,它打印了(这是正确的值)

 --------- Before : Fri Nov 20 14:09:01 EET 2015
 --------- After : Sun Dec 28 14:00:00 EET 2014

我测试了 here too 并且它打印了

 --------- Before : Fri Nov 20 10:54:40 UTC 2015
 --------- After : Sun Dec 28 00:00:00 UTC 2014

有谁知道可能出了什么问题?我的笔记本电脑时区是 "Europe\Athens",但我想这应该无关紧要。

此外,这是在另一台计算机上测试的,它打印出正确的值

 --------- Before : Fri Nov 20 14:09:01 EET 2015
 --------- After : Sun Dec 28 14:00:00 EET 2014

getCalendar(TimeZone) "Gets a calendar using the specified time zone and default locale."

正如 @Kartic 在他上面的评论中指出的那样,在某些地方,星期日被认为是一周的第一天,而在其他地方,星期一是一周的第一天 - 这会受到影响您的语言环境。

您 运行 代码所在的机器之间的默认语言环境可能不同。

tl;博士

ZonedDateTime.now()                                     // Capture the current moment as seen through the lens of the wall-clock time used by the people of a particular region (time zone).
             .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )  // Get the week number, with stable results per the ISO 8601 definition of a week that starts on a Monday and considers week # 1 to have the first Thursday of the calendar-year.

语言环境

Calendar class 中,“周”的含义因地区而异。如果在运行时 JVM 的当前默认值 Locale 不同,计算周数的结果可能会不同。

例如,在美国,一周的第一天是星期日。但在欧洲大部分地区,按照 ISO 8601 标准,一周的第一天是星期一。

那个Calendarclass很麻烦,很混乱。幸运的是,现在已经被行业领先的 java.time classes.

所取代

java.time

以 UTC 格式捕捉当前时刻。

Instant instant = Instant.now() ;

时区对于确定日期至关重要。对于任何给定时刻,日期在全球范围内因地区而异。例如,Paris France is a new day while still “yesterday” in Montréal Québec.

午夜后几分钟

如果未指定时区,JVM 将隐式应用其当前默认时区。该默认设置可能随时更改,因此您的结果可能会有所不同。最好明确指定您的 desired/expected 时区作为参数。

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们 不是 真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

应用 ZoneId 得到一个 ZonedDateTime 对象。

ZonedDateTime zdt = instant.atZone( z ) ;

现在查询基于周的年和周。 IsoFields class 提供对象,我们可以通过这些对象获取符合 ISO 8601 标准的周数:

  • 第 1 周是日历年的第一个星期四
  • 星期一是一年的第一天
  • 一年有 52 周或 53 周。
  • 一年中的 last/first 几天可能在 previous/next 周年中。

示例。

int yearIso = zdt.get( IsoFields.WEEK_BASED_YEAR ) ;
int weekIso = zdt.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;

提示: 考虑添加 ThreeTen-Extra library to your project to gain access to the YearWeek class.


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

从哪里获得java.time classes?

  • Java SE 8, Java SE 9,及以后
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and Java SE 7
  • Android
    • Android java.time classes.
    • 捆绑实施的更高版本
    • 对于较早的 Android,ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.