Java中OffsetDateTime.now()的OffsetDateTime字符串比较

时间:2019-02-20 16:19:43

标签: java date datetime java-time compareto

我对OffsetDateTime的用法非常陌生,我正在尝试以这种方式将OffsetDateTime字符串与OffsetDateTime.now()在Java中进行比较,

import java.time.OffsetDateTime;

public class OffsetDateTimeDemo {
   public static void main(String[] args) {

      OffsetDateTime one = OffsetDateTime.parse("2017-02-03T12:30:30+01:00");
      System.out.println("First ::" + OffsetDateTime.now().compareTo(one));

      OffsetDateTime date1 = OffsetDateTime.parse("2019-02-14T00:00:00");
      System.out.println("Second ::" +  OffsetDateTime.now().compareTo(date1));

      OffsetDateTime date3 = OffsetDateTime.parse("Mon Jun 18 00:00:00 IST 2012");
      System.out.println(" Third :: " +OffsetDateTime.now().compareTo(date3));


   }
}   

但是在所有3种情况下,我都遇到了java.time.format.DateTimeParseException。

但是,如果我将2个OffsetDateTime字符串与CompareTo方法进行比较,则效果很好。

有人可以在这方面给我一些启发,并请我通过我的错误来指导我。

谢谢。

1 个答案:

答案 0 :(得分:1)

您的compareTo编码让人分心。您的例外是将字符串输入解析为对象。

另一个问题:您在第二和第三输入上使用了错误的类。

另一个问题:调用now()时,您隐式依赖JVM的当前默认时区。糟糕的做法是,与许多程序员一样,任何程序员阅读的知识都不会知道您是否打算使用默认值,或者您是否不知道该问题。此外,当前默认值可以在运行时随时通过JVM中任何应用程序的任何线程中的任何代码进行更改。因此最好始终明确指定您想要的/期望的区域或偏移量。

OffsetDateTime.now( 
    ZoneOffset.UTC
)

或者更好的是,使用ZonedDateTimeOffsetDateTime捕获更多信息。

ZonedDateTime.now(
    ZoneId.of( "Pacific/Auckland" )
)

首先:OffsetDateTime有效

您输入的第一个字符串正确,并且解析成功。

OffsetDateTime.parse( "2017-02-03T12:30:30+01:00" )

完整行代码:

OffsetDateTime odt = OffsetDateTime.parse( "2017-02-03T12:30:30+01:00" ) ;

请参阅此code run live at IdeOne.com

  

odt.toString():2017-02-03T12:30:30 + 01:00

要进行比较,请提取Instant。这样做可以有效地将您的力矩从某个偏移量调整为零偏移量,即UTC本身。根据定义,Instant始终采用UTC。

Instant instant = Instant.now() ;                          // Capture the current moment as seen in UTC.
boolean odtIsPast = odt.toInstant().isBefore( instant ) ;

第二:LocalDateTime

您的第二个字符串输入缺少任何offset-from-UTCtime zone的指示符。因此,OffsetDateTime是使用错误的类。而是使用LocalDateTime,它缺少偏移量或区域的任何概念。

这意味着LocalDateTime 不能代表一个时刻。例如,今年1月23日中午可能意味着Asia/Tokyo的中午,这比Europe/Paris中的中午要早几个小时,或者可能意味着America/Montreal的中午将是一会儿再过几个小时。没有区域或偏移量的上下文,LocalDateTime并没有真正的意义。因此,LocalDateTime与当前时刻进行比较是毫无意义的

LocalDateTime.parse( "2019-02-14T00:00:00" )

请参阅此code run live at IdeOne.com

  

ldt.toString():2019-02-14T00:00

要进行比较,您不能-如上所述不合逻辑。您必须分配时区(或偏移量)才能确定时间轴上的时刻。如果您确定某天该日期和时间是针对特定时区的,请分配ZoneId以获得ZonedDateTime。然后提取Instant进行比较。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;                   // India time.
ZonedDateTime zdt = ldt.atZone( z ) ;
Instant instant = Instant.now() ;                          // Capture the current moment as seen in UTC.
boolean zdtIsPast = zdt.toInstant().isBefore( instant ) ;  // Compare.

顺便说一句,我注意到一天中的时间为零。如果您的目标是仅表示日期,没有任何时间,也没有任何区域,请使用LocalDate类。

第三:不要打扰,模棱两可的输入

您的第三个字符串输入带有时区指示符。因此,应将其解析为ZonedDateTime

很遗憾,您选择了 糟糕字符串格式进行解析。切勿使用IST之类的2-4个字符的伪区域。它们不是标准化的。而且它们不是唯一的!您的IST可能表示爱尔兰标准时间印度标准时间或其他。

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

请参阅此code run live at IdeOne.com

  

zdt.toString():2019-02-20T22:34:26.833 + 01:00 [非洲/突尼斯]

您可以尝试进行解析。 ZonedDateTime会猜测IST指的是哪个区域。但这只是一个猜测,鉴于固有的模棱两可的输入,因此也不可靠。就我个人而言,我会拒绝对此进行编码,拒绝此输入数据返回其源。

如果您坚持要进行这种不可靠的解析尝试,请参见the correct Answer至您最近询问的similar Question

教育您的资料来源:始终使用标准ISO 8601格式将日期时间值交换为人类可读的文本。

java.time 类在解析/生成字符串时默认使用这些ISO 8601格式。 ZonedDateTime类明智地扩展了标准,以将时区的标准名称附加在方括号中。


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

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

在哪里获取java.time类?

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