SimpleDateFormat setTimeZone不起作用

时间:2018-03-23 14:29:03

标签: java datetime groovy timezone simpledateformat

我使用以下代码将时间转换为UTC正在运行

import java.text.SimpleDateFormat;
import static java.util.Calendar.* 

def dt = "2018-03-19T06:00:00+01:00"
def format = "yyyy-MM-dd'T'HH:mm:ssX"

TimeZone tz  = TimeZone.getDefault(); //getting up local time zone
TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 
SimpleDateFormat sdf = new SimpleDateFormat(format);      
Date d = sdf.parse(dt);
TimeZone.setDefault(tz);

println d //output: 2018-03-19T05:00:00Z

println d.toTimestamp(); //Output: 2018-03-19 06:00:00.0

但是当我使用TimeZone.setTimeZone(TimeZone.getTimeZone("UTC"));时,它就无效了。

仅适用于TimeZone.setDefault(TimeZone.getTimeZone("UTC"));

为什么会这样?

评论后更新:输出需要在CET中,但在UTC

def dt = "2018-03-19T06:00:00+01:00"
def format = "yyyy-MM-dd'T'HH:mm:ssX"
SimpleDateFormat sdf = new SimpleDateFormat(format);      
sdf.setTimeZone(TimeZone.getTimeZone("CET"))
Date d = sdf.parse(dt);

println d
println d.toTimestamp();

输出:

Mon Mar 19 05:00:00 UTC 2018
2018-03-19 05:00:00.0

1 个答案:

答案 0 :(得分:3)

java.time

    String dt = "2018-03-19T06:00:00+01:00";
    OffsetDateTime dateTime = OffsetDateTime.parse(dt);
    System.out.println(dateTime);

打印

  

2018-03-19T06:00 + 01:00

与过时的Date类相反,来自OffsetDateTime的{​​{1}},现代Java日期和时间API,确实包含UTC偏移,正如名称所示。我没有Groovy的经验,很抱歉要相信你从我的Java代码翻译。

如果您想确保获得特定时区,无论字符串中包含哪个偏移量:

java.time

这次结果是:

  

2018-03-19T06:00 + 01:00 [欧洲/布鲁塞尔]

不要依赖CET等三个字母的时区缩写。 CET是非常多欧洲时区的标准时间半部分(没有夏令时/ DST的部分)的通用名称,通常共享时间,但并非总是如此,并且在历史日期时往往不同意。其他三个字母的缩写是模糊的,因此导致更多的混乱。总是把时区作为地区/城市,就像我在欧洲/布鲁塞尔那样​​。当然,选择符合您所需时区的城市。

如果您认为自己需要 ZoneId zone = ZoneId.of("Europe/Brussels"); ZonedDateTime dateTime = OffsetDateTime.parse(dt).atZoneSameInstant(zone); ,则可能不需要java.sql.Timestamp。如果使用JDBC 4.2或更高版本或类似的现代JPA实现,最好将InstantLocalDateTime存储到数据库中。选择取决于您的确切要求和数据库列的确切数据类型。

    Instant inst = dateTime.toInstant();
    System.out.println(inst);

输出

  

2018-03-19T05:00:00Z

Instant始终以UTC格式打印。如果没有足够新的JDBC驱动程序,您可以通过以下两种方式之一转换为Timestamp

    System.out.println(Timestamp.from(inst));
    System.out.println(Timestamp.valueOf(dateTime.toLocalDateTime()));
  

2018-03-19 06:00:00.0
2018-03-19 06:00:00.0

因为我的时区与日期时间对象中的时区一致,所以我从两次转换中得到相同的结果。在其他时区,结果可能不一样,您需要注意选择正确的结果。

您的代码出了什么问题?

当您使用SimpleDateFormat解析其中包含UTC偏移量的字符串时,它会使用该偏移量来确定时间点。在这种情况下,它不会使用您通过setTimeZone设置的时区。并且它不会将任何时区或偏移放入它返回的Date,因为Date不能包含时区。这只是一个时间点。

令许多人感到困惑的是,Date.toString()的结果似乎包含时区缩写,即输出Mon Mar 19 05:00:00 UTC 2018中的UTC。会发生什么是toString()使用JVM的时区设置来生成字符串。这就是TimeZone.setDefault()影响您获得的输出的原因:它设置JVM设置,影响在同一JVM中运行的所有程序。它不会影响Date对象本身,只会影响其toString()的结果。

TimeZoneDateTimestamp类已过时。 SimpleDateFormat也是同时出了名的麻烦。我建议你根本不要使用这些课程。 java.time可以更好地使用。

链接

Oracle tutorial: Date Time解释如何使用java.time