我正在尝试从 LocalDate
对象 (java.time) 生成
),其中我有以下标准:Date
对象 (java.util.Date
) .LocalDate
- 允许使用可以从
Date
对象中减去特定天数的参数 - 将日期和时间设置为当前 UTC 日期和时间
- 在一天的开始时间,即
00:00:00
- 时区标记(即 CDT 或 UTC)无关紧要,因为我将其从
String
中删除了
为了满足这个标准,我创建了一个测试程序,但是当我修改 LocalDate
的某个属性时,我得到了有趣的结果。请参阅下面的代码:
public static void main (String args[]) {
Long processingDaysInPast = 0L;
LocalDate createdDate1 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
LocalDate createdDate2 = LocalDate.now(Clock.systemUTC()).minusDays(processingDaysInPast);
System.out.println(createdDate1);
System.out.println(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC));
System.out.println(Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC)));
System.out.println((createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
System.out.println(Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
}
输出:
2017-08-14
2017-08-14T00:00:00Z
Sun Aug 13 19:00:00 CDT 2017
2017-08-14
2017-08-14T05:00:00Z
Mon Aug 14 00:00:00 CDT 2017
当我添加值 Date.from(createdDate1.atStartOfDay().toInstant(ZoneOffset.UTC))
时,我得到了日期的预期输出,其中 00:00: 00
时间字段。但是,如果我不添加此参数,例如: Date.from(createdDate2.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())
我会得到结果 day before , 19:00:00
这是为什么?
我的主要目标是能够捕获 Date
对象,其中包含当前 UTC 日期,并且时间归零 (StartOfDay
)。
最佳答案
当你这样做时:
createdDate2.atStartOfDay().atZone(ZoneId.systemDefault())
首先,createdDate2.atStartOfDay()
返回 LocalDateTime
,相当于 2017-08-14
在午夜。一个LocalDateTime
不了解时区。
当您调用atZone(ZoneId.systemDefault())
时,它创建一个ZonedDateTime
以及系统默认时区中的相应日期 (2017-08-14) 和时间(午夜)( ZoneId.systemDefault()
)。在您的情况下,默认时区不是 UTC(它是“CDT”,因此 CDT 已是午夜 - 只需执行 System.out.println(ZoneId.systemDefault())
来检查您的默认时区是什么)。
要获取 UTC 午夜日期,您可以将默认区域 ( ZoneId.systemDefault()
) 替换为 UTC ( ZoneOffset.UTC
):
Date.from(createdDate2.atStartOfDay().atZone(ZoneOffset.UTC).toInstant())
或者(较短的版本):
Date.from(createdDate2.atStartOfDay(ZoneOffset.UTC).toInstant())
当然你也可以像 createdDate1
那样做。 :
Date.from(createdDate2.atStartOfDay().toInstant(ZoneOffset.UTC))
它们都是等效的,并且结果将是 UTC 的午夜。
简单说明一下:短时区名称,例如 CDT
或PST
不是真正的时区。
API 使用IANA timezones names (始终采用 Region/City
格式,例如 America/Chicago
或 Europe/Berlin
)。
避免使用 3 个字母的缩写(如 CDT
或 PST
),因为它们是 ambiguous and not standard .
有lots of different timezones可以使用CDT
作为缩写。发生这种情况是因为时区是一个地区在历史上曾经、现在和将来的所有不同偏移量的集合。仅仅因为很多地方使用CDT
今天,并不意味着它们在过去的同一时期都使用过,也不意味着将来也会被所有人使用。由于历史不同,每个地区都会创建一个时区。
关于java - 本地日期不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45680464/