在Java <= 7中,您可以使用ThreeTen Backport,这是 Java 8 新日期/时间类的一个很好的反向端口。
有了这个,您可以轻松处理 DST 更改。
首先,您可以使用org.threeten.bp.DateTimeUtils
to 转换 from 和 to Calendar
。
以下代码将 转换Calendar
为org.threeten.bp.Instant
,这是一个表示“UTC 瞬间”(独立于时区的时间戳:现在,此时,世界上的每个人都在同一瞬间,尽管他们的本地日期和时间可能是不同,取决于他们在哪里)。
然后,将Instant
转换为 a org.threeten.bp.ZonedDateTime
(这意味着:此时,该时区的日期和时间是什么?)。我还使用了org.threeten.bp.ZoneId
获取时区:
Calendar c = Calendar.getInstance();
c.setTime(new Date());
// get the current instant in UTC timestamp
Instant now = DateTimeUtils.toInstant(c);
// convert to some timezone
ZonedDateTime z = now.atZone(ZoneId.of("Europe/Berlin"));
// today is 08/06/2017, so Berlin is in DST (GMT+2)
System.out.println(z); // 2017-06-08T14:11:58.608+02:00[Europe/Berlin]
// testing with a date in January (not in DST, GMT+1)
System.out.println(z.withMonth(1)); // 2017-01-08T14:11:58.608+01:00[Europe/Berlin]
我刚刚选择了一些使用中欧时区 ( Europe/Berlin
) 的时区:您不能使用那些 3 个字母的缩写,因为它们是模棱两可的而不是标准的。您可以将代码更改为最适合您的系统的时区(您可以使用 获取所有可用时区的列表ZoneId.getAvailableZoneIds()
)。
我更喜欢这个解决方案,因为它明确了我们用来向用户显示的时区(Date
并且Calendar
'stoString()
方法在后台使用默认时区,你永远不知道他们在做什么)。
在内部,我们可以继续使用Instant
UTC 格式的 ,因此它不受时区的影响(并且您可以随时在需要时转换和从时区转换) - 如果您想将ZonedDateTime
back 转换为Instant
,只需使用该toInstant()
方法。
实际上,如果您想获取当前日期/时间,只需忘记旧类(Date
和Calendar
)并使用Instant
:
// get the current instant in UTC timestamp
Instant now = Instant.now();
但是,如果您仍然需要使用旧类,只需使用DateTimeUtils
来进行转换。
上述示例的输出是该ZonedDateTime.toString()
方法的结果。如果要更改格式,请使用org.threeten.bp.format.DateTimeFormatter
该类(有关所有可能格式的更多详细信息,请查看javadoc ):
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss z X");
// DST (GMT+02)
System.out.println(formatter.format(z)); // 08/06/2017 14:11:58 CEST +02
// not DST (GMT+01)
System.out.println(formatter.format(z.withMonth(1))); // 08/01/2017 14:11:58 CET +01