java.util.Date - 测试转换美国 <-> 英国

标签 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。

最佳答案

伦敦夏令时

伦敦时间更改为 Daylight Saving Time (DST) ending在 2013-10-27 凌晨 2 点变成凌晨 1 点(再次)。

功能,而不是错误

documentation for java.util.Calendar在顶部的讨论中解释说,与 set() 不同,add() 强制立即重新计算日历的毫秒数和所有字段。

此外,documentation for java.util.GregorianCalendaradd 方法中注意较小的时间单位未调整。该文档特别指出 HOUR 是一个比 DAY_OF_MONTH 更小的字段,因此未对其进行调整。这意味着您从 23 小时开始,所以您将以 23 小时结束,毫秒自- epoch根据需要重新计算。

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

间接回答

捆绑java.util.Date 、java.util.Calendar 和 java.text.SimpleDateFormat 是出了名的麻烦、困惑和棘手。它们在设计和实现上都有缺陷。

我理解您对“使用 Java 的内置功能”感兴趣。虽然这种兴趣通常值得称赞,但在 Java 的这个特定角落,这是浪费时间。 甚至 Sun 和 Oracle 也放弃了这些类(class)。 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 提前五个半小时”。

  • 加号(“+”)表示在 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

关于java.util.Date - 测试转换美国 <-> 英国,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21370847/

相关文章:

java - 使用可选的解析器从 joda-time DateTimeFormatter 打印

java - Libgdx 无法绘制 Sprite

java - 蛇壳和 Camel 壳的混合体叫什么名字?

php - 根据日期时间列查询记录

java - 在 Java 中将字符串解析为日期时出错

json - 如何在 Grails 中为 JSON 转换器设置日期格式

java - 在非 Activity 类中获取 Android App Start Time

java - 向 JTable 添加一列,UI 不会改变

java - jetty worker : Install Maven dependencies during build stage only?

php - DatePeriod 返回空对象