在java和.net之间转换日期 – rest2天

我需要将.NET DateTime转换为等效的Java Calendar表示。

.NET DateTime使用自Ticks1月1日起的Ticks (.NET纪元)作为底层表示。

Java GregorianCalendar使用自19701月1日以来的毫秒(Java(或Unix)时代)。 正如预期的那样,Java纪元之前的日期值为负。

在这里,我将在Java时代以来以毫秒为单位转换DateTime表示:

 var dt = new DateTime(1,2,3); //way, way back. var javaEpoch = new DateTime(1970, 1, 1); var javaMillis = (dt - javaEpoch).Ticks / TimeSpan.TicksPerMillisecond; dt.ToString("MM/dd/yyyy").Dump(); // .Dump() is provided by LinqPad. javaMillis.Dump(); // Use Console.WriteLine(...) // for a regular console app. 

这输出:

02/03 / 0001
-62132745600000

现在,在此Java代码段中复制粘贴毫秒值:

 java.util.Calendar cal = new java.util.GregorianCalendar(); cal.setTimeInMillis(-62132745600000L); java.text.SimpleDateFormat df = new java.text.SimpleDateFormat(); df.applyPattern("MM/dd/yyyy"); System.out.println(df.format(cal.getTime())); 

这输出:

02/05 / 0001

我想我的问题是:我如何从DateTime获得有效的毫秒值,从中可以正确构建Java日历?

……隐含的子问题“这里到底发生了什么?”

编辑:我使用DateTimeValues围绕从Julian到Gregorian日历的缺失日期范围(1582年10月4日“跟随”到1582年10月15日)。

对于比1582年10月15日更近的日期,转换似乎工作正常。

…但是在缺失的范围内,DateTime开始(或者更确切地说, 没有开始)表现得很有趣:

 var timespan = new DateTime(1582, 10, 15) - new DateTime(1582, 10, 4); 

返回11天的TimeSpan ,因此DateTime运算符不会考虑这个漏洞。 是什么赋予了? 我认为底层实现基于System.Globalization.GregorianCalendar

令人惊讶的是,在1582年10月4日至1582年10月15日期间,没有人真正回答过为何在公历中存在“漏洞”的问题。有趣的答案是在1582年采用格里高利历的历史到朱利安日历。 有关详细信息,请参阅维基百科关于格里高利历的文章 。 历史中的最后一段:格里高利改革段落

  • 格雷戈里(教皇格雷戈里十三世)放弃了10天,使日历与季节同步。 因此,当新日历投入使用时,自尼西亚委员会以来的13个世纪中累积的错误被删除了十天。 朱利安历日在1582年10月4日星期四之后是格里高利历的第一天,即1582年10月15日星期五(工作日的周期没有受到影响)。*

实际上,格里高利历中不存在1582年10月5日至1582年10月14日的日期。 我怀疑.Net Framework使用了一个通用公式,并没有考虑到处理1582年10月15日之前的日期时的差异,而Java库确实考虑了它。

从Java文档 :

使用GregorianCalendar获得的日期在历史上仅从公元3月1日开始准确,当时采用现代儒略历规则

考虑到你的DateTime减法,它只是一个Ticks差异,这里绝对没有特定日历的概念。 实现基本上是return new TimeSpan(x.Ticks - y.Ticks)

您可能更0001-02-03T00:00:00Z简单地输出然后解析ISO- 0001-02-03T00:00:00Z /时间,例如0001-02-03T00:00:00Z ,它没有歧义,而不是依赖于内部表示。

回答’为什么’:

来自(反编译 – 感谢dotPeek!).NET 4源代码(评论是我的):

 public static DateTime operator -(DateTime d, TimeSpan t) { //range checks long internalTicks = d.InternalTicks; long num = t._ticks; if (internalTicks < num || internalTicks - 3155378975999999999L > num) throw new ArgumentOutOfRangeException("t", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic")); else //plain arithmetic using the Ticks property of the two dates. return new DateTime((ulong) (internalTicks - num) | d.InternalKind); } 

所以是的,绝对没有DateTime运算符的特殊’格里高利’处理。

关于’如何修复’:

我最终在这些方面使用了一些东西:(伪Java)

 Calendar cal = new GregorianCalendar(); cal.set(dt.Year, dt.Month - 1 /*it's 0-based*/, dt.Day, dt.Hour, dt.Minute, dt.Second); cal.set(Calendar.MILLISECOND, dt.Millisecond);