【问题标题】:Java Date and utcTimeOffset [closed]Java 日期和 utcTimeOffset [关闭]
【发布时间】:2019-01-27 17:03:22
【问题描述】:

我有一个 Java 日期 (java.util.Date) - 2018 年 7 月 31 日星期二 00:53:43 CEST 和一个 utcTimeOffset = +0200,表示给定日期距 UTC +2 小时。

这是一个遗留代码,Java 8 不是一个选项。我得到的是来自第三方 API 的日期文本表示为 20180730131847 和 utcTimeOffset = +0200

我想将其转换为丹麦时间。有人可以帮我怎么做吗。

【问题讨论】:

  • 我建议先搜索这个网站(和其他网站),然后尝试一下。
  • 使用 Java 8 中的 ZonedDateTime。它让一切变得更容易。
  • CEST,中欧是一小时偏移,加上白天节省 = 2 小时。
  • @GuillaumeF。 ZonedDateTime 是正确使用的好类,这是正确的。您不需要 Java 8。java.time,包括 ZonedDateTime 的现代 Java 日期和时间 API,已在 the ThreeTen Backport library 中向后移植到 Java 6 和 7。按照链接,将库添加到您的项目并开始编码。
  • @SarangaJayatilake 感谢您在回复 cmets 时提供的额外信息。最好在问题本身中添加补充信息,以将所有信息保存在一个位置。这次我给你加了。

标签: java timezone datetime-conversion date


【解决方案1】:

tl;博士

您的输入格式很差,但在这种情况下可以使用现代的 java.time 类进行解析。请注意,不幸地使用 3-4 个字母的伪区域(例如 CEST)不是标准化的并且不是唯一的,因此它们不能总是被解析为您的预期区域。

对于 Java 8 及更高版本,这些类是内置的。对于 Java 6 和 7,请参阅下面详细介绍的 ThreeTen-Backport 项目。

ZonedDateTime.parse(    // Parse an input string as a date-time moment.
    "Tue Jul 31 00:53:43 CEST 2018" ,
    DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu", Locale.US )                 // Specify `Locale` to determine human language and cultural norms to be used in translation.
)                       // Returns a `ZonedDateTime` object.
.withZoneSameInstant(   // Adjust from one zone to another.
    ZoneId.of( "Europe/Copenhagen" )  // Always use `Continent/Region` time zone names, never 3-4 letter pseudo-codes such as `CEST`.
)
.toString()             // Generate a `String` with text in standard ISO 8601 format wisely extended by appending the name of the time zone in square brackets.

2018-07-31T00:53:43+02:00[欧洲/哥本哈根]

java.time

这已经讨论过很多次了,所以搜索 Stack Overflow 以获取更多讨论。

解析

String input = "Tue Jul 31 00:53:43 CEST 2018";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE MMM d HH:mm:ss zzz uuuu", Locale.US );
ZonedDateTime zdt = ZonedDateTime.parse( input , f  );

zdt.toString(): 2018-07-31T00:53:43+02:00[欧洲/巴黎]

调整

调整为丹麦时区。我会随意选择Europe/CopenhagenDenmark 可能有其他区域,例如格陵兰或王国其他地区。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "Europe/Copenhagen" ) ;
ZonedDateTime zdtCopenhagen = zdt.withZoneSameInstant( z );  // Same moment, different wall-clock time.

2018-07-31T00:53:43+02:00[欧洲/哥本哈根]

请注意,在那个日期和时间,巴黎和哥本哈根time zones 共享相同的offset-from-UTC,因此它们感知到相同的时间。

ISO 8601

您的输入字符串使用了 可怕的 格式。它难以解析,假定为英语,并且包含冗余信息。

将日期时间值作为文本交换时,仅使用标准的ISO 8601 格式。

请注意,ZonedDateTime 类明智地扩展了该格式,将时区名称附加在方括号中。这可以在上面的输出中看到。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案2】:

    java.time,现代 Java 日期和时间 API

        ZoneId danishTime = ZoneId.of("Europe/Copenhagen");
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss");
        DateTimeFormatter offsetFormatter = DateTimeFormatter.ofPattern("XX");
    
        String dateTimeString = "20180730131847";
        String offsetString = "+0200";
        ZoneOffset offset = ZoneOffset.from(offsetFormatter.parse(offsetString));
        ZonedDateTime dateTime = LocalDateTime.parse(dateTimeString, dateTimeFormatter)
                .atOffset(offset)
                .atZoneSameInstant(danishTime);
        System.out.println("Danish time: " + dateTime);
    

    这段代码的输出是:

    丹麦时间:2018-07-30T13:18:47+02:00[欧洲/哥本哈根]

    丹麦使用的时区是欧洲/哥本哈根。虽然法罗群岛和格陵兰岛使用其他时区,并且与丹麦在同一个女王下属于一个国家社区(“rigsfællesskab”),但它们不是丹麦本土的一部分,因此在询问丹麦时间时可以忽略。由于丹麦夏季时间与您的示例偏移量 +0200 一致,因此在这种情况下,我们得到的时间与我们输入的时间相同。例如,如果日期在冬季,情况就不会如此,因为丹麦标准时间是偏移量+0100。

    Java 8 不是一个选项

    没什么大问题。 java.time 已被向后移植。

    • 在 Java 8 及更高版本以及新的 Android 设备上(据我所知,从 API 级别 26 开始)新的 API 是内置的。
    • 在 Java 6 和 7 中,获得 ThreeTen Backport,即新类的后向端口(对于 JSR 310 的 ThreeTen,首次描述了现代 API)。链接如下。
    • 在(较旧的)Android 上,使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。确保从包 org.threeten.bp 和子包中导入日期和时间类。

    在 backport 中,类位于包 org.threeten.bp 中,带有子包,例如 org.threeten.bp.ZoneIdorg.threeten.bp.format.DateTimeFormatter

    链接

    【讨论】:

    • V.V,感谢您重组我的更新。感谢大家的cmets。
    猜你喜欢
    • 2018-08-24
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多