SimpleDateFormat - 时区不正确
SimpleDateFormat - Timezone not correct
我在解析 Java 中的时间戳时遇到问题。
我希望两个时间戳都在同一时区 (CET)。
SimpleDateFormat sdaf = new SimpleDateFormat ("dd.MM.yyyy HH:mm:ss");
String str = "30.03.2013 06:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
str = "31.03.2013 05:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
但事实并非如此 - 查看输出。
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 05:00:00 CEST 2013
编辑:
如果我将 CET 更改为 GMT+1,我会得到这个。
03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 06:00:00 CEST 2013
似乎是正确的。但为什么 CET 不起作用?
UTC+1 产生
30.03.2013 06:00:00 = Sat Mar 30 07:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 07:00:00 CEST 2013
与 GMT+1 有何不同 - ???
您无法获得 31.03.2013 05:00:00 的 CET
时区,因为它已不在该时区。要理解,只需检查两个时区的名称
- CET:欧洲中部时间(
UTC+1
或 GMT+1
)
- CEST:欧洲中部夏令时(
UTC+2
或 GMT+2
)
那是 2013 年 3 月 31 日 02:00:00 发生的夏令时。所以你无法获得第二个日期的 CET
时区,因为它是在夏季 "time zone"。
如果你解析 31.03.2013 02:00:00
你会得到
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
因为那天02:00:00,正值夏令时,变成了03:00:00。
您可以使用 TimeZone.inDaylightTime(Date)
检查
String str = "30.03.2013 06:00:00";
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
SDT : false
str = "31.03.2013 02:00:00";
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
SDT : true
由于 CET
与 UTC+1
或 GMT+1
相同并且 CEST
变为 UTC+2
或 GMT+2
,当您强制日期在 GMT+1
上,您得到 CET
的等价物,但不考虑 SDT 参数。
注意:这是 LocalDateTime
不用 TimeZone
进行大部分处理的原因之一。
可以用Java8,比这个更清晰简单。
DateTimeFormatter parse = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm:ss.XXX");
LocalDate localDate = LocalDate.of(2013,3,30);
LocalTime localTime = LocalTime.of(6,0);
LocalDateTime dateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("CET"));
System.out.println(zonedDateTime.format(parse));
输出:30.03.2013 06:00:00.+01:00
是正确的。因此,我认为您真的不需要中欧(标准)时间作为 3 月 31 日的约会时间。
我想再说三点:
- 切勿依赖任何三字母或四字母的时区缩写,例如 CET。
- 如果您真的想要中欧时间,是可能的,因为阿尔及利亚和突尼西亚这两个非洲国家全年都使用 CET。
- 避免使用过时的
SimpleDateFormat
、TimeZone
和 Date
,而是使用 java.time
、现代的 Java 日期和时间 API .
所以我的代码建议是:
ZoneId cetAllYear = ZoneId.of("Africa/Algiers");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss");
DateTimeFormatter demoFormatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);
String str = "31.03.2013 05:00:00";
ZonedDateTime dateTime = LocalDateTime.parse(str, formatter).atZone(cetAllYear);
System.out.println (str + " = " + dateTime
+ " = " + dateTime.format(demoFormatter));
输出:
31.03.2013 05:00:00 = 2013-03-31T05:00+01:00[Africa/Algiers] = Sun Mar 31 05:00:00 CET 2013
Africa/Tunis 时区也是如此。
避免使用三个字母的时区缩写。中欧时间是标准时间的通用名称,偏移量为 +01:00,一年中有 5 个月用于大量时间欧洲时区。所以在某种程度上它只是半个时区,在另一种方式下它有很多,而且你不知道你得到的是哪个。当你给出一个属于夏令时(一年中的 DST 时间)的日期时间时更是如此。很多三字母和四字母的缩写是不明确的。而是给出时区,例如 Europe/Rome 或 Africa/Tunis,如 region/city.
避免使用 SimpleDateFormat
及其过时的朋友。 class 是出了名的麻烦。 java.time
更好用。
链接
- Oracle tutorial: Date Time 解释如何使用
java.time
.
- Central European Time on timeanddate.com.
我在解析 Java 中的时间戳时遇到问题。
我希望两个时间戳都在同一时区 (CET)。
SimpleDateFormat sdaf = new SimpleDateFormat ("dd.MM.yyyy HH:mm:ss");
String str = "30.03.2013 06:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
str = "31.03.2013 05:00:00";
sdaf.setTimeZone (TimeZone.getTimeZone ("CET"));
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
但事实并非如此 - 查看输出。
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 05:00:00 CEST 2013
编辑:
如果我将 CET 更改为 GMT+1,我会得到这个。
03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 06:00:00 CEST 2013
似乎是正确的。但为什么 CET 不起作用?
UTC+1 产生
30.03.2013 06:00:00 = Sat Mar 30 07:00:00 CET 2013
31.03.2013 05:00:00 = Sun Mar 31 07:00:00 CEST 2013
与 GMT+1 有何不同 - ???
您无法获得 31.03.2013 05:00:00 的 CET
时区,因为它已不在该时区。要理解,只需检查两个时区的名称
- CET:欧洲中部时间(
UTC+1
或GMT+1
) - CEST:欧洲中部夏令时(
UTC+2
或GMT+2
)
那是 2013 年 3 月 31 日 02:00:00 发生的夏令时。所以你无法获得第二个日期的 CET
时区,因为它是在夏季 "time zone"。
如果你解析 31.03.2013 02:00:00
你会得到
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
因为那天02:00:00,正值夏令时,变成了03:00:00。
您可以使用 TimeZone.inDaylightTime(Date)
String str = "30.03.2013 06:00:00";
java.util.Date dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
30.03.2013 06:00:00 = Sat Mar 30 06:00:00 CET 2013
SDT : false
str = "31.03.2013 02:00:00";
dat = sdaf.parse (str);
System.out.println (str + " = " + dat);
System.out.println("SDT : " + TimeZone.getTimeZone("CET").inDaylightTime(dat));
31.03.2013 02:00:00 = Sun Mar 31 03:00:00 CEST 2013
SDT : true
由于 CET
与 UTC+1
或 GMT+1
相同并且 CEST
变为 UTC+2
或 GMT+2
,当您强制日期在 GMT+1
上,您得到 CET
的等价物,但不考虑 SDT 参数。
注意:这是 LocalDateTime
不用 TimeZone
进行大部分处理的原因之一。
可以用Java8,比这个更清晰简单。
DateTimeFormatter parse = DateTimeFormatter.ofPattern("dd.MM.yyyy hh:mm:ss.XXX");
LocalDate localDate = LocalDate.of(2013,3,30);
LocalTime localTime = LocalTime.of(6,0);
LocalDateTime dateTime = LocalDateTime.of(localDate, localTime);
ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("CET"));
System.out.println(zonedDateTime.format(parse));
输出:30.03.2013 06:00:00.+01:00
我想再说三点:
- 切勿依赖任何三字母或四字母的时区缩写,例如 CET。
- 如果您真的想要中欧时间,是可能的,因为阿尔及利亚和突尼西亚这两个非洲国家全年都使用 CET。
- 避免使用过时的
SimpleDateFormat
、TimeZone
和Date
,而是使用java.time
、现代的 Java 日期和时间 API .
所以我的代码建议是:
ZoneId cetAllYear = ZoneId.of("Africa/Algiers");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss");
DateTimeFormatter demoFormatter
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);
String str = "31.03.2013 05:00:00";
ZonedDateTime dateTime = LocalDateTime.parse(str, formatter).atZone(cetAllYear);
System.out.println (str + " = " + dateTime
+ " = " + dateTime.format(demoFormatter));
输出:
31.03.2013 05:00:00 = 2013-03-31T05:00+01:00[Africa/Algiers] = Sun Mar 31 05:00:00 CET 2013
Africa/Tunis 时区也是如此。
避免使用三个字母的时区缩写。中欧时间是标准时间的通用名称,偏移量为 +01:00,一年中有 5 个月用于大量时间欧洲时区。所以在某种程度上它只是半个时区,在另一种方式下它有很多,而且你不知道你得到的是哪个。当你给出一个属于夏令时(一年中的 DST 时间)的日期时间时更是如此。很多三字母和四字母的缩写是不明确的。而是给出时区,例如 Europe/Rome 或 Africa/Tunis,如 region/city.
避免使用 SimpleDateFormat
及其过时的朋友。 class 是出了名的麻烦。 java.time
更好用。
链接
- Oracle tutorial: Date Time 解释如何使用
java.time
. - Central European Time on timeanddate.com.