我对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方法进行比较,则效果很好。
有人可以在这方面给我一些启发,并请我通过我的错误来指导我。
谢谢。
答案 0 :(得分:1)
您的compareTo
编码让人分心。您的例外是将字符串输入解析为对象。
另一个问题:您在第二和第三输入上使用了错误的类。
另一个问题:调用now()
时,您隐式依赖JVM的当前默认时区。糟糕的做法是,与许多程序员一样,任何程序员阅读的知识都不会知道您是否打算使用默认值,或者您是否不知道该问题。此外,当前默认值可以在运行时随时通过JVM中任何应用程序的任何线程中的任何代码进行更改。因此最好始终明确指定您想要的/期望的区域或偏移量。
OffsetDateTime.now(
ZoneOffset.UTC
)
或者更好的是,使用ZonedDateTime
比OffsetDateTime
捕获更多信息。
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-UTC或time 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/Montreal
,Africa/Casablanca
或Pacific/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 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。