我很清楚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采用即时而非本地日期作为参数。
有没有比解析String更简洁的方法?
答案 0 :(得分:1)
您没有提供足够的信息。报告:
myJavaUtilDate.toInstant().toString()
您没有真正提供有关您的问题的足够信息。您是否通过GUI组件中的java.util.Date
对象获得了正确的UTC日期时间值?
如果魁北克时区America/Montreal
的用户在2016年12月1日上午9点进入,并且您的组件在生成java.util.Date
对象时正确地将这些值调整为UTC,那么你没问题。对于UTC,UTC值将在下午2点,因为America/Montreal
在该特定日期落后于UTC 5小时。转换为Date
对象后,只需将java.sql.Timestamp
对象传递给数据库。
仅供参考,旧的日期时间类(Date
& Calendar
等)和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
字符串末尾的Z
是Zulu
的缩写,表示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类型。已经多次讨论Stack Overflow,所以请搜索更多信息。
服务器的当前默认时区应与您的编程无关。始终在可选参数中明确指定所需/预期的时区,而不是隐式依赖于默认值。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:0)
通过网络传输和保存日期的最佳方式是以时间戳(以毫秒为单位)的形式,此时间戳不需要任何时区信息。但是在以时间戳的形式获取日期后,使用它创建日期对象,如果要以UTC格式显示日期,则只需要转换它。