我需要将.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
。
答案 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)
[...]使用
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);