从GregorianCalendar获取日期

时间:2016-12-02 09:42:06

标签: java date datetime java-7

GregorianCalendar不一致:

Calendar cal = new GregorianCalendar(2000, 0, 1);
long testCalOne = cal.getTimeInMillis();
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
long testCalTwo = cal.getTimeInMillis();

Calendar cal2 = new GregorianCalendar(2000, 0, 1);
cal2.setTimeZone(TimeZone.getTimeZone("UTC"));
long testCalThree = cal2.getTimeInMillis();

System.out.println(testCalOne + ", " + testCalTwo + ", " + testCalThree);

结果

946681200000, 946681200000, 946684800000

这分别代表GMT + 1,GMT + 1和UTC的2000-01-01午夜。我的时区相对于UTC为+1小时。

这里的问题是getTimeInMillis应该以UTC格式返回自1970-01-01以来的毫秒数。只有testCalThree是正确的。

另一个问题是setTimeZone似乎无法正常工作,具体取决于我之前是否调用过getTimeInMillis。

我的目标是从其他代码中获取我作为参数接收的日历,并获取UTC(java.util)日期以供进一步使用。

2 个答案:

答案 0 :(得分:0)

我认为这是Calendar实施中的一个错误。 time已缓存,即如果您在重复使用后计算了它,除非某些内容发生变化

但不知何故,设置时区不会被视为相关更改。

您可以通过明确更改或清除某些字段来强制重新计算时间(以毫秒为单位)。所以这个:

    Calendar cal = new GregorianCalendar(2000, 0, 1);
    long testCalOne = cal.getTimeInMillis();
    cal.clear(Calendar.ZONE_OFFSET);
    cal.setTimeZone(TimeZone.getTimeZone("UTC"));
    long testCalTwo = cal.getTimeInMillis();

    Calendar cal2 = new GregorianCalendar(2000, 0, 1);
    cal2.setTimeZone(TimeZone.getTimeZone("UTC"));
    long testCalThree = cal2.getTimeInMillis();

    System.out.println(testCalOne + ", " + testCalTwo + ", " + testCalThree);

给出:

946681200000, 946684800000, 946684800000

正如您所料。在设置时区之前,我唯一需要做的就是cal.clear(Calendar.ZONE_OFFSET)

无论如何,我想重复评论的建议。如果您重视自己的理智,请切换到JodaTime或Java8日期/时间。

答案 1 :(得分:0)

TL;博士

myGregCal.toZonedDateTime()
         .toInstant()

...或...

java.util.Date.from(
    myGregCal.toZonedDateTime()
             .toInstant()
)

java.time

  

我的目标是从其他代码中获取我作为参数接收的日历,并获取UTC(java.util)日期以供进一步使用。

麻烦的旧日期时间类CalendarDate现在已经遗留下来,取而代之的是java.time类。幸运的是,您可以通过在旧类上调用新方法来转换为/从java.time转换。

ZonedDateTime zdt = myGregCal.toZonedDateTime() ;

对于UTC值,提取Instant。该类代表UTC时间轴上的一个时刻,分辨率为纳秒。

Instant instant = zdt.toInstant() ;

要生成表示标准ISO 8601格式的UTC值的字符串,请致电toString

String output = instant.toString() ;

如果您在生成的字符串中需要其他格式,请转换为更灵活的OffsetDateTime并使用DateTimeFormatter。搜索Stack Overflow有很多例子。

最好避开Date课程。但如果你必须,转换。与Instant一样,Date代表UTC时间轴上的一个点。但Date仅限于毫秒分辨率。所以你冒着数据丢失风险,从超过3位毫秒的小数点开始减去数字,而不是9位数纳秒。

java.util.Date utilDate = Date.from( instant ) ;

关于java.time

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

现在位于Joda-Timemaintenance mode项目建议迁移到java.time。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore