使用java.util.Calendar添加天数会产生奇怪的结果
使用java.util.Calendar为日期添加一天,并使用SimpleDateFormat显示结果,通常在3月份,有时似乎会丢失一天,有时会跳过11月份的一天 下面的程序及其输出说明了该问题。请注意,我只是一次添加一天,然后跳过几个月,再添加几天。您将看到2008-03-09打印了两次,但跳过了2008-11-02。同样的事情发生在其他年份,但在不同的日子。我必须进行实验,找出导致问题的时间 如果我没有在SimpleDataFormat中将时区设置为UTC,那么问题就不会发生。我在美国中央时区的一台机器上运行了这个 这看起来确实像日历或SimpleDataFormat中的一个bug,但我还没有在任何地方找到它的文档。有人对这里发生的事情有解释吗 该方案:使用java.util.Calendar添加天数会产生奇怪的结果,java,simpledateformat,Java,Simpledateformat,使用java.util.Calendar为日期添加一天,并使用SimpleDateFormat显示结果,通常在3月份,有时似乎会丢失一天,有时会跳过11月份的一天 下面的程序及其输出说明了该问题。请注意,我只是一次添加一天,然后跳过几个月,再添加几天。您将看到2008-03-09打印了两次,但跳过了2008-11-02。同样的事情发生在其他年份,但在不同的日子。我必须进行实验,找出导致问题的时间 如果我没有在SimpleDataFormat中将时区设置为UTC,那么问题就不会发生。我在美国中央时
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
它看起来更像是一个节省时间的问题,在3月和11月会发生变化。您可以尝试将时间元素设置为00:00:00吗?如果你这样做
addDays("2008-03-08 00:00:00");
addDays("2009-03-07 00:00:00");
addDays("2010-03-13 00:00:00");
并将格式更改为
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
您将看到它在时间元素上的差异。这是由时间元素引起的,完全正确
北半球的时间提前了一个小时,通常是在3月份,11月份又推迟到11月份。当您遇到此类问题时,您必须打印日历和日期实例以了解发生了什么 以下是:
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
根据JVM本地时间和时区更改日历的时间。Calendar.getInstance;在执行Calendar.setTimesdf.parse…..时,在JVM本地时间中创建日历。。。。。根据创建sdf!的方式,以UTC为单位设置时间!。取决于年份和年份!这会让你度过午夜,当你用yyyy-MM-dd格式打印日期时,你会看到一天的差异
打印完整的日历和完整的日期,你就会知道发生了什么 夏时制
错误是正确的,问题是DST
当地时间在3月的第二个星期日从当地标准时间02:00更改为当地夏时制03:00,并在11月的第一个星期日从当地夏时制02:00恢复为当地标准时间01:00
参见维基百科
乔达时间
图书馆使这类工作容易得多
一个在乔达时代的人知道自己。要使用/GMT无时间偏移,请传递内置的常量DateTimeZone.UTC
要仅打印日期时间的日期部分,请使用
//©2013巴西尔布尔克。此源代码可以由任何对此承担全部责任的人自由使用。
//导入org.joda.time.*;
//导入org.joda.time.format.*;
字符串日期字符串=2008-03-08;
//在这个例子中,withTimeAtStartOfDay可能是多余的,但我喜欢它自己记录我们对一天的关注,而不是一天中的某个特定时间。
DateTime DateTime=新的DateTime日期字符串,DateTimeZone.UTC.withTimeAtStartOfDay;
DateTime dateTimePlus1=DateTime.plusDays 1.带有时间开始日期;
DateTime dateTimePlus2=DateTime.plusDays 2.带时间开始日期;
DateTime dateTimePlus3=DateTime.plusDays 3.带时间开始日期;
转储到控制台
System.out.printlndateTime:+dateTime;
System.out.printlndateTime日期部分:+ISODateTimeFormat.date.withZone DateTimeZone.UTC.print dateTime;
System.out.printlndateTimePlus1:+dateTimePlus1;
System.out.printlndateTimePlus2:+dateTimePlus2;
System.out.printlndateTimePlus3:+dateTimePlus3;
当运行时
日期时间:2008-03-08T00:00:00.000Z
日期时间日期部分:2008-03-08
dateTimePlus1:2008-03-09T00:00:00.000Z
dateTimePlus2:2008-03-10T00:00:00.000Z
dateTimePlus3:2008-03-11T00:00:00.000Z
由于时区设置为UTC,夏令时是否重要?根据本节,UTC不知道DST@srikfreak但日历不是UTC格式。发生这种情况时的诀窍是检查您的假设:我刚刚打印了日历本身,没有SDF,问题很明显,因为日历的TZ发生了变化。谢谢。我想你所说的打印日历是指调用字符串。我又做了一些测试。当添加一个日历日时,我的时区CST中的日历将在春季提前日添加23小时,在秋季推迟日添加25小时。如果SimpleDataFormat也是CST,它将正确打印当天,但如果是UTC,则添加的23个小时并不能让您完全进入第二天。到了秋天,25个小时增加了UTC一天内的跳跃。如果日历为UTC,则始终添加24小时。关键的一点是日历和SimpleDateFormat应该在时区上达成一致。但是,只有当你告诉他们使用相同的TZ时,他们才会在时区上达成一致。欢迎来到Java时间/日期处理的世界。吹毛求疵:sdf.setTimeZone不会更改日历的时间,它会更改sdf的时间,wh ich然后用于设置日历的时间。