在java和.net之间转换日期 - 休息2天

时间:2013-04-11 13:22:41

标签: java .net datetime calendar gregorian-calendar

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

.NET DateTime使用Ticks,因为 1月1日1月(.NET纪元)作为基础表示。

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

自从 Java 时代以来,我正在改变millis中的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

3 个答案:

答案 0 :(得分:1)

令人惊讶的是,在1582年10月4日到1582年10月15日之间,没有人真正回答过为什么在公历中存在“洞”的问题。有趣的答案是在公历中采用格里高利历的历史。 1582年改为朱利安历法。有关详细信息,请参阅Wikipedia's article on Gregorian Calendar。历史中的最后一段:格里高利改革段落陈述

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

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

答案 1 :(得分:0)

来自Java documentation

  

[...]使用GregorianCalendar获得的日期仅在历史上是准确的   从公元4月1日开始,当时现代朱利安历法规则   通过

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

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

答案 2 :(得分: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);