考虑代码:
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()
吗?
答案 0 :(得分:4)
为什么会这样?使用UTC代替
ZoneId.systemDefault()
是 对吗?
是的。 java.util.Date
的EPOCH是 1970年1月1日UTC ,但是ZoneId.systemDefault()
将获取当前计算机配置为用作用户时区的内容。不太可能是UTC。
因此,您需要使用时区UTC,而不要使用其他任何时间。
答案 1 :(得分:1)
可能的问题是您的两台计算机都位于不同的时区。 在两台计算机上检查ZoneId(如果它们相同)。
也许您想放置定义的ZoneId,以确保结果始终相同?
答案 2 :(得分:1)
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
和北美大部分东海岸的同上。
因此,您必须了解,在任何给定时刻,日期都会在全球范围内变化,日期会随区域而变化。例如,当日本出现新的一天时,在巴西仍然是“昨天”。
Date
类很糟糕,应该从不使用。它与Calendar
一起成为了遗产,几年前被 java.time 类所取代。具体来说,Date
被Instant
取代,这两个类均表示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