java - 以原始时区打印日期

标签 java android date simpledateformat timestamp-with-timezone

假设我的设备在澳大利亚(GMT + 10:00)。

我有一个从API收到的日期“ 2016-04-22T17:45:00 + 02:00”。

我想在原始时区(GMT + 02:00)很好地显示它。

因此,我将SimpleDateFormat与“ yyyy-MM-dd'T'HH:mm:ssZZZZZ”一起使用。

String date = "2016-04-22T17:45:00+02:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ");
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(date));


但是不幸的是,我找不到一种显示日期的干净方法:

sdf.format(cal.getTime());


使用设备时区。

因此,我“手动”解析了日期以提取时区以将其设置在日历中。

cal.setTimeZone(TimeZone.getTimeZone("GMT" + date.substring(date.length() - 6, date.length())));


但这似乎并不能解决问题。

我怎样才能做到这一点?

最佳答案

时区=偏移量+规则


  在原始时区(GMT + 02:00)。


不,不正确。文本GMT+02:00表示offset-from-UTC,而不是时区。时区是一个偏移量,外加一组用于处理异常的规则,例如夏令时(DST)。

时区以continent/region格式命名,例如America/MontrealAsia/Kolkata。始终使用these proper names。永远不要在主流媒体中看到3-4个缩写;这些既不是标准化的也不是唯一的。

实际上,UTC是新的GMT

避免使用旧的日期时间类

事实证明,与最早的Java版本捆绑在一起的旧的日期时间类设计不佳,令人困惑且麻烦。避免他们。这些类被非常成功的Joda-Time库及其后继的java.time框架所取代。

java.time框架内置在Java 8 and later中。它的大部分功能在ThreeTen-Backport项目中都已移植回Java 6和7,并在ThreeTenABP中进一步适用于Android。

Oracle Tutorial中了解更多信息。

OffsetDateTime

输入字符串仅具有与UTC的偏移量,没有完整的time zone。因此,我们使用OffsetDateTime类表示此类值。

幸运的是,您输入的字符串为标准ISO 8601格式。解析/生成日期时间值的文本表示时,java.time类默认使用ISO 8601格式。因此,我们可以直接解析而无需费心定义格式设置模式。

String input = "2016-04-22T17:45:00+02:00";
OffsetDateTime odt = OffsetDateTime.parse( input );


调用OffsetDateTime::toString()以生成相同格式的字符串。

String output = odt.toString(); // ISO 8601 formatted string.


Instant

程序员不应该考虑这种本地日期时间。通常,您应该在UTC中进行业务逻辑,数据库存储和数据交换。

在java.time中,Instant表示UTC时间轴上的时刻,分辨率为nanoseconds。我们可以从Instant中提取一个OffsetDateTime

Instant instant = odt.toInstant();


ZonedDateTime

由于使用了诸如夏令时之类的异常处理规则,使用时区总是比仅使用偏移更好。

通过应用Instant获取OffsetDateTime,您可以轻松地将ZoneIdZonedDateTime调整到时区。有关更多讨论,请参见my longer answerdiagram有关在这些类之间进行转换/调整的一般主题。

ZoneId zoneId_Montreal = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId_Montreal );


…要么…

ZonedDateTime zdt_Montreal = odt.atZoneSameInstant( zoneId_Montreal );


请注意,在应用时区时,您可能会看到一天中的时间甚至日期发生变化。可能需要根据该区域的规则进行调整,以适应Daylight Saving Time (DST)或其他问题。

您可以进一步调整到其他时区。你提到澳大利亚。该国家/地区有很多时区,因此您必须选择适合您(或您的用户)的时区,因为它们现在或过去或将来可能有不同的规则。

ZoneId zoneId_Melbourne = ZoneId.of( "Australia/Melbourne" );
ZonedDateTime zdt_Melbourne = zdt_Montreal.withZoneSameInstant( zoneId_Melbourne );


您将在调用ZonedDateTime::toString时注意到,该方法通过将时区的名称附加在方括号中来扩展标准ISO 8601格式。

要生成其他格式的字符串,请在Stack Overflow中搜索java.time.formatDateTimeFormatter主题。 ofLocalized…方法与Locale一起可以自动本地化格式,包括翻译人类语言的日期/月份名称,以及遵循文化规范的元素顺序,句点与逗号等。



关于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 driver或更高版本兼容的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?


Java SE 8Java SE 9和更高版本


内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。

Java SE 6Java SE 7


ThreeTen-Backport中的大部分java.time功能都已反向移植到Java 6和7。

Android


更高版本的Android捆绑了java.time类的实现。
对于早期的Android,ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参见How to use ThreeTenABP…



ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

关于java - 以原始时区打印日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36736174/

相关文章:

Android map 路线叠加示例

objective-c - Objective C 中几个月的锻炼差异

mysql - 没有时间戳的 HQL 中的日期比较

java - 在 facebook 墙上发布 sdk 3.5 android 错误

java - transient 如何在序列化 Java 中与 final 一起工作

java - 自定义小部件的 Android 解析样式不起作用

javascript - 使用 d3.js 进行日期排序

java - 将 ZipEntry 写入文件的最易读方式?

java - Java 中的 REST POST 方法

Android Bootstrap 到底是什么,它有什么作用?