在Java中,某些日期无法正确转换为特定时区午夜的历元时间戳
这个Java代码,以字符串形式给出日期,应该在CET区域的午夜打印同一日期的历元时间戳(假设我不在同一区域) 如果我运行上述程序,我将得到打印:在Java中,某些日期无法正确转换为特定时区午夜的历元时间戳,java,timestamp,epoch,zone,Java,Timestamp,Epoch,Zone,这个Java代码,以字符串形式给出日期,应该在CET区域的午夜打印同一日期的历元时间戳(假设我不在同一区域) 如果我运行上述程序,我将得到打印: Epoch timestamp = 802389600000 我可以在这里验证它是否正确: 现在,这适用于大多数日期。然而,也有一些奇怪的日期,如“1975-09-19”,在那里它不起作用。事实上,它生成180313200000作为时间戳,给出凌晨1点而不是午夜: 你能解释一下原因吗?我遗漏了什么?关于夏令时,您的约会示例之间似乎存在差异。 如
Epoch timestamp = 802389600000
我可以在这里验证它是否正确:
现在,这适用于大多数日期。然而,也有一些奇怪的日期,如“1975-09-19”,在那里它不起作用。事实上,它生成180313200000作为时间戳,给出凌晨1点而不是午夜:
你能解释一下原因吗?我遗漏了什么?关于夏令时,您的约会示例之间似乎存在差异。
如果我使用
java.time
(从java 8开始就应该一直使用),我会得到不同偏移量的结果:
用于“+02:00”
和“1995-06-06”
对于“+01:00”
“1975-09-19”
public static void main(String[] args) {
// provide two sample dates
String workingDateStr = "1995-06-06";
String failingDateStr = "1975-09-19";
// and a formatter that parses the format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// then parse them to date objects that don't know about time or zone
LocalDate workingDate = LocalDate.parse(workingDateStr, dtf);
LocalDate failingDate = LocalDate.parse(failingDateStr, dtf);
/*
* then create an objects that are aware of time and zone
* by using the parsed dates, adding a time of 00:00:00 and a zone
*/
ZonedDateTime workingZdt = ZonedDateTime.of(workingDate, LocalTime.MIN, ZoneId.of("CET"));
ZonedDateTime failingZdt = ZonedDateTime.of(failingDate, LocalTime.MIN, ZoneId.of("CET"));
// finally, print different representations of the results
System.out.println(workingZdt + " ——> " + workingZdt.toInstant().toEpochMilli());
System.out.println(failingZdt + " ——> " + failingZdt.toInstant().toEpochMilli());
}
输出:
1995-06-06T00:00+02:00[CET]->802389600000
1975-09-19T00:00+01:00[CET]->180313200000
这意味着您最好使用特定偏移,而不是分区
这一问题可能是由于马耳他采用夏令时的时间,请查看以下代码及其输出:
public static void main(String[] args) {
// provide two sample dates
String failingDateStr = "1975-09-19";
// and a formatter that parses the format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// then parse them to date objects that don't know about time or zone
LocalDate failingDate = LocalDate.parse(failingDateStr, dtf);
/*
* then create an objects that are aware of time and zone
* by using the parsed dates, adding a time of 00:00:00 and a zone
*/
ZonedDateTime failingZdt = ZonedDateTime.of(failingDate, LocalTime.MIN, ZoneId.of("CET"));
// add some years to 1975 and...
for (int year = 0; year < 4; year++) {
// ... print the different representations of the result
System.out.println(failingZdt.plusYears(year) + " ——> "
+ failingZdt.plusYears(year).toInstant().toEpochMilli());
}
}
此输出表示1977年的介绍。。。正确吗?时区差异
您的Java代码使用CET,而CET并不是真正的时区(例如,因为大部分使用CET的区域在一年中的大部分时间都使用CEST)。Java将CET翻译成欧洲/巴黎。1975年,法国和巴黎没有使用夏季时间(DST)。它于1976年3月重新引入
您与历元转换器的链接指定马耳他时区(欧洲/马耳他)。马耳他在1975年确实使用了夏季时间:该年4月20日至9月21日在CEST
这就解释了结果的差异
在Java代码中
如果你想要时间:
String dateStr = "1975-09-19";
long epochTimestamp =
LocalDate
.parse(dateStr)
.atStartOfDay(ZoneId.of("Europe/Malta"))
.toInstant()
.toEpochMilli();
System.out.println("Epoch timestamp = " + epochTimestamp);
这张照片是:
历元时间戳=18030960000
您链接到的epoch converter很高兴同意:
转换结果(180309600)
180309600转换为1975年9月19日星期五00:00:00(上午)in
时区欧洲/马耳他(CEST)偏移量(与格林威治的差异
时间/GMT)为+02:00或7200秒。这个日期是在白天
节省时间
在Java中,一定要使用Java.time,这是现代Java日期和时间API,用于日期和时间工作。与旧的日期和时间类(如SimpleDateFormat
,时区
,日期
和日历
)相比,使用它要好得多。此外,将小时数等设置为0也不是获取一天中第一个时刻的正确方法。在有些情况下,夏季从一天的开始开始,因此一天的第一个时刻是01:00:00。Java知道这一点,因此,atStartOfDay
方法将为您提供一天中正确的forst时刻
无论是使用过时类还是现代类,始终以区域/城市格式指定时区,例如Europe/Paris或Europe/Malta。三个、四个和五个字母的时区缩写常常模棱两可,而且往往不是真正的时区,因此不值得依赖
链接
- 解释如何使用java.time
SimpleDateFormat
、Date
和Calendar
。这些类设计得很糟糕,而且早已过时,第一个类尤其令人讨厌。而是使用ZoneDateTime
和Instant
,这两种方法都来自。
String dateStr = "1975-09-19";
long epochTimestamp =
LocalDate
.parse(dateStr)
.atStartOfDay(ZoneId.of("Europe/Malta"))
.toInstant()
.toEpochMilli();
System.out.println("Epoch timestamp = " + epochTimestamp);