我在下面有这个测试代码。
行/// 1 ///和/// 2 ///是替代品。
如果我使用第///2行///输出看起来有点儿,似乎没有考虑到美国波士顿和英国伦敦在全年没有相差5小时的事实。如果我使用行/// 1 ///它看起来没问题,似乎它解释了这个事实。为什么这样?概念差异在哪里?为什么将这两个日期改为1天(我的意思是在/// 2 ///中)是不正确的?
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class TimeZoneExample02 {
// private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) {
Calendar bostonTime = Calendar.getInstance(TimeZone.getTimeZone("America/New_York"));
Calendar londonTime = new GregorianCalendar(TimeZone.getTimeZone("Europe/London"));
londonTime.setTimeInMillis(bostonTime.getTimeInMillis());
bostonTime.getTime();
londonTime.getTime();
for (int i=0; i>=-500; i--){
bostonTime.add(Calendar.DATE, -1);
// londonTime.setTimeInMillis(bostonTime.getTimeInMillis()); /// 1 ///
londonTime.add(Calendar.DATE, -1); /// 2 ///
bostonTime.getTime();
londonTime.getTime();
System.out.printf("Boston time: %s", getString(bostonTime));
System.out.print(" /// ");
System.out.printf("London time: %s\n", getString(londonTime));
}
}
private static String getString(Calendar c){
StringBuilder sb = new StringBuilder();
sb.append(c.get(Calendar.YEAR));
sb.append("-");
sb.append(String.format("%02d", c.get(Calendar.MONTH) + 1));
sb.append("-");
sb.append(String.format("%02d", c.get(Calendar.DAY_OF_MONTH)));
sb.append(" ");
sb.append(String.format("%02d", c.get(Calendar.HOUR_OF_DAY)));
sb.append(":");
sb.append(String.format("%02d", c.get(Calendar.MINUTE)));
sb.append(":");
sb.append(String.format("%02d", c.get(Calendar.SECOND)));
sb.append(".");
return sb.toString();
}
}
输出1:
波士顿时间:2013-10-30 18:51:12 ///伦敦时间:2013-10-30 22:51:12 波士顿时间:2013-10-29 18:51:12 ///伦敦时间:2013-10-29 22:51:12 波士顿时间:2013-10-28 18:51:12 ///伦敦时间:2013-10-28 22:51:12 波士顿时间:2013-10-27 18:51:12 ///伦敦时间:2013-10-27 22:51:12 波士顿时间:2013-10-26 18:51:12 ///伦敦时间:2013-10-26 23:51:12 波士顿时间:2013-10-25 18:51:12 ///伦敦时间:2013-10-25 23:51:12 波士顿时间:2013-10-24 18:51:12 ///伦敦时间:2013-10-24 23:51:12
输出2:
波士顿时间:2013-10-30 18:50:53 ///伦敦时间:2013-10-30 23:50:53
波士顿时间:2013-10-29 18:50:53 ///伦敦时间:2013-10-29 23:50:53
波士顿时间:2013-10-28 18:50:53 ///伦敦时间:2013-10-28 23:50:53
波士顿时间:2013-10-27 18:50:53 ///伦敦时间:2013-10-27 23:50:53。
波士顿时间:2013-10-26 18:50:53 ///伦敦时间:2013-10-26 23:50:53
波士顿时间:2013-10-25 18:50:53 ///伦敦时间:2013-10-25 23:50:53
波士顿时间:2013-10-24 18:50:53 ///伦敦时间:2013-10-24 23:50:53
答案 0 :(得分:3)
伦敦时间在2013-10-27凌晨2点变为凌晨1点(再次)时随着Daylight Saving Time (DST) ending而变化。
顶部讨论中的documentation for java.util.Calendar解释了unlike set(), add() forces an immediate recomputation of the calendar's milliseconds and all fields.
此外,add
方法的documentation for java.util.GregorianCalendar表示较小的时间单位未调整。该文档特别指出HOUR
是DAY_OF_MONTH
的较小字段,因此不会进行调整。这意味着你以23小时开始,所以你最终得到的是23小时,从毫秒开始 - epoch根据需要重新计算。
您在set
和add
方法中看到的行为都是正确的。 功能,而不是错误。
捆绑的java.util.Date,java.util.Calendar和java.text.SimpleDateFormat是众所周知的麻烦,令人困惑和棘手。它们在设计和实施方面都存在缺陷。
我理解您对“使用Java的内置功能”的兴趣。虽然这种兴趣通常值得称赞,但在Java的这个特定角落,这是浪费时间。 甚至Sun和Oracle都放弃了这些类。 Java 8带来了一个全新的java.time。*包,由JSR 310定义,受Joda-Time启发,并取代旧的捆绑类。
如果您尚未转移到Java 8,请使用Joda-Time。 Joda-Time适用于多个版本的Java,并且在Java 8中继续工作,因为它是主动维护的。
使用Joda-Time 2.3的一些示例代码让您前进。
一些笔记......
Joda-Time DateTime实际上知道自己的时区。相比之下,java.util.Date没有时区,但其toString
方法应用了JVM的默认时区,这不会造成混淆。
请注意,此示例中dateTime_Boston
和dateTime_London
具有相同的毫秒数 - 自纪元以来。
Joda-Time默认使用标准ISO 8601格式进行字符串输出,如2014-02-13T10:32:28.131+05:30
。
末尾的+
或-
标志着与UTC / GMT的时区偏移。 不将此作为公式中的操作数读取。阅读此标签,例如,“印度的时区偏移为+05:30,因此显示的日期时间比UTC / GMT提前了五个半小时”。
最后的Z
发音为“Zulu”,是+00:00
的简写。这意味着UTC / GMT时区,即没有时区偏移。
// Specify a time zone rather than rely on default.
DateTimeZone timeZone_Boston = DateTimeZone.forID( "America/New_York" );
DateTimeZone timeZone_London = DateTimeZone.forID( "Europe/London" );
DateTime dateTime_Boston = new DateTime( 2013, 10, 27, 22, 51, 12, timeZone_Boston );
DateTime dateTime_London = dateTime_Boston.toDateTime( timeZone_London );
DateTime earlier_London = dateTime_London.minusDays( 2 ); // Use '2' to get us before DST change.
DateTime earlier_UtcGmt = earlier_London.toDateTime( DateTimeZone.UTC );
转储到控制台...
System.out.println( "dateTime_Boston " + dateTime_Boston );
System.out.println( "dateTime_London " + dateTime_London );
System.out.println( "earlier_London " + earlier_London );
System.out.println( "earlier_UtcGmt " + earlier_UtcGmt );
跑步时......
dateTime_Boston 2013-10-27T22:51:12.000-04:00
dateTime_London 2013-10-28T02:51:12.000Z
earlier_London 2013-10-26T02:51:12.000+01:00
earlier_UtcGmt 2013-10-26T01:51:12.000Z