[英]Cannot Convert Date '0001-01-01' from Java to C# correctly
我尝试提供一个工具将 datetime 从 Java 转换为 C#。但是有一个严重的问题。
在 Java 中,我通过 java.sql.Date 从 SQL 服务器数据库中读取“0001-01-01”,并得到毫秒-62135798400000
。
我还考虑了时区偏移量。
private static long getMilliSecondWithoutTimeZone(long origin) {
return origin + (ZonedDateTime.now().getOffset().getLong(OFFSET_SECONDS) * 1000);
}
最后的毫秒是-62135769600000
。
在 C# 中,我使用这个毫秒到新的 Datetime
var ticks = new DateTime(1970, 1, 1).Ticks + (-62135769600000 * 10000);
var date = new DateTime(ticks);
代码运行时,会抛出异常:
System.ArgumentOutOfRangeException: 'Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. (Parameter 'ticks')'
但是,根据我的测试,“1600-01-01”之后的转换是正确的。
在'1600-01-01'之前,总会有几天的错误。
这让我很困惑。
公历是作为儒略历(由 JulianCalendar 类表示)的替代品而开发的,并于 1582 年 10 月 15 日首次在少数文化中引入。在处理文化采用公历之前的历史日期时日历,如果 .NET Framework 中可用,则应使用原始日历。 例如,丹麦在 1700 年的 2 月 19 日(儒略历)或 3 月 1 日(公历)从儒略历改为公历。在这种情况下,对于采用公历之前的日期,您应该使用儒略历。 但是,请注意,没有任何区域性为 JulianCalendar class 提供内在支持。您必须将 JulianCalendar class 用作独立日历。 有关详细信息,请参阅使用日历。
实际原因是:
解决方案:
import java.sql.Date;
import java.time.chrono.IsoChronology;
import java.time.*;
public class Test {
public static Long getMilliSeconds(Date date) {
if (null == date) {
return null;
}
IsoChronology ISO = IsoChronology.INSTANCE;
LocalDate ld = date.toLocalDate();
return ISO.localDateTime(LocalDateTime.of(ld.getYear(), ld.getMonth(), ld.getDayOfMonth(), 0, 0, 0)).toInstant(ZoneOffset.UTC).toEpochMilli();
}
}
您提到的毫秒值-62_135_798_400_000
来自老式的java.sql.Date
object 在当时假定为 UTC 偏移 +08:00 的时区中创建,也许只是 Etc/GMT-8 . 根据这个假设,该值在历史上是正确的,因为当时使用的是 Julian 日历,而Date
确实使用了它。
我不知道 C# 使用的 .NET 类,但我认为这几天的错误很可能是由于他们使用了 proleptic 公历,也就是说,假装过去一直使用公历,即使它没有在1582
之前就存在了。 现代 Java 日期和时间 API 执行此操作,因此为您提供通常相差几天的毫秒值。
long milliseconds = LocalDate.of(1, 1, 1)
.atStartOfDay(ZoneOffset.ofHours(8))
.toInstant()
.toEpochMilli();
System.out.format(Locale.ENGLISH, "%,d%n", milliseconds);
Output:
-62,135,625,600,000
比您提到的时间晚了 48 小时或 2 天。 看看它是否解决了您的问题。
Oracle 教程:日期时间解释如何使用 java.time。
您忘记考虑时区偏移量。
如果我们将时区设置为 UTC,您将看到:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
System.out.println(new Date(-62135798400000L));
Output
Fri Dec 31 16:00:00 UTC 1
它实际上是公元前 1 年,而不是公元 1 年。
时间 16:00 表示 8 小时的时区偏移,因此如果我们更改为GMT+8
,我们将得到:
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
System.out.println(new Date(-62135798400000L));
Output
Sat Jan 01 00:00:00 GMT+08:00 1
这是正确的公元 1 年。
这意味着您需要将毫秒值调整 8 小时,即 28800000 毫秒。
对于日期0001-01-01 00:00 UTC
,正确的毫秒值是-62135769600000
。 C# DateTime
class 将拒绝任何小于该值的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.