[英]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.