如何正确地将新的Date(0L)转换为LocalDate(1970-01-01)?

时间:2018-09-17 07:34:49

标签: java java-time localdate

考虑代码:

import org.junit.Test;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * @author nsheremet
 */
public class MyTest {
    private static final Date CREATED_ON = new Date(0L);

    @Test
    public void someTest() {
        LocalDate actualDate = CREATED_ON.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        assertThat(actualDate).isEqualTo(LocalDate.of(1970, 01, 01));
    }
}

在我的机器上,它运行良好,但在其他机器上却出现异常:

[ERROR] Failures: 
[ERROR] MyTest.someTest:23 expected: <19[70-01-0]1> but was:<19[69-12-3]>1 

为什么会这样?是使用UTC而非ZoneId.systemDefault()吗?

3 个答案:

答案 0 :(得分:4)

  

为什么会这样?使用UTC代替ZoneId.systemDefault()是   对吗?

是的。 java.util.Date的EPOCH是 1970年1月1日UTC ,但是ZoneId.systemDefault()将获取当前计算机配置为用作用户时区的内容。不太可能是UTC。

因此,您需要使用时区UTC,而不要使用其他任何时间。

答案 1 :(得分:1)

可能的问题是您的两台计算机都位于不同的时区。 在两台计算机上检查ZoneId(如果它们相同)。

也许您想放置定义的ZoneId,以确保结果始终相同?

答案 2 :(得分:1)

tl; dr

Instant
.ofEpochMilli( 0L ) 
.atOffset( 
    ZoneOffset.UTC
)
.toLocalDate()
.toString()
  

1970-01-01

java.util.Date

java.util.Date表示UTC中的一个时刻,带有日期的日期。

您的代码:

new Date(0L)

…产生了一个代表UTC 1970-01-01T00:00:00Z的1970年第一刻的对象。

时区

在同一时刻,让印度电话上的某人告诉您他们在时钟上看到的一天中的时间,您会得到“ 5:30 AM”的答复。当时的时区Asia/Kolkata使用了UTC提前五个半小时的时间。

如果与蒙特利尔魁北克省的某人通电话,您会得到“ 1969年12月31日晚上7点…”的答案。该日期所在的时区America/Montreal使用的时间比UTC时间落后 五小时。在UTC的午夜之后数小时意味着也要在1969年的最后一天而不是1970年的第一天。America/New_York和北美大部分东海岸的同上。

因此,您必须了解,在任何给定时刻,日期都会在全球范围内变化,日期会随区域而变化。例如,当日本出现新的一天时,在巴西仍然是“昨天”。

java.time

Date类很糟糕,应该从不使用。它与Calendar一起成为了遗产,几年前被 java.time 类所取代。具体来说,DateInstant取代,这两个类均表示UTC的时刻。

Instant instant = Instant.ofEpochMilli( 0L ) ;
  

instant.toString():1970-01-01T00:00Z

调整特定区域(时区)的人们使用的挂钟时间。应用ZoneId获得ZonedDateTime对象。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

提取仅包含日期的部分,而不包含时间和区域。

LocalDate ld = zdt.toLocalDate() ;
  

ld.toString():1969-12-31

如果要保留UTC,请应用ZoneOffset的{​​{1}}常量而不是ZoneOffset.UTC。并获得ZoneId而不是OffsetDateTime

ZonedDateTime

提取仅日期的值OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

LocalDate
  

ld.toString():1970-01-01