将日历转换为日期-忽略时区

时间:2018-07-09 22:36:05

标签: java date calendar

我们从第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对象。并且最好也与时间偏移匹配。

2 个答案:

答案 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)

tl; dr

没有变化

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当前的默认时区。

请注意,DateString是两个不同的对象。一个在UTC中保留一个时刻,另一个是在调整到某个时区后该时刻的文本表示。

GregorianCalendarDateString代表相同的时刻,时间轴上的同一点,但不同的时钟时间。

为清晰起见,请使用 java.time

如果使用现代的 java.time 类,而不是可怕的混乱(传统类DateCalendar和{ {1}}。

java.time

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 ) ; 。从概念上讲,此类是InstantUTC中的某个时刻)与指定的时区,ZoneId对象的组合。

如果您希望在UTC中看到相同的时刻,请提取Instant

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.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance 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中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore