java - WEEK_OF_YEAR 在不同机器上不一致

标签 java calendar jvm

更新: 好的,我似乎找到了一半的答案。如果我使用无参数 getInstance 创建我的日历,我得到 WEEK_OF_YEAR = 52。但是,如果我通过向 getInstance 提供 Local.getDefaul() 创建它,我得到 WEEK_OF_YEAR = 1。完全没想到这个......我想需要重新阅读日历文档。

根据时间戳构建日历,时间戳对应于星期六,2011 年 1 月 1 日 00:00:00 GMT

使用 java.util.Date、Calendar 和 TimeZone 的相同代码在不同机器(具有相同语言环境)上表现不同;日历中的所有字段都相同,除了 WEEK_OF_YEAR。在我的机器上它是 52(实际上在我的两台机器上)。在我同事的机器上它是 1(这似乎是正确的)。

import java.util.Date;
import java.util.TimeZone;
import java.util.Calendar;
import java.util.Locale;

public class CalendarTest {

    public static void main(String[] args) {

        Locale l = Locale.getDefault();
        System.out.println(l);
        Long d = new Long(1293840000000l);

        Calendar c = Calendar.getInstance();
        c.setTimeZone(TimeZone.getTimeZone("UTC"));
        c.setTime(new Date(d));

        System.out.println(c.toString());
}

.. 语言环境是 en_US,但日历是:

>java.util.GregorianCalendar[time=1293840000000,
areFieldsSet=true,
areAllFieldsSet=true,
lenient=true,
zone=sun.util.calendar.ZoneInfo[
id="UTC",
offset=0,
dstSavings=0,
useDaylight=false,
transitions=0,lastRule=null
],
firstDayOfWeek=2,
minimalDaysInFirstWeek=4,
ERA=1,
YEAR=2011,
MONTH=0,
WEEK_OF_YEAR=52,
WEEK_OF_MONTH=0,
DAY_OF_MONTH=1,
DAY_OF_YEAR=1,
DAY_OF_WEEK=7,
DAY_OF_WEEK_IN_MONTH=1,
AM_PM=0,HOUR=0,
HOUR_OF_DAY=0,
MINUTE=0,
SECOND=0,
MILLISECOND=0,
ZONE_OFFSET=0,
DST_OFFSET=0]

可能是什么导致了 WEEK_OF_YEAR 不一致?

最佳答案

firstDayOfWeekminimalDaysInFirstWeek

原来是一个特性,而不是一个错误。

导致您看到不同行为的原因是问题中显示的输出中报告的两个设置:

  • firstDayOfWeek
  • minimalDaysInFirstWeek

阅读类和子类的文档很重要:

第二个文档详细解释了上面列出的这两个设置对于确定本地化周的重要性。

日历

注意日历。 2011 年的第一天是星期六。每月的第二个星期日,星期日是美国默认的一周开始时间。

Calendar of month of January 2011 showing the first of the month is a Saturday

在设置为美国区域设置的 Mac OS X 计算机上,这些设置均为 1。如果所需的最少天数为 1,则第一个登陆在本地化的第 1 周。Java 报告了这一点。

但在您报告的问题机器上,这些设置分别为 2 和 4。我不知道您是如何从通常的默认设置中更改这些设置的,但您确实做到了。

  • firstDayOfWeek | 12(周日与周一)
  • minimalDaysInFirstWeek | 14

最少 4 天意味着第一天不符合新年的一周。所以现在是前一年(2010 年)的第 52 周。 2011 年的第一周是 2011 年 1 月 2 日到 1 月 8 日。

因此,根据 Java 7 中 java.util.Calendar 类的文档,您看到的行为符合预期。谜团是这些设置是如何从您的问题机器上的默认设置更改的?

ISO 8601

顺便说一下,文档提到 2 和 4 的设置为您提供了 ISO 8601 定义的行为标准,如 my other answer 中所述.这可能是关于为什么这些设置在您的问题机器上不是默认设置的线索。某些人(系统管理员或程序员)可能正在尝试获得标准行为而不是本地化行为。

示例代码

让我们用一些代码来证明这一点。我们将使用问题代码的修改版本。我们此处的代码明确设置了相关变量。所以你可以在你的任何一台机器上运行这个例子,无论是正常的还是有问题的。首先,我们强制使用美国语言环境机器上的默认设置,1 & 1。然后我们使用问题中报告的设置,2 & 4

Locale l = Locale.getDefault();
System.out.println( l + "\n" );
Long d = new Long( 1293840000000l );

Calendar c = Calendar.getInstance();
c.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
c.setTime( new Date( d ) );

// Running Java 8 Update 11, Mac OS 10.8.5, virtual machine in Parallels 9, hosted on Mac with Mavericks.

// Force the use of default settings found on a machine set for United States locale (using Apple defaults).
c.setFirstDayOfWeek( 1 );
c.setMinimalDaysInFirstWeek( 1 );
// Reports: WEEK_OF_YEAR=1
System.out.println( "Default US settings:\n" + c.toString() + "\n" );

// Using reported settings (Coincides with ISO 8601 Week definition).
c.setFirstDayOfWeek( 2 );
c.setMinimalDaysInFirstWeek( 4 );
// Reports: WEEK_OF_YEAR=52
System.out.println( "Reported settings (ISO 8601):\n" + c.toString() + "\n" );

运行时...

en_US

Default US settings:
java.util.GregorianCalendar[time=1293840000000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2011,MONTH=0,WEEK_OF_YEAR=1,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=1,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]

Reported settings (ISO 8601):
java.util.GregorianCalendar[time=1293840000000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2011,MONTH=0,WEEK_OF_YEAR=52,WEEK_OF_MONTH=0,DAY_OF_MONTH=1,DAY_OF_YEAR=1,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=0,DST_OFFSET=0]

故事寓意

使用ISO 8601 standard weeks ! 😉


感谢 Marco13,他对问题的评论引发了这个答案。

关于java - WEEK_OF_YEAR 在不同机器上不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24828014/

相关文章:

java - Mixpanel - 使用 Java API 取消设置人们的属性(property)?

java - 没有毫秒的日历与毫秒为 0 的日历

ios - 在 iOS 中创建自定义日历/月 View

使用正确的时区将 ICS 导入 Google 日历

java - JVM(Java 传输客户端)缓存 DNS 条目 AWS 的 IP 地址

java - JSP和Spring MVC的多个复选框,如何获取值

Java Hangman Oop 静态、非静态

java - 将现有项目的构建路径添加到新项目

.net - 压缩对象指针的目的是什么?

process - 如何将正在运行的Java程序从一台机器迁移到另一台机器?