为什么 GregorianCalendar.getTimeInMillis() return 值错误?
Why does GregorianCalendar.getTimeInMillis() return wrong value?
我想计算两个日期之间的天数形式的时间间隔。所以我写了下面的代码:
public static int calculateTimeGap(long start, long end) {
GregorianCalendar calendar1 = new GregorianCalendar();
calendar1.setTimeInMillis(start);
System.out.println("calendar1:");
showCalendar(calendar1);
GregorianCalendar calendar2 = new GregorianCalendar();
calendar2.setTimeInMillis(end);
System.out.println("calendar2:");
showCalendar(calendar2);
int gap = (int) (end / 86400000 - start / 86400000);
System.out.println("gap in days:" + gap);
return gap;
}
输出如下:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: calendar1:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: year: 2016
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: month: 3
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: day: 2
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: week: 3
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: hour: 15
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: minute: 28
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: second: 8
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: calendar2:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: year: 2016
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: month: 3
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: day: 3
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: week: 4
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: hour: 1
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: minute: 0
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: second: 0
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out:
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: gap in days:0
你可以看到两个 GregorianCalendar
出现了不同的日子,但最后我们得到的差距等于 0。
该方法的参数start
和end
来自以下代码:
GregorianCalendar curCalendar = new GregorianCalendar();
long start = curCalendar.getTimeInMillis(); // parameter start
GregorianCalendar calendar = new GregorianCalendar(2016, Calendar.MARCH, 3, 1, 0);
long end = calendar.getTimeInMillis(); // parameter end
所以这个行为很奇怪。我认为 gregorianCalendar.getTimeInMillis()
将始终 return 正确且与时区无关的值,因此它可以用作计算和比较时间的稳定且值得信赖的标准。但是,如代码和输出所示,这是错误的。如果我考虑我的时区(北京 GMT+8:00),将偏移量添加 Timezone.getDefault().getRawOffset()
到参数 start
或减去它到 end
,结果将是正确的。但这其实很奇怪。
是什么让我得到了错误的结果?
更新:
public static void showCalendar(GregorianCalendar calendar) {
System.out.println("year: " + calendar.get(Calendar.YEAR));
System.out.println("month: " + (calendar.get(Calendar.MONTH) + 1));
System.out.println("day: " + calendar.get(Calendar.DATE));
System.out.println("week: " + (calendar.get(Calendar.DAY_OF_WEEK) - 1));
System.out.println("hour: " + calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("minute: " + calendar.get(Calendar.MINUTE));
System.out.println("second: " + calendar.get(Calendar.SECOND));
System.out.println(" ");
}
You can see that two GregorianCalendars present different days, but finally we got a gap equals 0.
是的,这是完全合理的。您将 3 月 2 日 15:28:08 与 3 月 3 日 01:00:00 进行比较。他们在不同的日期,但相隔不到一天。这里没有问题。
哎呀,您可以看到两个值相同,这两个值仅相隔 一毫秒 - 它们仍然可以在不同的日期。
请注意,就时区而言,默认情况下 GregorianCalendar
将使用您的系统默认时区。由 getTimeInMillis
编辑的值 return 将始终 return 自 Unix 纪元以来的毫秒数,因此这是时区中立的 - 但您在这里调用的构造函数:
new GregorianCalendar(2016, Calendar.MARCH, 3, 1, 0)
... 表示 "I want the value representing March 3rd, 1am local time" 其中 当地时间 表示 "in your default time zone".
计算日期之间的差异很困难 - 我 非常强烈 建议您完全放弃 Calendar
和 Date
,而是使用 java.time
如果您使用 Java 8,否则 Joda Time。然后你可以用LocalDate
表示没有时间的日期,很容易找出两个日期之间的差异。
您要衡量的不是您定义的天数差距。您要测量的是开始和结束之间的完整 24 小时周期数。
在您的示例中,您的结束时间实际上与开始时间相差不到 24 小时。所以你在 24 小时内的距离是 0.
如果您想测量由当前时区午夜定义的天数差异作为天数之间的边界,您应该比较两个 Calendar 对象的 DAY_OF_YEAR and YEAR 值。
我想计算两个日期之间的天数形式的时间间隔。所以我写了下面的代码:
public static int calculateTimeGap(long start, long end) {
GregorianCalendar calendar1 = new GregorianCalendar();
calendar1.setTimeInMillis(start);
System.out.println("calendar1:");
showCalendar(calendar1);
GregorianCalendar calendar2 = new GregorianCalendar();
calendar2.setTimeInMillis(end);
System.out.println("calendar2:");
showCalendar(calendar2);
int gap = (int) (end / 86400000 - start / 86400000);
System.out.println("gap in days:" + gap);
return gap;
}
输出如下:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: calendar1:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: year: 2016
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: month: 3
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: day: 2
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: week: 3
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: hour: 15
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: minute: 28
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: second: 8
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: calendar2:
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: year: 2016
03-02 15:28:08.021 20814-20814/com.ywwynm.everythingdone I/System.out: month: 3
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: day: 3
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: week: 4
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: hour: 1
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: minute: 0
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: second: 0
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out:
03-02 15:28:08.022 20814-20814/com.ywwynm.everythingdone I/System.out: gap in days:0
你可以看到两个 GregorianCalendar
出现了不同的日子,但最后我们得到的差距等于 0。
该方法的参数start
和end
来自以下代码:
GregorianCalendar curCalendar = new GregorianCalendar();
long start = curCalendar.getTimeInMillis(); // parameter start
GregorianCalendar calendar = new GregorianCalendar(2016, Calendar.MARCH, 3, 1, 0);
long end = calendar.getTimeInMillis(); // parameter end
所以这个行为很奇怪。我认为 gregorianCalendar.getTimeInMillis()
将始终 return 正确且与时区无关的值,因此它可以用作计算和比较时间的稳定且值得信赖的标准。但是,如代码和输出所示,这是错误的。如果我考虑我的时区(北京 GMT+8:00),将偏移量添加 Timezone.getDefault().getRawOffset()
到参数 start
或减去它到 end
,结果将是正确的。但这其实很奇怪。
是什么让我得到了错误的结果?
更新:
public static void showCalendar(GregorianCalendar calendar) {
System.out.println("year: " + calendar.get(Calendar.YEAR));
System.out.println("month: " + (calendar.get(Calendar.MONTH) + 1));
System.out.println("day: " + calendar.get(Calendar.DATE));
System.out.println("week: " + (calendar.get(Calendar.DAY_OF_WEEK) - 1));
System.out.println("hour: " + calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("minute: " + calendar.get(Calendar.MINUTE));
System.out.println("second: " + calendar.get(Calendar.SECOND));
System.out.println(" ");
}
You can see that two GregorianCalendars present different days, but finally we got a gap equals 0.
是的,这是完全合理的。您将 3 月 2 日 15:28:08 与 3 月 3 日 01:00:00 进行比较。他们在不同的日期,但相隔不到一天。这里没有问题。
哎呀,您可以看到两个值相同,这两个值仅相隔 一毫秒 - 它们仍然可以在不同的日期。
请注意,就时区而言,默认情况下 GregorianCalendar
将使用您的系统默认时区。由 getTimeInMillis
编辑的值 return 将始终 return 自 Unix 纪元以来的毫秒数,因此这是时区中立的 - 但您在这里调用的构造函数:
new GregorianCalendar(2016, Calendar.MARCH, 3, 1, 0)
... 表示 "I want the value representing March 3rd, 1am local time" 其中 当地时间 表示 "in your default time zone".
计算日期之间的差异很困难 - 我 非常强烈 建议您完全放弃 Calendar
和 Date
,而是使用 java.time
如果您使用 Java 8,否则 Joda Time。然后你可以用LocalDate
表示没有时间的日期,很容易找出两个日期之间的差异。
您要衡量的不是您定义的天数差距。您要测量的是开始和结束之间的完整 24 小时周期数。
在您的示例中,您的结束时间实际上与开始时间相差不到 24 小时。所以你在 24 小时内的距离是 0.
如果您想测量由当前时区午夜定义的天数差异作为天数之间的边界,您应该比较两个 Calendar 对象的 DAY_OF_YEAR and YEAR 值。