使用 java.util.Calendar 添加天数会产生奇怪的结果
使用 java.util.Calendar 向日期添加一天,并使用 SimpleDateFormat 显示结果,有时似乎会丢失一天(通常在三月),有时会跳过一天(十一月)。
下面的程序及其输出说明了这个问题。请注意,我只是一次添加一天,然后跳过几个月并再添加几天。您将看到 2008-03-09 被打印两次,但 2008-11-02 被跳过。同样的事情在其他年份也会发生,但在不同的日子。我必须尝试找出导致问题的日子。
如果我没有在 SimpleDateFormat 中将时区设置为 UTC,则不会出现问题。我在美国中部时区的一台机器上运行了这个。
这看起来确实像是 Calendar 或 SimpleDateFormat 中的错误,但我无法在任何地方找到它的记录。有人对这里发生的事情有解释吗?
程序:
package mab;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalendarHiccup2 {
public static void main(String[] args) {
addDays("2008-03-08");
addDays("2009-03-07");
addDays("2010-03-13");
}
public static void addDays(String dateString) {
System.out.println("Got dateString: " + dateString);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar calendar = Calendar.getInstance();
try {
calendar.setTime(sdf.parse(dateString));
Date day1 = calendar.getTime();
System.out.println(" day1 = " + sdf.format(day1));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day2 = calendar.getTime();
System.out.println(" day2 = " + sdf.format(day2));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day3 = calendar.getTime();
System.out.println(" day3 = " + sdf.format(day3));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day4 = calendar.getTime();
System.out.println(" day4 = " + sdf.format(day4));
// Skipping a few days ahead:
calendar.add(java.util.Calendar.DAY_OF_MONTH, 235);
Date day5 = calendar.getTime();
System.out.println(" day5 = " + sdf.format(day5));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day6 = calendar.getTime();
System.out.println(" day6 = " + sdf.format(day6));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day7 = calendar.getTime();
System.out.println(" day7 = " + sdf.format(day7));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day8 = calendar.getTime();
System.out.println(" day8 = " + sdf.format(day8));
} catch (Exception e) {
}
}
}
输出:
Got dateString: 2008-03-08
day1 = 2008-03-08
day2 = 2008-03-09
day3 = 2008-03-09
day4 = 2008-03-10
day5 = 2008-10-31
day6 = 2008-11-01
day7 = 2008-11-03
day8 = 2008-11-04
Got dateString: 2009-03-07
day1 = 2009-03-07
day2 = 2009-03-08
day3 = 2009-03-08
day4 = 2009-03-09
day5 = 2009-10-30
day6 = 2009-10-31
day7 = 2009-11-02
day8 = 2009-11-03
Got dateString: 2010-03-13
day1 = 2010-03-13
day2 = 2010-03-14
day3 = 2010-03-14
day4 = 2010-03-15
day5 = 2010-11-05
day6 = 2010-11-06
day7 = 2010-11-08
day8 = 2010-11-09
Using java.util.Calendar to add a single day to a Date, and SimpleDateFormat to display the result, sometimes seems to lose a day (generally in March) and sometimes skips a day (in November).
The program below, with output, illustrates the issue. Notice that I'm just adding one day at a time, then skipping a few months and adding a few more days. You'll see that 2008-03-09 gets printed twice, but 2008-11-02 is skipped. The same thing happens in other years, but on different days. I had to experiment to find the days that cause the problem.
If I don't set the timezone to UTC in the SimpleDateFormat then the problem does not occur. I ran this on a machine in the US Central Time Zone.
This certainly looks like a bug in Calendar or SimpleDateFormat, but I have not been able to find it documented anywhere. Anybody have an explanation of what is happening here?
The program:
package mab;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class CalendarHiccup2 {
public static void main(String[] args) {
addDays("2008-03-08");
addDays("2009-03-07");
addDays("2010-03-13");
}
public static void addDays(String dateString) {
System.out.println("Got dateString: " + dateString);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Calendar calendar = Calendar.getInstance();
try {
calendar.setTime(sdf.parse(dateString));
Date day1 = calendar.getTime();
System.out.println(" day1 = " + sdf.format(day1));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day2 = calendar.getTime();
System.out.println(" day2 = " + sdf.format(day2));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day3 = calendar.getTime();
System.out.println(" day3 = " + sdf.format(day3));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day4 = calendar.getTime();
System.out.println(" day4 = " + sdf.format(day4));
// Skipping a few days ahead:
calendar.add(java.util.Calendar.DAY_OF_MONTH, 235);
Date day5 = calendar.getTime();
System.out.println(" day5 = " + sdf.format(day5));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day6 = calendar.getTime();
System.out.println(" day6 = " + sdf.format(day6));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day7 = calendar.getTime();
System.out.println(" day7 = " + sdf.format(day7));
calendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
Date day8 = calendar.getTime();
System.out.println(" day8 = " + sdf.format(day8));
} catch (Exception e) {
}
}
}
The output:
Got dateString: 2008-03-08
day1 = 2008-03-08
day2 = 2008-03-09
day3 = 2008-03-09
day4 = 2008-03-10
day5 = 2008-10-31
day6 = 2008-11-01
day7 = 2008-11-03
day8 = 2008-11-04
Got dateString: 2009-03-07
day1 = 2009-03-07
day2 = 2009-03-08
day3 = 2009-03-08
day4 = 2009-03-09
day5 = 2009-10-30
day6 = 2009-10-31
day7 = 2009-11-02
day8 = 2009-11-03
Got dateString: 2010-03-13
day1 = 2010-03-13
day2 = 2010-03-14
day3 = 2010-03-14
day4 = 2010-03-15
day5 = 2010-11-05
day6 = 2010-11-06
day7 = 2010-11-08
day8 = 2010-11-09
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是由夏令时引起的,并且是完全正确的。
时间(北半球)通常在三月提前一小时,在十一月则向后推迟一小时。
This is caused by the daylight saving time and is completely correct.
The time (on north hemisphere) is advanced one hour typically in March and moved back in November.
它看起来更像是夏令时问题,在 3 月和 11 月发生变化。您可以尝试将时间元素设置为 00:00:00 吗?如果这样做,
并将格式更改为,
您将看到它在时间元素中产生的差异。
It looks more like a day light saving time issue, which changes in Mar and Nov. Can you try setting the time element to 00:00:00? If you do,
and change the format to,
you'll see the difference it makes in the time elements.
当您遇到此类问题时,您必须打印日历和日期实例才能弄清楚发生了什么。
以下内容:
根据 JVM 本地时间(和时区)更改日历时间。
Calendar.getInstance();
在您的 JVM 本地时间创建一个日历,当您执行calendar.setTime(sdf.parse("....."))
时设置 UTC 时间(考虑到您创建 sdf 的方式!)。根据可以让您度过午夜的 DoY(以及年份!),当您使用 yyyy-MM-dd 格式打印日期时,您会看到一天的差异。打印完整的日历和完整的日期,您就会知道发生了什么!
When you have these kind of issues you have to print the Calendar and Date instances to figure out what's going on.
The following:
changes the time of your Calendar depending on your JVM local time (and timezone).
Calendar.getInstance();
creates a Calendar in your JVM local time, when you docalendar.setTime(sdf.parse("....."))
that sets the time in UTC (given how you created the sdf!). Depending on the DoY (and the Year as well!) that can make you pass the midnight and when you print your Date with the yyyy-MM-dd format you see the one day difference.Print the full Calendar and full Date and you'll figure out what's going on!
夏令时
Tomasz Nurkiewicz 的回答是正确的,问题是夏令时 (DST)。
请参阅维基百科上的 中央时区
Joda-Time
Joda-Time 库使这种工作变得更加容易。
Joda-Time 中的 DateTime 知道其自己的时区。要使用 UTC/GMT(无时间偏移),请传递内置常量
DateTimeZone.UTC
。要仅打印日期时间的日期部分,请使用 DateTimeFormatter。
转储到控制台...
运行时...
Daylight Saving Time
The answer by Tomasz Nurkiewicz is correct, the problem is Daylight Saving Time (DST).
See Wikipedia on Central Time Zone
Joda-Time
The Joda-Time library makes this kind of work much easier.
A DateTime in Joda-Time knows its own time zone. To use UTC/GMT (no time offset), pass the built-in constant
DateTimeZone.UTC
.To print out only the date portion of a date-time, use a DateTimeFormatter.
Dump to console…
When run…