Calendar.get(Calendar.DAY_OF_MONTH) 返回错误日期
Calendar.get(Calendar.DAY_OF_MONTH) returning wrong day
当我运行以下代码时:
int year = 2017;
int month = 7;
int dayOfMonth = 10;
Calendar dateOfBirth = new GregorianCalendar(year, month, dayOfMonth);
dateOfBirth.getTime(); // See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4827490
dateOfBirth.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Original Day Of Month:\t\t" + dayOfMonth);
System.out.println("Calendar:\t\t\t" + dateOfBirth);
System.out.println("Calendar substring:\t\t" + dateOfBirth.toString().substring(dateOfBirth.toString().indexOf("DAY_OF_MONTH"), dateOfBirth.toString().indexOf("DAY_OF_MONTH") + 15));
System.out.println("Formatted date:\t\t\t" + new SimpleDateFormat("dd").format(dateOfBirth.getTime()));
System.out.println("get(Calendar.DAY_OF_MONTH):\t" + dateOfBirth.get(Calendar.DAY_OF_MONTH));
我得到这个输出:
Original Day Of Month: 10
Calendar: java.util.GregorianCalendar[time=1502312400000,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=7,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=10,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
Calendar substring: DAY_OF_MONTH=10
Formatted date: 10
get(Calendar.DAY_OF_MONTH): 9
如您所见,dateOfBirth.get(Calendar.DAY_OF_MONTH)
返回的值不正确。
我使用 UTC 是因为它是出生日期,我不希望它依赖于特定时区。为了正确执行此操作,我需要调用 dateOfBirth.getTime()
- 请参阅 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4827490。
如果我取消那个电话,这会正常工作,但随后我会遇到其他错误。
知道我可以做些什么来准确地得到一个月中的正确日期吗?
我正在使用 Java v1.7。0_79,并且,以防万一,我目前使用的是 GMT+3。
设置时区后只需设置日期值:
int year = 2017;
int month = Calendar.JULY;
int dayOfMonth = 10;
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.set(year, month, dayOfMonth);
System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
这会正确输出月中的第几天:
DAY_OF_MONTH: 10
很高兴 解决了您的问题。我想解释一下发生了什么以及为什么这个答案有帮助。
当您使用三参数 GregorianCalendar
构造函数时,它“构造一个 GregorianCalendar
并在默认时区 中设置给定日期 默认语言环境。”引用文档;斜体字是我的。在你的情况下,这是 GMT+3(现在;重要的是在八月它仍然是 GMT plus 东西)。
文档不太清楚的是将一天中的小时设置为 0,所以你确实得到了 2017 年 8 月 10 日 0:00 时区偏移 +[=63= 的时间点].你真的希望 GregorianCalendar
不用担心一天中的时间,但没有这样的事情。正如我在评论中提到的那样,这就是我推荐 LocalDate
的原因之一。
当您更改时区时,时间点保持不变,但由于您在自己的时区早于格林威治标准时间,因此您现在拥有 2017 年 8 月 9 日 21:00 UTC。所以现在 9 是正确的日期值。
我认为最大的惊喜是 toString
方法仍然产生 DAY_OF_MONTH=10
。当 GregorianCalendar
计算哪些字段对我来说是模糊的,但显然此时仍记得旧值。
对于格式,您使用 new SimpleDateFormat("dd")
。此格式化程序使用您的默认时区 GMT+3,以及来自日历对象的时间点,正确生成 10。如果您希望它从日历中生成日期,您可能已经设置了它的时区也到 UTC。
dateOfBirth.get(Calendar.DAY_OF_MONTH)
生成正确的值 9。
有趣的是,如果在这次通话后我重复你的话:
System.out.println("Calendar substring:\t\t"
+ dateOfBirth.toString().substring(dateOfBirth.toString().indexOf("DAY_OF_MONTH"),
dateOfBirth.toString().indexOf("DAY_OF_MONTH") + 15));
这次它产生:
Calendar substring: DAY_OF_MONTH=9,
现在已经计算了该字段。
在 Robby Cornelissen 的代码中,日历对象天生带有 UTC 时区,因此当您设置日期时,它实际上设置为 — 好吧,这次是 2017 年 7 月 10 日,但是 0:00 UTC。这对应于您所在时区的 3:00,但那里的日期也是 7 月 10 日,因此您的其余代码将产生您预期的 10。但是,格林威治以西时区的用户现在会遇到问题,因为他们的 SimpleDateFormat
将使用他们的时区,该时区晚于格林威治标准时间,因此他们将看到 09
.
的格式化日期
为了完整起见,这里是 ThreeTen(向后移植)版本:
LocalDate date = LocalDate.of(2017, Month.AUGUST, 10);
System.out.println("Day of month:\t" + date.getDayOfMonth());
这会打印
Day of month: 10
A LocalDate
既没有一天中的任何时间也没有任何时区,因此混淆的空间要小得多。与 Calendar
相反,它还按照人类的方式对月份进行编号,因此 7 是七月,8 是八月。
当我运行以下代码时:
int year = 2017;
int month = 7;
int dayOfMonth = 10;
Calendar dateOfBirth = new GregorianCalendar(year, month, dayOfMonth);
dateOfBirth.getTime(); // See http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4827490
dateOfBirth.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Original Day Of Month:\t\t" + dayOfMonth);
System.out.println("Calendar:\t\t\t" + dateOfBirth);
System.out.println("Calendar substring:\t\t" + dateOfBirth.toString().substring(dateOfBirth.toString().indexOf("DAY_OF_MONTH"), dateOfBirth.toString().indexOf("DAY_OF_MONTH") + 15));
System.out.println("Formatted date:\t\t\t" + new SimpleDateFormat("dd").format(dateOfBirth.getTime()));
System.out.println("get(Calendar.DAY_OF_MONTH):\t" + dateOfBirth.get(Calendar.DAY_OF_MONTH));
我得到这个输出:
Original Day Of Month: 10
Calendar: java.util.GregorianCalendar[time=1502312400000,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=7,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=10,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
Calendar substring: DAY_OF_MONTH=10
Formatted date: 10
get(Calendar.DAY_OF_MONTH): 9
如您所见,dateOfBirth.get(Calendar.DAY_OF_MONTH)
返回的值不正确。
我使用 UTC 是因为它是出生日期,我不希望它依赖于特定时区。为了正确执行此操作,我需要调用 dateOfBirth.getTime()
- 请参阅 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4827490。
如果我取消那个电话,这会正常工作,但随后我会遇到其他错误。
知道我可以做些什么来准确地得到一个月中的正确日期吗?
我正在使用 Java v1.7。0_79,并且,以防万一,我目前使用的是 GMT+3。
设置时区后只需设置日期值:
int year = 2017;
int month = Calendar.JULY;
int dayOfMonth = 10;
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
calendar.set(year, month, dayOfMonth);
System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
这会正确输出月中的第几天:
DAY_OF_MONTH: 10
很高兴
当您使用三参数 GregorianCalendar
构造函数时,它“构造一个 GregorianCalendar
并在默认时区 中设置给定日期 默认语言环境。”引用文档;斜体字是我的。在你的情况下,这是 GMT+3(现在;重要的是在八月它仍然是 GMT plus 东西)。
文档不太清楚的是将一天中的小时设置为 0,所以你确实得到了 2017 年 8 月 10 日 0:00 时区偏移 +[=63= 的时间点].你真的希望 GregorianCalendar
不用担心一天中的时间,但没有这样的事情。正如我在评论中提到的那样,这就是我推荐 LocalDate
的原因之一。
当您更改时区时,时间点保持不变,但由于您在自己的时区早于格林威治标准时间,因此您现在拥有 2017 年 8 月 9 日 21:00 UTC。所以现在 9 是正确的日期值。
我认为最大的惊喜是 toString
方法仍然产生 DAY_OF_MONTH=10
。当 GregorianCalendar
计算哪些字段对我来说是模糊的,但显然此时仍记得旧值。
对于格式,您使用 new SimpleDateFormat("dd")
。此格式化程序使用您的默认时区 GMT+3,以及来自日历对象的时间点,正确生成 10。如果您希望它从日历中生成日期,您可能已经设置了它的时区也到 UTC。
dateOfBirth.get(Calendar.DAY_OF_MONTH)
生成正确的值 9。
有趣的是,如果在这次通话后我重复你的话:
System.out.println("Calendar substring:\t\t"
+ dateOfBirth.toString().substring(dateOfBirth.toString().indexOf("DAY_OF_MONTH"),
dateOfBirth.toString().indexOf("DAY_OF_MONTH") + 15));
这次它产生:
Calendar substring: DAY_OF_MONTH=9,
现在已经计算了该字段。
在 Robby Cornelissen 的代码中,日历对象天生带有 UTC 时区,因此当您设置日期时,它实际上设置为 — 好吧,这次是 2017 年 7 月 10 日,但是 0:00 UTC。这对应于您所在时区的 3:00,但那里的日期也是 7 月 10 日,因此您的其余代码将产生您预期的 10。但是,格林威治以西时区的用户现在会遇到问题,因为他们的 SimpleDateFormat
将使用他们的时区,该时区晚于格林威治标准时间,因此他们将看到 09
.
为了完整起见,这里是 ThreeTen(向后移植)版本:
LocalDate date = LocalDate.of(2017, Month.AUGUST, 10);
System.out.println("Day of month:\t" + date.getDayOfMonth());
这会打印
Day of month: 10
A LocalDate
既没有一天中的任何时间也没有任何时区,因此混淆的空间要小得多。与 Calendar
相反,它还按照人类的方式对月份进行编号,因此 7 是七月,8 是八月。