3

我需要将 .NETDateTime转换为等效的 JavaCalendar表示。

.NETDateTime使用Ticks0001 年 1 月 1 日(.NET 纪元)以来的底层表示。

自1970 年 1 月 1 日(Java(或 Unix)时代)以来,JavaGregorianCalendar使用毫秒。正如预期的那样,对于 Java 纪元之前的日期,该值为负数。

DateTimeJava时代以来,我在这里以毫秒为单位转换表示形式:

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(1582 年 10 月 4 日“紧随”1582 年 10 月 15 日)。

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

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

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

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

4

3 回答 3

1

令人惊讶的是,没有人真正回答过为什么在 1582 年 10 月 4 日至 1582 年 10 月 15 日之间公历中存在一个“洞”的问题。有趣的答案是在 1582 年采用公历作为改革的历史中到儒略历。有关详细信息,请参阅Wikipedia 关于公历的文章。历史中的最后一段:格里高利改革段落指出

  • 格雷戈里(教皇格雷戈里十三世)减少了 10 天,以使日历恢复与季节同步。因此,当新历法投入使用时,自尼西亚会议以来 13 世纪以来积累的错误被删去十天来纠正。1582 年 10 月 4 日星期四是儒略历日,随后是 1582 年 10 月 15 日星期五的公历第一天(工作日周期不受影响)。 *

实际上,公历中不存在从 1582 年 10 月 5 日到 1582 年 10 月 14 日的日期。我怀疑 .Net 框架使用了一个通用公式,并且在处理 1582 年 10 月 15 日之前的日期时没有考虑到差异,而 Java 库确实考虑了这一点。

于 2013-11-12T04:07:08.777 回答
0

Java 文档

[...] 使用获得的日期GregorianCalendar仅在公元 4 年 3 月 1 日之后在历史上是准确的,当时采用现代儒略历规则

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

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

于 2013-04-11T15:04:11.190 回答
0

回答“为什么”:

来自(反编译 - 感谢 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);
于 2013-04-11T17:41:15.447 回答