Java 日期和 utcTimeOffset

Java Date and utcTimeOffset

我有一个 Java 日期 (java.util.Date) - 7 月 31 日星期二 00:53:43 CEST 2018 和一个 utcTimeOffset = +0200,表示给,日期是 +2 小时世界标准时间。

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

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

tl;博士

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

对于 Java 8 及更高版本,这些 class 是内置的。对于 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[Europe/Copenhagen]

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/Paris]

调整

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

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 ESTIST 等 3-4 字母缩写,因为它们 不是 真正的时区,不是标准化的,甚至不是唯一的(!)。

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

2018-07-31T00:53:43+02:00[Europe/Copenhagen]

请注意,在那个日期和时间,巴黎和哥本哈根 time zones shared the same offset-from-UTC,因此他们感知的是同一天的时间。

ISO 8601

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

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

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


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

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

从哪里获得java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

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);

这段代码的输出是:

Danish time: 2018-07-30T13:18:47+02:00[Europe/Copenhagen]

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

Java 8 不是一个选项

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

  • 在 Java 8 和更高版本以及新的 Android 设备上(据我所知,来自 API 级别 26)新的 API 是内置的。
  • 在 Java 6 和 7 中获取 ThreeTen Backport,新的 类 的 backport(ThreeTen 用于 JSR 310,其中首次描述了现代 API)。 Link 下面。
  • 在(较旧的)Android 上,使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。确保从包 org.threeten.bp 和子包中导入日期和时间 类。

在向后移植中,类 在带有子包的包 org.threeten.bp 中,例如 org.threeten.bp.ZoneIdorg.threeten.bp.format.DateTimeFormatter

Links