java.util.Date - 测试转换US< - >联合王国

时间:2014-01-26 23:47:49

标签: java date datetime timezone date-conversion

我在下面有这个测试代码。

行/// 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

1 个答案:

答案 0 :(得分:3)

伦敦DST

伦敦时间在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表示较小的时间单位未调整。该文档特别指出HOURDAY_OF_MONTH的较小字段,因此不会进行调整。这意味着你以23小时开始,所以你最终得到的是23小时,从毫秒开始 - epoch根据需要重新计算。

您在setadd方法中看到的行为都是正确的。 功能,而不是错误。

间接答案

捆绑的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_BostondateTime_London具有相同的毫秒数 - 自纪元以来。

Joda-Time默认使用标准ISO 8601格式进行字符串输出,如2014-02-13T10:32:28.131+05:30

末尾的+-标志着与UTC / GMT的时区偏移。 将此作为公式中的操作数读取。阅读此标签,例如,“印度的时区偏移为+05:30,因此显示的日期时间比UTC / GMT提前了五个半小时”。

  • PLUS SIGN(“+”)表示超过UTC / GMT
  • HYPHEN-MINUS(“ - ”)表示落后于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