0 年之前的 LocalDateTime 与时间戳之间的转换是错误的

问题描述 投票:0回答:1

如果 LocalDateTime 在 0000-00-00 00:00:00 之前,转换为 Timestamp 时,Timestamp 年份是错误的,例如 LocalDateTime 中的 -1996 将转换为 Timestamp 中的 -1997。 -1996是闰年,-1997不是闰年,所以你不能将Timestamp中的-1997-02-29转换为LocalDateTime

 LocalDateTime localDateTime = LocalDateTime.of(-1996,2,29,10,10,10,100);
 Timestamp timestamp =  Timestamp.valueOf(localDateTime); // timestamp is B.C.E. 1997-02-29T10:10:10.000
 LocalDateTime localDateTime1 = timestamp.toLocalDateTime(); // throw exception[ Invalid date 'February 29' as '1997' is not a leap year]
java timestamp
1个回答
0
投票
LocalDateTime 中的

-1996 将转换为 Timestamp 中的 -1997

这并没有错。

LocalDateTime
Timestamp
的“年”含义不同。

A

LocalDateTime
“年份”值为 1 表示公元 1 年,值为 0 表示公元前 1 年,依此类推,因此值 -1996 代表公元前 1997 年。

A

Timestamp
“年份”是一个数字,加上 1900 就可以得到实际的年份(请参阅
java.util.Date
的文档),尽管它的许多 API 会自动为您加/减 1900。更糟糕的是,加上 1900 得到的年份总是正数,所以这有点像“纪元之年”。

当您打印

Timestamp
时,会自动添加 1900 以显示 1997 年。该数字不是负数,但
Timestamp
实际上代表 BC 中的某个时刻。

因此,转换

Timestamp
是正确的,但是当将
Timestamp
转换为
LocalDateTime
时,
toLocalDateTime
方法只是从
Timestamp
获取年份并加上 1900,然后将其用作
LocalDateTime
年。所以你实际上得到了一个
LocalDateTime
代表公元中的日期。由于公元 1997 年不是闰年,转换失败。

另请参阅 toLocalDateTime

来源

可以说,这可以被视为

toLocalDateTime
中的一个错误,但我不认为
Timestamp
首先被设计来代表公元前的日期(它可以代表那些时间的瞬间) ).

我建议您应该完全停止使用

Timestamp
。如果您想代表某个时刻,请使用
Instant

要进行此往返,您需要检查

Timestamp
是否在 AD 1 之前,如果是,则使用
-(getYear() + 1899)
作为
LocalDateTime
的年份。

这是它的外观草图:

// getAD1EpochMillis() is a method you should write to get the epoch millis
// of AD 1 January 1st midnight, in the system timezone. 
// You should use the old APIs to do this, because timezones in java.time behaves differently.
if (timestamp.getTime() < getAD1EpochMillis()) {
    return LocalDateTime.of(
            -(timestamp.getYear() + 1899),
            timestamp.getMonth() + 1,
            timestamp.getDate(),
            timestamp.getHours(),
            timestamp.getMinutes(),
            timestamp.getSeconds(),
            timestamp.getNanos()
    );
} else {
    return timestamp.toLocalDateTime();
}

“AD 1 之前”的含义取决于时区,但

java.time
API 计算时区的方式与旧 API 不同(例如,
java.time
在时区标准化之前考虑了当地平均时间)。这也是为什么你不能只对往返执行此操作:

timestamp.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()

所有这些都表明,旧的 API 非常不擅长处理历史日期。请迁移至

java.time

© www.soinside.com 2019 - 2024. All rights reserved.