Java 使用UTC时区解析ISO8601日期字符串至日期

Java 使用UTC时区解析ISO8601日期字符串至日期,java,javascript,mongodb,date,jodatime,Java,Javascript,Mongodb,Date,Jodatime,我正在尝试从JavaScript应用程序序列化/反序列化日期 服务器端,我用Java,上面安装了JodaTime。我找到了如何使用UTC时区序列化到ISO,但找不到如何执行反向操作 这是我的密码 public static String getIsoDate( Date date ) { SimpleDateFormat dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT ); TimeZone tz

我正在尝试从JavaScript应用程序序列化/反序列化日期

服务器端,我用Java,上面安装了JodaTime。我找到了如何使用UTC时区序列化到ISO,但找不到如何执行反向操作

这是我的密码

public static String getIsoDate( Date date )
{
    SimpleDateFormat  dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT );
    TimeZone tz = TimeZone.getTimeZone("UTC");
    dateToIsoDateString.setTimeZone( tz );
    return dateToIsoDateString.format( date );
}

// this will return a date with GMT timezone
public static Date getDateFromIsoDateString( String iso8601date )
{
    DateTimeFormatter jodaParser = ISODateTimeFormat.dateTimeNoMillis();
    return jodaParser.parseDateTime( iso8601date ).toDate();
}
我不介意使用或不使用Joda,只需要一个快速有效的解决方案,

tl;博士 2015-10-27T23:22:27.605Z

细节 你的问题不清楚也不具体。也许这些小例子会有所帮助。将旧的java.util.Date和.Calendar类与Joda Time混合使用可能会让您感到困惑。Joda Time完全取代了这些类,而不是增加

java.time 现代的java.time类取代了java中遗留的日期时间类以及提供了灵感的Joda时间库

OffsetDateTime
该类表示时间线上的某个时刻,该时刻与UTC的特定偏移量决定了其挂钟时间

在解析/生成字符串时,java.time类默认使用标准格式。因此,无需指定格式化模式

OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;
Instant
要将UTC后7小时的偏移量调整为UTC本身,我们需要在一天的时间上增加7小时,并在需要时滚动日期。
OffsetDateTime
类可以为我们完成这项工作。使用
ZoneOffset.UTC
常量指定UTC

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;
odtUtc.toString():2015-10-27T23:22:27.605Z

如果您在代码中经常使用此UTC值,并且通常应该使用此值,那么您可能会发现使用
Instant
对象更清晰。根据定义,
即时
始终为UTC。我们可以从
OffsetDateTime
中提取一个
即时

Instant instant = odt.toInstant() ;
instant.toString():2015-10-27T23:22:27.605Z

请注意,我们上面的三个对象(
odt
odtUtc
instant
)都表示非常相同的同时时刻,即时间线上的相同点。唯一不同的是他们的挂钟时间

ZoneDateTime
顺便说一句,如果您希望看到某个地区的人们使用的同一时刻被调整为挂钟时间,请通过
ZoneId
指定时区以获取
ZonedDateTime
对象

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString():2015-10-27T19:22:27.605-04:00[美国/蒙特利尔]

在java.time中使用具体类 与上述方法类似,但使用接口。通常,在Java中使用高级接口和超类是一个好主意。但不是在这里。time文档解释说,他们的设计意图是让我们在应用程序中使用更低更具体的类。这些抽象通常只在框架内供内部使用

在这个问题的特定情况下,类
OffsetDateTime
是合适的,而不是
TemporalAccessor


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

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

从哪里获得java.time类

  • 然后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(如果您使用的是Java 7或更早版本,您可以参考以下内容

      如果您使用的是Java 8,则可以执行以下操作:

          DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
          TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");
      
          Date date = Date.from(Instant.from(accessor));
          System.out.println(date);
      
      更新 正如@BasilBourque在评论中指出的,是java框架级接口,不建议在应用程序代码中使用,建议使用具体类而不是接口

      此接口是一个框架级接口,不应在应用程序代码中广泛使用。相反,应用程序应创建并传递具体类型的实例,如LocalDate。这有许多原因,部分原因是此接口的实现可能在ISO以外的日历系统中。请参阅ChronoLocalD我想对这些问题进行更充分的讨论

      有几个具体的类可供使用,如、、等

      DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
      
      OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);
      
      Date date = Date.from(Instant.from(offsetDateTime));
      System.out.println(date);
      

      Java8中的本机解决方案

      Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())
      
      Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())
      

      您的问题可能重复的地方还不清楚。您应该提供输入和所需输出的示例。java.time类不鼓励使用接口/超类。具体的类
      OffsetDateTime
      class在这里是合适的。
      OffsetDateTime.parse(“2015-10-27T16:22:27.605-07:00”)
      @BasilBourque您是对的。文档建议不要在应用程序代码中使用框架级接口。更新了答案。
      ZoneDateTime
      不是这里要使用的合适类。第一个类,使用
      OffsetDateTime.parse
      。第二个类,
      Instant.parse
      。我已经在中发布过但是,根据“ISO-8601日历系统中带有时区的日期时间,如2007-12-03T10:15:30+01:00欧洲/巴黎。”ZonedDateTime也是一个有效的解决方案,我希望,不是吗?我得到的两种方法的输出都是相同的。请注意该引用中的官方时区名称,
      Europe/Paris
      。我们正在讨论的输入字符串缺少该时区,并且只与UTC有一个偏移量。偏移量仅为小时、分钟、秒的数量。一个时区非常重要此外,一个特定地区的人们使用的偏移量的过去、现在和未来变化的历史
      DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
      
          DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
          TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");
      
          Date date = Date.from(Instant.from(accessor));
          System.out.println(date);
      
      DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
      
      OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);
      
      Date date = Date.from(Instant.from(offsetDateTime));
      System.out.println(date);
      
      Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())
      
      Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())