在C#中将DateTime转换为Julian日期(ToOADate Safe?)

cwe*_*ton 29 .net c# datetime date julian-date

我需要将标准格里高利日期转换为儒略日日期.

我在C#中没有看到任何直接执行此操作的文档,但我发现许多帖子(谷歌搜索时)建议使用ToOADate.

ToOADate上的文档并未将此建议为Julian日期的有效转换方法.

任何人都可以澄清这个函数是否会准确地执行转换,或者可能是一个更合适的方法将DateTime转换为Julian格式的字符串.


在根据维基百科的Julian Day页面进行验证时,为我提供了预期的数字

public static long ConvertToJulian(DateTime Date)
{
    int Month = Date.Month;
    int Day = Date.Day;
    int Year = Date.Year;

    if (Month < 3)
    {
        Month = Month + 12;
        Year = Year - 1;
    }
    long JulianDay = Day + (153 * Month - 457) / 5 + 365 * Year + (Year / 4) - (Year / 100) + (Year / 400) + 1721119;
    return JulianDay;
}
Run Code Online (Sandbox Code Playgroud)

但是,这并不了解所使用的幻数.

谢谢


参考文献:

Dav*_*Yaw 83

OADate类似于Julian Dates,但使用了不同的起点(1899年12月30日对公元前4713年1月1日),以及不同的"新的一天"点.Julian Dates认为中午是新的一天的开始,OADates使用现代定义,午夜.

1899年12月30日午夜的朱利安日期是2415018.5.这个方法应该给你正确的值:

public static double ToJulianDate(this DateTime date)
{
    return date.ToOADate() + 2415018.5;
}
Run Code Online (Sandbox Code Playgroud)

至于算法:

  • if (Month < 3) ...:为了让神奇数字成为我们的权利,他们将二月放在今年的"年底".
  • (153 * Month - 457) / 5:哇,这是一些严肃的魔术数字.
    • 通常,每个月的天数是31 28 31 30 31 30 31 31 30 31 30 31,但在if语句中调整后,它变为31 30 31 30 31 31 30 31 30 31 31 28.或者,减去30你最终得到1 0 1 0 1 1 0 1 0 1 1 -2.他们通过在整数空间中进行划分来创建1和0的模式.
    • 重写到浮点,它会(int)(30.6 * Month - 91.4).30.6是每月的平均天数,不包括二月份(准确地说是30.63重复).91.4几乎是3月平均非2月份的天数.(30.6*3是91.8).
    • 所以,让我们删除30,然后只关注0.6天.如果我们将它乘以月数,然后截断为整数,我们将得到0和1的模式.
      • 0.6*0 = 0.0 - > 0
      • 0.6*1 = 0.6 - > 0(差值为0)
      • 0.6*2 = 1.2 - > 1(1的差异)
      • 0.6*3 = 1.8 - > 1(差值为0)
      • 0.6*4 = 2.4 - > 2(1的差异)
      • 0.6*5 = 3.0 - > 3(1的差异)
      • 0.6*6 = 3.6 - > 3(差值为0)
      • 0.6*7 = 4.2 - > 4(1的差异)
      • 0.6*8 = 4.8 - > 4(差值为0)
    • 看到右边的差异模式?这与上面列表中的模式相同,每个月的天数减去30.减去91.8将补偿前三个月的天数,这些天数被移到"年底",并调整它通过0.4移动1的连续差异(上表中的0.6*4和0.6*5)以与31天的相邻月份对齐.
    • 由于二月现在处于年底,我们不需要处理它的长度.它可能是45天(闰年46),唯一需要改变的是一年365天的常数.
    • 请注意,这取决于30个月和31个月的模式.如果我们连续两个月都是30天,这是不可能的.
  • 365 * Year:每年的天数
  • (Year / 4) - (Year / 100) + (Year / 400):每4年增加一个闰日,每100个减1个,每400个减1个.
  • + 1721119:这是公元前1月3日的朱利安日期.由于我们将日历的"开始"从1月移到3月,我们将其用作抵消,而不是1月1日.由于没有零年,1 BC得到整数值0.至于为什么3月2日而不是3月1日,我猜这是因为整个月的计算结果仍然有点偏差.如果原作者使用- 462而不是- 457(- 92.4而不是- 91.4浮点数学),那么偏移将是3月1日.


小智 8

而方法

public static double ToJulianDate(this DateTime date) { return date.ToOADate() + 2415018.5; }
Run Code Online (Sandbox Code Playgroud)

适用于现代日期,它有很大的缺点.

朱利安日期定义为负日期 - 即BCE(普通时代之前)日期,并且在天文计算中很常见.您不能构建年份小于0的DateTime对象,因此无法使用上述方法计算BCE日期的Julian日期.

1582年的格里高利历改革在10月4日至15日之间的历法中设置了11天.这些日期未在Julian日历或Gregorian日历中定义,但DateTime接受它们作为参数.此外,使用上述方法不会返回任何Julian日期的正确值.使用System.Globalization.JulianCalendar.ToDateTime()或将JulianCalendar时代传递到DateTime构造函数的实验仍然会对1582年10月5日之前的所有日期产生不正确的结果.

以下例程改编自Jean Meeus的"天文算法",从-4712年1月1日中午开始的所有日期返回正确的结果,在Julian日历上为零时间.如果传递的日期无效,它们也会抛出ArgumentOutOfRangeException.

 public class JulianDate
{
    public static bool isJulianDate(int year, int month, int day)
    {
        // All dates prior to 1582 are in the Julian calendar
        if (year < 1582)
            return true;
        // All dates after 1582 are in the Gregorian calendar
        else if (year > 1582)
            return false;
        else
        {
            // If 1582, check before October 4 (Julian) or after October 15 (Gregorian)
            if (month < 10)
                return true;
            else if (month > 10)
                return false;
            else
            {
                if (day < 5)
                    return true;
                else if (day > 14)
                    return false;
                else
                    // Any date in the range 10/5/1582 to 10/14/1582 is invalid 
                    throw new ArgumentOutOfRangeException(
                        "This date is not valid as it does not exist in either the Julian or the Gregorian calendars.");
            }
        }
    }

    static private double DateToJD(int year, int month, int day, int hour, int minute, int second, int millisecond)
    {
        // Determine correct calendar based on date
        bool JulianCalendar = isJulianDate(year, month, day);

        int M = month > 2 ? month : month + 12;
        int Y = month > 2 ? year : year - 1;
        double D = day + hour/24.0 + minute/1440.0 + (second + millisecond / 1000.0)/86400.0;
        int B = JulianCalendar ? 0 : 2 - Y/100 + Y/100/4;

        return (int) (365.25*(Y + 4716)) + (int) (30.6001*(M + 1)) + D + B - 1524.5;
    }

    static public double JD(int year, int month, int day, int hour, int minute, int second, int millisecond)
    {
        return DateToJD(year, month, day, hour, minute, second, millisecond);
    }


    static public double JD(DateTime date) 
    {
        return DateToJD(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);
    }
}
Run Code Online (Sandbox Code Playgroud)


Mal*_*ick 6

如果有人需要儒略日期转换为 DateTime ,请参见下文:

public static DateTime FromJulianDate(double julianDate)
{
    return DateTime.FromOADate(julianDate - 2415018.5);
}
Run Code Online (Sandbox Code Playgroud)