如何在日期解析(Java)中忽略时区标识符?

san*_*ith 2 java datetime date

我正在尝试解析这样的日期:

DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");
Run Code Online (Sandbox Code Playgroud)

而且我的价值是5小时,因为我住的是UTC + 3时区.但是我需要具有2am的值,但是,使用相同的格式字符串(以指定格式给出的日期字符串,我不允许更改).这该怎么做?

更新:我不需要在适当的时区格式化日期,我需要通过没有时区的值来比较这些日期.我想要确切地说该日期已经解析了忽略原始字符串中的时区 - 并且总是在相同的时区(例如我的)中,无论包含原始字符串:UTC或UTC + 3或其他什么.

Bas*_*que 7

接受的答案是工作太辛苦.操纵偏移量是日期时间库的范畴.自己做这样的工作是浪费你的时间,并可能成为错误的来源.

旧的java.util.Date/.Calendar类非常麻烦.避免他们.而是使用java.time或Joda-Time.

java.time

Java 8及更高版本内置了一个新的java.time框架.

困惑的问题

你的问题很困惑.你说你想忽略时区,但是你接受了一个确实解析并处理时区的答案.然后,该答案通过偏移调整结果.所以,看来你不是要忽略的时区.

实际上,忽略时区很少有意义.也许你想比较柏林和底特律的一对工厂,看看他们是否同时休息.在这种情况下,您要比较各自的挂钟时间.该java.time框架提供的"本地"类用于此目的:LocalDate,LocalTime,和LocalDateTime.但根据我的经验,这在大多数业务场景中很少需要.这些对象与时间轴无关.

如此看来,你想要的是能够跨越不同的时区比较日期时间值.java.time类隐式地执行此操作.ZonedDateTime与各种分配的时间区的对象可以与具有彼此isBefore,isAfterisEqual方法.

示例代码

首先我们解析输入字符串.

z模式代码意味着预期和分析的时区.如果未指定其他特定时区,则还将为结果日期时间对象分配此对象.

我们还为一个Locale对象提供了一个人类语言组件,该组件与我们希望在输入字符串中看到的文本相匹配.在这种情况下,我们需要任何带英语的Locale.

String input = "Oct 04, 2015 2:11:58,757 AM UTC";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MMM dd, yyyy K:mm:ss,SSS a z" ).withLocale( Locale.ENGLISH );

ZonedDateTime then = ZonedDateTime.parse( input, formatter );
Run Code Online (Sandbox Code Playgroud)

接下来我们获取魁北克省的当前时间.这个任意选择的时区将进一步证明我们可以将这个ZonedDateTime对象与另一个具有不同时区的对象进行比较.具体来说,与分配给我们then上面的对象的UTC时区进行比较.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now( zoneId );
Run Code Online (Sandbox Code Playgroud)

做比较.

Boolean isThenBeforeNow = then.isBefore( now );
Run Code Online (Sandbox Code Playgroud)

顺便说一下,一般来说,日期时间工作的最佳实践是将所有日期时间值转换为UTC时区,以进行业务逻辑,存储和数据交换.仅在需要时调整到时区以满足用户对屏幕或报告的期望.

ZonedDateTime nowUtc = now.withZoneSameInstant( ZoneOffset.UTC );
Run Code Online (Sandbox Code Playgroud)

转储到控制台.

System.out.println( "input: " + input );
System.out.println( "then: " + then );
System.out.println( "now: " + now );
System.out.println( "isThenBeforeNow: " + isThenBeforeNow );
System.out.println( "nowUtc: " + nowUtc );
Run Code Online (Sandbox Code Playgroud)

跑步时

输入:2015年10月4日上午2:11:58,757 UTC

然后:2015-10-04T02:11:58.757Z [UTC]

现在:2015-10-19T19:28:04.619-04:00 [美国/蒙特利尔]

isThenBeforeNow:是的

nowUtc:2015-10-19T23:28:04.619Z


关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

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

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.


san*_*ith 2

更新2:已解决

好吧,现在我得到了我想要的:

DateFormat df = new SimpleDateFormat("MMM dd, yyyy K:mm:ss,SSS a z", Locale.ENGLISH);
Date date = df.parse("Oct 04, 2015 2:11:58,757 AM UTC");
long diff = TimeZone.getDefault().getRawOffset() - df.getTimeZone().getRawOffset();
date = new Date(date.getTime()-diff);
Run Code Online (Sandbox Code Playgroud)

不管怎样,谢谢大家

  • 这个新解决方案有什么作用? (2认同)