虽然方法
public static double ToJulianDate(this DateTime date) { return date.ToOADate() + 2415018.5; }
适用于现代日期,它有很大的缺点。
儒略日期是为负日期定义的 - 即 BCE(普通纪元之前)日期,并且在天文计算中很常见。您不能构造年份小于 0 的 DateTime 对象,因此无法使用上述方法为 BCE 日期计算儒略日期。
1582 年的公历改革在 10 月 4 日至 15 日之间的日历中设置了 11 天的漏洞。这些日期在儒略历或公历中都没有定义,但 DateTime 接受它们作为参数。此外,使用上述方法不会返回任何儒略日期的正确值。使用 System.Globalization.JulianCalendar.ToDateTime() 或将 JulianCalendar 纪元传递给 DateTime 构造函数的实验仍然会为 1582 年 10 月 5 日之前的所有日期产生不正确的结果。
以下例程改编自 Jean Meeus 的“天文算法”,从儒略历上的 1 月 1 日中午 -4712 年正午开始返回所有日期的正确结果。如果通过了无效日期,它们还会抛出 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);
}
}