6

我按照下面的代码在指定的 dateTime 上使用指定的时区创建一个 Date 对象。
注意:我没有为 jvm 设置任何时区;但是用不同的 linux 服务器时区测试这段代码。

    String date = "20121225 10:00:00";
    String timeZoneId = "Asia/Calcutta";
    TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);

    DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
                //This date object is given time and given timezone
    java.util.Date parsedDate = dateFormatLocal.parse(date + " "  
                     + timeZone.getDisplayName(false, TimeZone.SHORT));

    if (timeZone.inDaylightTime(parsedDate)) {
        // We need to re-parse because we don't know if the date
        // is DST until it is parsed...
        parsedDate = dateFormatLocal.parse(date + " "
                + timeZone.getDisplayName(true, TimeZone.SHORT));
    }


现在 parsedDate 对象的行为不同
当我的 jvm 服务器在 IST 中运行时
parsedDate.getTime() -- 1356409800000
parsedDate.toString() -- Tue Dec 25 10:00:00 IST 2012
in GMT --- 12/25/2012 04: 30:00 GMT
当我的 jvm 服务器在 EST 运行时
parsedDate.getTime() -- 1356422400000
parsedDate.toString() -- Tue Dec 25 03:00:00 EST 2012
in GMT --- 12/25/2012 08:00 :00 格林威治标准时间

我的两个系统时间是同步的
Mon Dec 24 10:30:04 EST 2012
Mon Dec 24 21:00:48 IST 2012
我期望在两台机器上我应该得到相同的 GMT 时间。
这里出了什么问题?

4

3 回答 3

4

我认为问题在于您正在尝试解析 IST,并且它具有不同的含义,具体取决于您默认的“位置”是什么。

Time Zone Abbreviation  Zone Description    Relative UTC
IST     Irish Summer Time   UTC+01
IST     Israeli Standard Time   UTC+02
IST     Iran Standard Time  UTC+0330
IST     Indian Standard Time    UTC+0530

如果您的位置是印度,它会按照您的预期处理 IST,但如果您使用美国,它会猜测不同的时区。

解决方案是不使用三个字母的时区并明确设置它们。

String date = "20121225 10:00:00";
String timeZoneId = "Asia/Calcutta";
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);

DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
dateFormatLocal.setTimeZone(timeZone);

Date parsedDate = dateFormatLocal.parse(date);

http://www.worldtimezone.com/wtz-names/wtz-ist.html

于 2012-12-28T20:48:56.100 回答
3

短名称不是识别时区的好方法,因为它不是唯一的;Javadocjava.util.TimeZone给出了“'CST' 可以是美国'中部标准时间'和'中国标准时间'”的例子。

更普遍 。. . 而不是将时区作为字符串传递,以便您DateFormat必须解析它,而是通过使用您已经拥有DateFormat的实例来告诉您时区是什么更有意义:TimeZone

    DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
    dateFormatLocal.setTimeZone(timeZone);
    java.util.Date parsedDate = dateFormatLocal.parse(date);

(这也将在可能的范围内自动处理夏令时。)

于 2012-12-28T20:35:27.607 回答
1

这里有一个简短的Groovy脚本来演示如何使用缩写的时区名称是一个问题,并且结果会因本地环境而异,尤其是本地默认值TimeZone

假设您要解析2015-02-20T17:21:17.190EST,并且您认为 EST =美国东海岸意义上的东部标准时间,因此是纽约市时间。因此,您期望纪元时间是准确的1424470877190,或者GMT: Fri, 20 Feb 2015 22:21:17.190 GMT因为这ESTGMT-0500。这是一个测试脚本,显示了当前默认值TimeZone如何影响如何EST被解释。

import java.util.*
import java.text.*

SimpleDateFormat sdf

TimeZone.setDefault(TimeZone.getTimeZone("Australia/Sydney"))
printDefaultTimeZone()

sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz")

checkTime(sdf.parse("2015-02-20T17:21:17.190EST").getTime())
checkTime(sdf.parse("2015-02-20T17:21:17.190-0500").getTime())

TimeZone.setDefault(TimeZone.getTimeZone("EST"))
printDefaultTimeZone()

// same SDF

checkTime(sdf.parse("2015-02-20T17:21:17.190EST").getTime())
checkTime(sdf.parse("2015-02-20T17:21:17.190-0500").getTime())

printDefaultTimeZone()

// new SDF
sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz")

checkTime(sdf.parse("2015-02-20T17:21:17.190EST").getTime())
checkTime(sdf.parse("2015-02-20T17:21:17.190-0500").getTime())

void printDefaultTimeZone() {
    println(TimeZone.getDefault().getDisplayName() + ":" +     TimeZone.getDefault().getRawOffset() / 3600 / 1000)
}

void checkTime(long time) {
    println(time + (time == 1424470877190L ? ": CORRECT" : ":"))
}

输出:

Eastern Standard Time (New South Wales):10 1424413277190: 1424470877190: CORRECT Eastern Standard Time:-5 1424413277190: 1424470877190: CORRECT Eastern Standard Time:-5 1424470877190: CORRECT 1424470877190: CORRECT

在上面的输出中,意外/不正确的日期时间是1424413277190 = GMT: Fri, 20 Feb 2015 06:21:17.190 GMT,比解析时间早11EST小时(在本例中是 的Australia/Sydney变体EST),因为夏令时适用于该日期。

所以你可以看到 的解释EST取决于TimeZone构造时的默认值。在前两个转换批次中,默认TimeZoneAustralia/Sydney,它本身缩写为EST,因此 Java 将缩写解释为。直到在默认 TZ 更改后构造新的 SDF 之后,我们才看到按预期应用的缩写。

作为设置默认时区的替代方法,您还可以Calendar在 SDF 上设置一个实例:

sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz")
sdf.setCalendar(Calendar.getInstance(TimeZone.getTimeZone("America/New_York"), new Locale("en_US")))

这将产生EST最初预期的解释效果。

于 2016-06-02T00:27:46.573 回答