Joda Time用时区解析日期并保留该时区
我想解析一个使用特定时区创建的日期,将其转换为格式并返回。 转换有效但时区偏移始终设置为+0000,并根据需要添加/减去时差。 如何使其格式化并保持偏移正确?
我期待这个:2012-11-30T12:08:56.23 + 07:00
但得到这个:2012-11-30T05:08:56.23 + 00:00
执行:
public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSZZ"; public static String formatDateToISO8601Standard(Date date) { DateTime dateTime = new DateTime(date); DateTimeFormatter df = DateTimeFormat.forPattern(ISO_8601_DATE_FORMAT); return dateTime.toString(df); }
测试类:
private static final String DATE_WITH_TIMEZONE = "30 11 2012 12:08:56.235 +0700"; private static final String EXPECTED_DATE_WITH_TIMEZONE = "2012-11-30T12:08:56.23+07:00"; @Test public void testFormattingDateWithSpecificTimezone() throws Exception { String result = JodaDateUtil.formatDateToISO8601Standard(createDate(DATE_WITH_TIMEZONE)); assertEquals("The date was not converted correctly", EXPECTED_DATE_WITH_TIMEZONE, result); } private Date createDate(String dateToParse) throws ParseException { DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z"); DateTime temp = df.parseDateTime(dateToParse); Date date = temp.toDate(); return date; }
基本上,一旦你解析日期字符串[在你的createDate()方法中]你就失去了原始区域。 Joda-Time允许您使用任何区域格式化日期,但您需要保留原始区域。
在createDate()方法中, DateTimeFormatter “df”可以返回字符串上的区域。 您需要使用withOffsetParsed()方法。 然后,当你有DateTime时 ,调用getZone() 。 如果您将此区域保存在某处或以某种方式将其传递给格式化例程,则可以通过创建DateTimeFormatter“withZone”并在该格式上指定该区域作为所需区域来使用它。
作为演示,这里是一个方法中的一些示例代码。 希望它能帮助您按照希望的方式更改代码。
public static void testDate() { DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z"); DateTime temp = df.withOffsetParsed().parseDateTime("30 11 2012 12:08:56.235 +0700"); DateTimeZone theZone = temp.getZone(); Date date = temp.toDate(); DateTime dateTime = new DateTime(date); DateTimeFormatter df2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSZZ"); DateTimeFormatter df3 = df2.withZone(theZone); System.out.println(dateTime.toString(df2)); System.out.println(dateTime.toString(df3)); }
TL;博士
OffsetDateTime.parse ( "30 11 2012 12:08:56.235 +0700" , DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US ) ).toString()
2012-11-30T12:08:56.235 + 07:00
细节
接受的答案是正确的。 只要转换为java.util.Date
对象,就会丢失时区信息。 由于java.util.Date::toString
在生成String时会混淆地应用当前的默认时区,因此这很复杂。
避免使用像java.util.Date
这样的旧日期时间类。 它们的设计很差,令人困惑,也很麻烦。 现在遗留下来,取而代之的是java.time项目。 现在由java.time类取代的Joda-Time项目也是如此。
java.time
将输入字符串解析为OffsetDateTime
对象,因为它包含从UTC的偏移量但缺少时区。 调用DateTimeFormatter.ofPattern
以指定与输入字符串匹配的自定义格式。 将该formatter对象传递给OffsetDateTime.parse
。
String input = "30 11 2012 12:08:56.235 +0700" ; DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US ); OffsetDateTime odt = OffsetDateTime.parse ( input , f );
odt:toString():2012-11-30T12:08:56.235 + 07:00
要查看UTC中的相同时刻,请提取Instant
。 Instant
类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。
Instant instant = odt.toInstant();
instant.toString():2012-11-30T05:08:56.235Z
您可以应用您想要查看同一时刻的任何时区,即时间轴上的相同点。
ZonedDateTime zdtKolkata = odt.toInstant ().atZone ( ZoneId.of ( "Asia/Kolkata" ) );
zdtKolkata.toString():2012-11-30T10:38:56.235 + 05:30 [亚洲/加尔各答]
根本不需要混合旧的日期时间类。 坚持使用java.time。 如果必须使用尚未更新为java.time类型的旧代码,请查看添加到旧类的新方法以转换为/从java.time。
java.util.Date
的等价物是Instant
,它们都是UTC中1970-01-01T00:00:00Z
的count-since-epoch。 但请注意数据丢失,因为java.time类支持纳秒分辨率,但旧类限制为毫秒。
java.util.Date utilDate = java.util.Date.from( instant );
实时代码
查看IdeOne.com中的实时工作代码 。
关于java.time
java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,例如java.util.Date
, .Calendar
和java.text.SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time。
要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。
从哪里获取java.time类?
- Java SE 8和SE 9及更高版本
- 内置。
- 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和SE 7
- 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
- Android的
- ThreeTenABP项目特别适用于Android的ThreeTen-Backport (如上所述)。
- 请参阅如何使用….
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如Interval
, YearWeek
, YearQuarter
等。
尝试这个。
ISODateTimeFormat.dateTimeParser().parseDateTime(dateString),
然后将其转换为您想要的格式。
使用格式val formatter = DateTimeFormat.forPattern(“yyyy-MM-dd HH:mm:ss.SSSZZ”)