Java 时区转换期间的异常行为

Java 时区转换期间的异常行为,java,datetime,timezone,Java,Datetime,Timezone,我正在尝试将在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 *

我正在尝试将在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
尽管美国东部标准时间和格林尼治标准时间之间的时差总是5,但它不知何故与英国夏令时有关


我不能用

SimpleDataFormat.parse(String)方法的javadoc指的是parse(String,ParsePosition)方法,即:

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

根据这一点,您不能使用此方法告诉SimpleDataFormat哪个时区 给定的日期在中。 您可以按如下方式修复此方法:

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字符串的方法。

正确

美国东海岸偏移量 如果您所说的
EST
是指美国东海岸(以及加拿大部分地区),那么您的陈述
EST和GMT之间的时差总是5
是不正确的。使用夏令时(DST),偏移可能为-05:00或-04:00。事实上,您指定的日期时间确实有DST生效

避免使用3-4个字母的时区代码 这三个或四个字母的时区代码既不是标准化的,也不是唯一的。避开它们。使用,其中大部分为大陆+城市

与乔达时间的比较 为了进行比较,下面是一些示例代码。与java捆绑在一起的java.util.Date和.Calendar类非常麻烦,以至于每个java程序员都应该使用Joda Time或new(受Joda Time的启发,由定义)

虽然java.util.Date似乎有时区,但实际上没有,请注意,Joda time确实知道自己分配的时区

Joda Time使用ISO 8601标准作为其默认值。您也可以使用其他格式,如下面的Montréal示例所示

示例代码 转储到控制台

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 );
当运行时

输入:1307011200
纽约时间:2013-07-01T12:00:00.000-04:00
日期时间UTC:2013-07-01T16:00:00.000Z
产量:2013年美国东部夏令时12时00分
输出速度:1307011200

这给了我一个不同的输入输出->1307011200中间->周一至七月一日18:00:00英国夏令时2013输出->1307011700这太奇怪了。我每次都可以在我的机器上复制上面的输出。而且,更奇怪的是,如果我将日期字符串更改为1301011200(1月1日),转换是正确的。这确实有效。我不敢相信,
simpleDataFormat
的正常行为与API的预期相差如此之远。难怪他们正在用java 8:)编写新的java.time API……也难怪java程序员最终会去(直到zovits提到迁移到java 8,这是受Joda time的启发,由Joda time定义的)。Joda Time值得为您的项目添加依赖项。
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 );