我们从第3方库中收到了GregorianCalendar对象。我们需要将其转换为Date,以便在另一个第三方库中使用。而且我们使用的是Java 1.6,因此我们没有新的时间/即时类。
问题是调用Calendar.getTime()给出了一个不同的日期,被我们的时区抵消了。所以第二天要8个小时。
如果没有这种转变,我们怎么办呢?
更新:我们通过OData调用获取日期。返回的日期是员工的生日(罗斯文),因此不应有时间。但是它作为GregorianCalendar对象返回,时间为1992-05-01 00:00:00。出现格林尼治标准时间(GMT)时区。
并且getTime()返回的日期为“ Thu Apr 30 18:00:00 MDT 1992”-我在山区时区。
问题是我需要从日历对象中获取1992-05-01而不是1992-04-30的Date对象。并且最好也与时间偏移匹配。
答案 0 :(得分:2)
获取默认时区的Date
值,致电setTimeZone()
。
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
cal.clear();
cal.set(1992,4,1); // 1992-05-01 00:00:00 GMT
// "Fix" time zone
cal.setTimeZone(TimeZone.getDefault());
System.out.println(cal.getTime());
输出
Fri May 01 00:00:00 EDT 1992
答案 1 :(得分:0)
java.util.Date date = myGregorianCalendar.getTime() ; // Same moment, same point on the timeline. `Date` is in UTC, `GregorianCalendar` may be in some other time zone.
String output = date.toString() ; // This new string is a lie, dynamically applying the JVM’s current time zone while the `Date` is actually in UTC, always, by definition.
没有变化。调用GregorianCalendar.getTime
会产生一个java.util.Date
。根据定义,Date
对象始终使用UTC。 不幸的是,Date::toString
方法位于,在生成String时注入了JVM当前的默认时区。
请注意,Date
和String
是两个不同的对象。一个在UTC中保留一个时刻,另一个是在调整到某个时区后该时刻的文本表示。
GregorianCalendar
,Date
和String
代表相同的时刻,时间轴上的同一点,但不同的时钟时间。
如果使用现代的 java.time 类,而不是可怕的混乱(传统类Date
,Calendar
和{ {1}}。
GregorianCalendar
类是Java 8及更高版本中内置的 java.time 类所取代的麻烦的旧日期时间类之一。在ThreeTen-Backport项目中,许多 java.time 功能都被反向移植到Java 6和Java 7。
使用添加到旧类中的新方法,特别是GregorianCalendar
,从旧类转换为现代 java.time 。如果使用反向端口,请使用DateTimeUtils
类。
GregorianCalendar::toZonedDateTime
ZonedDateTime
对象替代了ZonedDateTime zdt = DateTimeUtils.toZonedDateTime( myCalendar ) ;
。从概念上讲,此类是Instant
(UTC中的某个时刻)与指定的时区,ZoneId
对象的组合。
GregorianCalendar
您可以从Instant instant = zdt.toInstant() ;
转换回java.util.Date
,以与尚未更新为 java.time 的旧代码兼容。
Instant
如果只需要日期部分,而不需要时间和时区,则创建一个LocalDate
对象。
java.util.Date date = DateTimeUtils.toDate( instant ) ; // Convert from modern `Instant` class to legacy `Date` class.
问题是调用Calendar.getTime()给出了一个不同的日期,被我们的时区抵消了。所以第二天要8个小时。
如果没有这种转变,我们怎么办呢?
...
并且getTime()返回的日期为“ Thu Apr 30 18:00:00 MDT 1992”-我在山区时区。
您看到的是一种幻觉。 LocalDate ld = zdt.toLocalDate() ;
方法向您返回一个GregorianCalendar::getTime
对象。然后,您在该java.util.Date
对象上隐式调用了toString
。该Date
方法具有不幸的行为,即在生成表示其值的字符串时应用JVM当前的默认时区。根据定义,java.util.Date::toString
的值实际上是UTC,始终是UTC。该Date
方法产生了一种幻觉,即toString
确实具有时区,而实际上却没有†。
†实际上,Date
类确实包含一个时区,但位于其源代码的深处。用于java.util.Date
方法实现之类的东西。但是该类没有getter或setter,因此对于我们来说似乎是看不见的。与您的问题相关,这是无关紧要的。
令人困惑?是。这是避免这些可怕的旧日期时间类的许多原因之一。只能使用 java.time 类。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要equals
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。