将DateTime转换为C#中的朱利安日期(ToOADate Safe?)
我需要将标准的格里高利日期转换为朱利安日期 我在C#中没有看到任何可以直接做到这一点的文档,但我发现许多帖子(在谷歌搜索时)建议使用 关于的文档不建议将其作为儒略日期的有效转换方法 有人能澄清一下这个函数是否能准确地执行转换,或者是一个更合适的方法来将DateTime转换为Julian格式的字符串将DateTime转换为C#中的朱利安日期(ToOADate Safe?),c#,.net,datetime,date,julian-date,C#,.net,Datetime,Date,Julian Date,我需要将标准的格里高利日期转换为朱利安日期 我在C#中没有看到任何可以直接做到这一点的文档,但我发现许多帖子(在谷歌搜索时)建议使用 关于的文档不建议将其作为儒略日期的有效转换方法 有人能澄清一下这个函数是否能准确地执行转换,或者是一个更合适的方法来将DateTime转换为Julian格式的字符串 根据验证时为我提供预期的数字 publicstaticlongconverttojulian(DateTime-Date) { int MOUNT=日期。月份; int Day=日期.Day; in
根据验证时为我提供预期的数字
publicstaticlongconverttojulian(DateTime-Date)
{
int MOUNT=日期。月份;
int Day=日期.Day;
int Year=日期。年份;
如果(月<3)
{
月=月+12;
年份=第1年;
}
长儒略历日=日+(153*月-457)/5+365*年+(年/4)-(年/100)+(年/400)+1721119;
返回朱利安代;
}
然而,这是没有一个魔术数字正在使用的理解
谢谢
参考文献:
public static double ToJulianDate(this DateTime date)
{
return date.ToOADate() + 2415018.5;
}
至于算法:
:为了让神奇的数字发挥我们的作用,他们把二月放在一年的“末尾”if(Month<3).
:哇,这真是一些神奇的数字。(153*月-457)/5
- 通常情况下,每个月的天数为3128313031,但在if报表中进行调整后,则变为31303128。或者,减去30,结果是101011-2。他们通过在整数空间进行除法来创建1和0的模式李>
- 重新写入浮点,它将是
。30.6是每月的平均天数,不包括2月(准确地说是30.63天)。91.4几乎是3个平均非2月份月份的天数。(30.6*3等于91.8)(int)(30.6*月-91.4)
- 那么,让我们去掉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*年
:每4年加一个闰日,每100年减一个,每400年加一个李>(年/4)-(年/100)+(年/400)
:这是公元前1年3月2日的儒略日期。由于我们将日历的“开始日期”从1月移到了3月,因此我们使用它作为偏移量,而不是1月1日。由于没有年份0,因此1BC获得整数值0。至于为什么3月2日而不是3月1日,我猜那是因为整个月的计算在最后还是有点偏离。如果原始编写器使用了+1721119
而不是-462
(-457
而不是浮点数学中的-92.4
),那么偏移量应该是3月1日李>-91.4
- 当方法
适用于现代日期,它有明显的缺点 朱利安日期是为负日期定义的,即BCE(普通纪元之前)日期,在天文计算中很常见。您无法构造年份小于0的DateTime对象,因此无法使用上述方法计算BCE日期的儒略日期 1582年的公历改革使公历在10月4日至15日之间有11天的空缺。这些日期在儒略历或公历中都没有定义,但DateTime接受它们作为参数。此外,使用上述方法不会返回任何儒略日期的正确值。使用System.Globalization.JulianCalendar.ToDateTime()或将JulianCalendar纪元传递到DateTime构造函数的实验仍然会对1582年10月5日之前的所有日期产生不正确的结果 以下例程改编自Jean Meeus的“天文算法”,返回从1月1日中午开始的所有日期的正确结果,-4712,朱利安历法上的时间零点。如果传递的日期无效,它们还会抛出ArgumentOutOfRangeExceptionpublic static double ToJulianDate(this DateTime date) { return date.ToOADate() + 2415018.5; }
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); } }
公共类JulianDate { 公共静态bool isJulianDate(整数年、整数月、整数日) { //1582年之前的所有日期都在儒略历中 如果(年)<
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); } }
/* * convert magic numbers created by: * (153*month - 457)/5) * into an explicit array of integers */ int[] CumulativeDays = new int[] { -92 // Month = 0 (Should not be accessed by algorithm) , -61 // Month = 1 (Should not be accessed by algorithm) , -31 // Month = 2 (Should not be accessed by algorithm) , 0 // Month = 3 (March) , 31 // Month = 4 (April) , 61 // Month = 5 (May) , 92 // Month = 6 (June) , 122 // Month = 7 (July) , 153 // Month = 8 (August) , 184 // Month = 9 (September) , 214 // Month = 10 (October) , 245 // Month = 11 (November) , 275 // Month = 12 (December) , 306 // Month = 13 (January, next year) , 337 // Month = 14 (February, next year) };
int julianDay = day + CumulativeDays[month] + 365*year + (year/4)
(153*month - 457)/5)
public static int IntegerDate(DateTime date) { int Month = date.Month; int Day = date.Day; int Year = date.Year; if (Month < 3) { Month = Month + 12; Year = Year - 1; } //modified Julian Date return Day + (153 * Month - 457) / 5 + 365 * Year + (Year / 4) - (Year / 100) + (Year / 400) - 678882; }
public static DateTime FromDateInteger(int mjd) { long a = mjd + 2468570; long b = (long)((4 * a) / 146097); a = a - ((long)((146097 * b + 3) / 4)); long c = (long)((4000 * (a + 1) / 1461001)); a = a - (long)((1461 * c) / 4) + 31; long d = (long)((80 * a) / 2447); int Day = (int)(a - (long)((2447 * d) / 80)); a = (long)(d / 11); int Month = (int)(d + 2 - 12 * a); int Year = (int)(100 * (b - 49) + c + a); return new DateTime(Year, Month, Day); }
public static DateTime FromJulianDate(double julianDate) { return DateTime.FromOADate(julianDate - 2415018.5); }
typedef struct { unsigned int8 seconds; // 0 to 59 unsigned int8 minutes; // 0 to 59 unsigned int8 hours; // 0 to 23 (24-hour time) unsigned int8 day; // 1 to 31 unsigned int8 weekday; // 0 = Sunday, 1 = Monday, etc. unsigned int8 month; // 1 to 12 unsigned int8 year; // (2)000 to (2)255 unsigned int32 julian; // Julian date } date_time_t;
void JulianTime(date_time_t * dt) { unsigned int8 m, y; y = dt->year; m = dt->month; if (m > 2) m -= 3; else { m += 9; y --; } dt->julian = ((1461 * y) / 4) + ((153 * m + 2) / 5) + dt->day; dt->weekday = ( dt->julian + 2 ) % 7; dt->julian = (dt->julian * 24) + (dt->hours ); dt->julian = (dt->julian * 60) + (dt->minutes ); dt->julian = (dt->julian * 60) + (dt->seconds ); }
void GregorianTime(date_time_t *dt) { unsigned int32 j = dt->julian; dt->seconds = j % 60; j /= 60; dt->minutes = j % 60; j /= 60; dt->hours = j % 24; j /= 24; dt->weekday = ( j + 2 ) % 7; // Get day of week dt->year = (4 * j) / 1461; j = j - ((1461 * dt->year) / 4); dt->month = (5 * j - 3) / 153; dt->day = j - (((dt->month * 153) + 3) / 5); if ( dt->month < 10 ) { dt->month += 3; } else { dt->month -= 9; dt->year ++; } }