【问题标题】:Odd behavior during timezone conversion时区转换期间的奇怪行为
【发布时间】:2014-03-11 15:13:46
【问题描述】:

我正在尝试将在 EST 时区打印的日期转换为在 GMT/UTC 打印的日期

package com.stefano;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;


public class MainEntry {

/**
 * @param args
 * @throws ParseException 
 */


public static void main(String[] args) throws ParseException {


    String dateTime = "1307011200"; //12:00PM 01 July 2013
    System.out.println("Input -> " + dateTime);
    SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm");
    format.setTimeZone(TimeZone.getTimeZone("EST"));
    Date date = format.parse(dateTime);
    System.out.println("Intermediate -> " + date);
    format.setTimeZone(TimeZone.getTimeZone("GMT"));
    System.out.println("Output -> " + format.format(date));


    }

}

它给出的输出是:

Input -> 1307011200
Intermediate -> Mon Jul 01 17:00:00 BST 2013
Output -> 1307011600

尽管 EST 和 GMT 之间的时差始终为 5,但它以某种方式与 BST 相关。

我不能使用Joda-Time

【问题讨论】:

  • 这给了我不同的输入输出 -> 1307011200 中级 -> Mon Jul 01 18:00:00 BST 2013 Output -> 1307011700
  • 这太奇怪了。我每次都可以在我的机器上重现它作为上述输出。
  • 另外,更奇怪的是 - 如果我将日期字符串更改为 1301011200(1 月 1 日),则转换是正确的。

标签: java datetime timezone


【解决方案1】:

SimpleDateFormat.parse(String) 方法的 javadoc 引用了 parse(String, ParsePosition) 方法,上面写着:

此解析操作使用日历来生成日期。因此,日历的日期时间字段和 TimeZone 值可能已被覆盖,具体取决于子类实现。之前通过调用 setTimeZone 设置的任何 TimeZone 值可能需要恢复以进行进一步操作。

据此,您不能使用此方法告诉 SimpleDateFormat 哪个时区 给定的日期在。 您可以像这样修复此方法:

String dateTime = "1307011200"; // 12:00PM 01 July 2013
dateTime += " EST"; // append the timezone information to the input string
System.out.println("Input -> " + dateTime);
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmm z"); // tell the formatter to look for the timezone info
Date date = format.parse(dateTime);
System.out.println("Intermediate -> " + date);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("Output -> " + format.format(date));

这也将使用您的本地时区打印 Date 对象,但它显示了一种使用给定时区解析 dateTime 字符串的方法。

【讨论】:

  • 确实工作。我无法相信SimpleDateFormat 的正常行为与 API 的预期相差甚远。
  • 难怪他们在 Java 8 中编写新的 java.time API :)
  • 而且……难怪 Java 程序员最终会转向 Joda-Time(直到迁移到 Java 8 的 java.time package,正如 zovits 所提到的,受 Joda-Time 的启发,由 JSR 310 定义)。 Joda-Time 值得为您的项目添加依赖项。
【解决方案2】:

answer by zovits 是正确的。

美国东海岸偏移

如果EST 是指美国东海岸(和加拿大部分地区),那么您的the time difference between EST and GMT is always 5 陈述不正确。使用夏令时 (DST),偏移量可能是 -05:00 -04:00。事实上,您指定的日期时间确实有 DST。

避免使用 3-4 个字母的时区代码

这三个或四个字母的时区代码既不是标准化的也不是唯一的。避开他们。使用proper time zone names,大部分是大陆+城市。

与 Joda-Time 的比较

为了比较,这里有一些Joda-Time 示例代码。与 Java 捆绑在一起的 java.util.Date 和 .Calendar 类非常麻烦,以至于每个 Java 程序员都应该迁移到 Joda-Time 或新的 Java 8 java.time package(受 Joda-Time 启发,由 JSR 310 定义) .

虽然 java.util.Date 似乎有一个时区但实际上没有,但请注意 Joda-Time DateTime 确实知道它自己分配的时区。

Joda-Time 使用 ISO 8601 标准作为其默认值。您也可以使用其他格式,如下面的蒙特利尔示例所示。

示例代码

String input = "1307011200"; //12:00PM 01 July 2013
DateTimeFormatter formatterSmooshed = DateTimeFormat.forPattern( "yyMMddHHmm" );
DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime dateTimeNewYork = formatterSmooshed.withZone( timeZoneNewYork ).parseDateTime( input );
DateTime dateTimeUtc = dateTimeNewYork.withZone( DateTimeZone.UTC );
String outputMontréal = DateTimeFormat.forStyle( "FF" ).withLocale( Locale.CANADA_FRENCH ).print( dateTimeNewYork );
String outputSmooshed = formatterSmooshed.print( dateTimeNewYork ); // Expect same as input.

转储到控制台...

System.out.println( "input: " + input );
System.out.println( "dateTimeNewYork: " + dateTimeNewYork );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "outputMontréal: " + outputMontréal );
System.out.println( "outputSmooshed: " + outputSmooshed );

运行时……

input: 1307011200
dateTimeNewYork: 2013-07-01T12:00:00.000-04:00
dateTimeUtc: 2013-07-01T16:00:00.000Z
outputMontréal: lundi 1 juillet 2013 12 h 00 EDT
outputSmooshed: 1307011200

【讨论】:

    猜你喜欢
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 2014-11-23
    • 2012-07-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-07
    相关资源
    最近更新 更多