繁体   English   中英

如何将本地dateTime对象转换为UTC java.util.Date

[英]How to convert a local dateTime Object to a UTC java.util.Date

我很清楚java.util.Date没有时区,为什么会这样。

我有一个应用程序,用户在其中设置了自己的TimeZone,当他在DateTime选择器中选择Date时,该组件将Date对象返回给我。 然后,我需要修改日期以将UTC等效项保存在数据库中。

使用org.joda.time获取代表本地时区的UTC日期的Date对象非常简单:

public static final Date getTimeZoneDependantDate(Date pDateUtc, String pUserTimezoneValue) {
    // Build the DateTime Object
    DateTime originalDate = new DateTime(pDateUtc.getTime(), DateTimeZone.forID(PREF_TIMEZONE_DEF_VALUE));
    // Convert the Date
    DateTime convertedDate  = originalDate.withZone(DateTimeZone.forID(pUserTimezoneValue));
    // Return the localTime associated with the timeZone
    return convertedDate.toLocalDateTime().toDate();
}

但是我坚持如何做相反的事情,将用户选择的日期(从他的时区角度)更改为UTC。 由于LocalDateTime将即时而不是本地Date作为参数。

除了解析String之外,还有什么更干净的方法吗?

tl; dr

您没有提供足够的信息。 报告:

  • 结果如下: myJavaUtilDate.toInstant().toString()
  • 组件的输入
  • 应用程序的当前默认时区

细节

您实际上并未提供有关您的问题的足够信息。 您是否通过GUI组件中的java.util.Date对象在UTC中获取了正确的日期时间值?

如果位于America/Montreal魁北克时区的用户在2016年12月1日输入9 AM,并且您的组件在生成java.util.Date对象时正确地将这些值调整为UTC ,那么您就没有问题。 对于UTC,UTC值为下午2点,因为America/Montreal在该特定日期比UTC落后5个小时。 转换为java.sql.Timestamp对象后,只需将Date对象传递给数据库即可。

仅供参考,旧的日期时间类( DateCalendar等)和Joda-Time现在都被java.time类取代了。 这是java.time中的一些示例代码,显示了您的组件希望采用的行为类型。

LocalDate ld = LocalDate.of ( 2016 , Month.DECEMBER , 1 );
LocalTime lt = LocalTime.of ( 9 , 0 );
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.of ( ld , lt , z );
Instant instant = zdt.toInstant (); // UTC

System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "instant.toString(): " + instant );

zdt.toString():2016-12-01T09:00-05:00 [美国/蒙特利尔]

Instant.toString():2016-12-01T14:00:00Z

字符串末尾的ZZulu缩写,表示UTC。

鉴于java.util.Date::toString在生成字符串时应用当前默认时区的不幸行为,建议您将Date转换为Instant以便清楚地了解其值。

Instant instantConvertedFromDateOfComponent = myJavaUtilDate.toInstant();

如果在此步骤之后您确实确实看到下午2点,那么一切都很好,并且您的组件运行良好。

如果您的组件运行状况不佳,忽略时区问题,并像用户希望将UTC作为自己的时区一样报告用户的输入,那么您将看到2016-12-01T09:00:00Z 那是个问题。 解决方法是自行进行时区调整。 提取“本地”(无区域)值,然后应用预期的时区。

要获取“本地”日期和时间,请首先转换为OffsetDateTime对象。

OffsetDateTime odt = instantConvertedFromDateOfComponent.atOffset( ZoneOffset.UTC );
LocalDateTime ldt = odt.toLocalDateTime();  // 2016-12-01T09:00:00Z
ZonedDateTime zdt = ldt.atZone( z );  // 2016-12-01T09:00-05:00[America/Montreal]

如果您的JDBC驱动程序符合JDBC 4.2或更高版本,则可以直接传递这些java.time类型。 如果不是,则通过添加到旧类中的新方法转换为java.sql类型。 有关堆栈溢出的讨论已经很多次了,所以搜索更多信息。

服务器的当前默认时区应与您的编程无关。 始终在可选参数中明确指定所需/期望的时区,而不是隐式依赖默认值。


关于java.time

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

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

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

在哪里获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置的
    • 标准Java API的一部分,具有捆绑的实现。
    • Java 9添加了一些次要功能和修复。
  • Java SE 6SE 7
    • java.time的许多功能在ThreeTen- Backport中都被反向移植到Java 6和7。
  • 安卓系统

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

通过网络传输和保存日期的最佳方法是以时间戳的形式(以毫秒为单位的日期),该时间戳不需要任何时区信息。 但是,在以时间戳记的形式获取日期之后,请使用它创建日期对象。如果要以UTC格式显示日期,则只需要对其进行转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM