是的,您应该在Java 8中使用Joda-Time或新的java.time包(受Joda-Time启发)。
偏移量是表示某个日期时间值的距离UTC(GMT)的小时-分钟-秒数。 西海岸为-08:00(忽略 夏令时的荒谬性),意味着比UTC早8个小时。
请注意,java.time在其初始版本中存在一个小错误,无法处理仅具有小时的偏移(例如+08
)而没有分钟(例如+08:00
)。
时区是特定地区人民使用的偏移量过去、现在和未来变化的历史。
使用适当的时区名称(大多数为洲/城市)。避免使用三个或四个字母的代码,例如EST,这些代码既不标准化也不唯一。
java.util.Date
没有时区,而Joda-Time DateTime
有时区。
要获取Web浏览器的时区,请参见此问题。但通常,这并不起作用。正如您可能已经看到的那样,许多网站要求用户选择时区。
您确切的用例很令人困惑。一般来说,最好的方法是将日期时间值用于UTC,然后根据需要调整为用户的本地时间。通常最好将软件的日期时间作为UTC工作和存储。然后呈现本地日期时间以适应用户。换句话说,全球思考(UTC),本地呈现(本地时区调整)。
通常系统管理员将服务器计算机设置为UTC(没有时区偏移)。如果你的操作系统(如Mac OS X)没有提供UTC,则使用Reykjavik,因为冰岛全年都使用UTC,没有任何夏令时。同样,数据库引擎几乎总是将日期时间值转换为UTC进行存储。
Joda-Time确实提供了LocalDate类,用于当您真正不关心时区或时间时。但通常最好使用日期时间(DateTime实例),并根据需要格式化为仅日期字符串。
Joda-Time 2.3中的示例代码。
DateTimeZone timeZoneChina = DateTimeZone.forID( "Asia/Shanghai" );
DateTime dateTimeChina = new DateTime( 2013, 8, 29, 17, 45, 00, timeZoneChina );
DateTime dateTimeUtc = dateTimeChina.withZone( DateTimeZone.UTC );
DateTime dateTimeParis = dateTimeChina.withZone( DateTimeZone.forID( "Europe/Paris" ) );
DateTimeZone timeZoneUsWestCoast = DateTimeZone.forID( "America/Los_Angeles" );
DateTime dateTimeUnitedStatesWestCoast = dateTimeChina.withZone( timeZoneUsWestCoast );
DateTimeFormatter formatter = ISODateTimeFormat.date();
String outputDateOnlyForUnitedStatesWestCoast = formatter.withZone( timeZoneUsWestCoast ).print( dateTimeUtc );
输出到控制台...
System.out.println( "dateTimeChina: " + dateTimeChina );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUnitedStatesWestCoast: " + dateTimeUnitedStatesWestCoast );
System.out.println( "outputDateOnlyForUnitedStatesWestCoast: " + outputDateOnlyForUnitedStatesWestCoast );
当运行时...
dateTimeChina: 2013-08-29T17:45:00.000+08:00
dateTimeUtc: 2013-08-29T09:45:00.000Z
dateTimeParis: 2013-08-29T11:45:00.000+02:00
dateTimeUnitedStatesWestCoast: 2013-08-29T02:45:00.000-07:00
outputDateOnlyForUnitedStatesWestCoast: 2013-08-29
java.time
在java.time中类似的代码。
当前的UTC时间。
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
将时间调整到芝加哥地区的时区,生成一个ZonedDateTime
对象。
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = instant.atZone( z ) ;
调整为中国时区。
ZoneId zShanghai = ZoneId.of( "Asia/Shanghai" ) ;
ZonedDateTime zdtShanghai = zdtChicago.withZoneSameInstant( zChicago ) ;
所有三个对象(
instant
、
zdtChicago
和
zdtShanghai
)代表同一时刻,时间线上的同一点。同时发生,但通过不同的挂钟时间看到。
显然,您想要仅日期部分,没有每天的时间和时区,为此提取一个
LocalDate
对象。
LocalDate ld = zdtChicago.toLocalDate() ;
当然,这可能与 zdtShanghai.toLocalDate()
返回的日期不同。
您可能需要构建一个特定的时刻。
ZonedDateTime zdtShanghai = ZonedDateTime.of( 2013, 8, 29, 17, 45, 0, 0 , zShanghai ) ;
位置和时区
你说:
我需要提供“位置”名称。
位置与时区无关。来自魁北克的商人可能想在东京旅行期间查看特定的 America/Montreal
时区的时间表。
您可以询问用户的Web浏览器或本地JVM其当前默认时区。但如果很重要,您必须与用户确认所需/预期的时区。
![Table of date-time types in Java, both modern and legacy](https://istack.dev59.com/7Wk03.webp)
关于java.time
java.time框架内置于Java 8及其后续版本中。这些类取代了过时的传统日期时间类,例如java.util.Date
、Calendar
和SimpleDateFormat
。
要了解更多信息,请参阅
Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是
JSR 310。
Joda-Time项目现在处于
维护模式,建议迁移到
java.time类。
您可以直接使用与JDBC 4.2或更新版本兼容的JDBC驱动程序,直接与您的数据库交换java.time对象。无需字符串,无需java.sql.*
类。Hibernate 5和JPA 2.2支持java.time。
如何获取java.time类?