Julian Day Number

来自osdev
跳到导航 跳到搜索

任何操作系统都需要“时间”格式。 对于操作系统何时开始测量“时间的开始”,似乎没有真正的标准。 但事实上,有一个接近标准。

基本定义

天文学中有一种测量时间的方法,叫做儒略日数(Julian Day Number-JDN)。 出于历史日历系统的原因,它从UTC正午(公元前4713年1月1日)开始测量时间,并使用浮点值以天为单位测量时间。 因为它是一种标准,所以有代码可用于将JDN转换为日历日期。

在任何情况下,一旦从任何自定义时间格式中划分出秒和秒的分数,就剩下“天”。 这意味着你的数字和儒略日数字之间的差异只是一个一天内的偏差。 当然,也就可以可以截断JDN,并将其用作整数。

日期计算

公元2000年的JDN为2451545。 如果你假装有一个“公元前0年”(或者说公元前1年),那么那一年的1月1日就是JDN 1721060。

计算(标准)公历日期:400年正好有146097天。

计算闰年:如果一年是4的倍数,那么它就是闰年,除非它恰好是一个新世纪,不能除以400。

代码示例

uint32_t days2years[401];

#define LEAP_FLAG		0x80000000

//days2years表涵盖400年,包括:
//1)年初的天数
//2)“世纪”(year/100)向上移动了24位
//3)闰年标志
void BuildDaysTbl()
{
	int i;
	int j = 0;
	uint32_t days = 366;
	days2years[0] = LEAP_FLAG;
	while (days < 0x40000000)
	{
		i = 24;
		while (--i >= 0)
		{
			days2years[++j] = days;
			days += 365;
			days2years[++j] = days;
			days += 365;
			days2years[++j] = days;
			days += 365;
			days2years[++j] = days | LEAP_FLAG;
			days += 366;
		}
		days2years[++j] = days;
		days += 365;
		days2years[++j] = days;
		days += 365;
		days2years[++j] = days;
		days += 365 + 0x10000000;
		days2years[++j] = days;
		days += 365;
	}
}


//将儒略日转换为公历年,并带有“余数”和闰年标志
// outputs: *doy = day of year (jan 1 = 0) with leapyear flag, *cent = century AD
uint32_t JDN_to_GregYear(uint32_t jdn, uint16_t *doy, uint32_t *cent)
{
	uint32_t greg_yr = 0;
	uint32_t qcen, temp, temp2;

	temp -= 1721060;			// make temp align with jan1, "year 0" quadcentury boundary
	qcen = temp / 146097;		// 400 years contain 146097 days
	temp %= 146097;				// get the remainder days within the 400 yr span
	temp2 = temp;				// save a copy
	// do an approximate conversion to years -- sometimes one too low
	if (temp > 73048)			// calculation for years 200 to 399
	{
		temp -= 73048;			// this shifts the calculation by 1 day
		greg_yr= 200;
	}
	greg_yr += (temp << 10) / 374014;	// 374014 is a magic number

	if ((days2years[greg_yr + 1] & 0xfffffff) <= temp2)	// fix if greg_yr is off by 1
		++greg_yr;
	temp = days2years[greg_yr];
	*doy = (uint16_t) (temp2 - (temp & 0xfffffff));
	*cent = ((temp & 0x30000000) >> 24) + qcen * 4;
	if ((int32_t) temp < 0)
		*doy |= 0x8000;		// set the leapyear flag on "day of year"

	return greg_yr;
}


// convert Jan 1 of a Gregorian year to a Julian day #
// "sign" bit of the return value is set on a leap year
uint32_t GregYear_to_JDN(uint32_t greg_yr)
{
	uint32_t jdn = (greg_yr / 400) * 146097;	// convert quadcenturies to days
	uint32_t temp = greg_yr % 400;
	// add in the days from the remaining years, and adjust jan1, "year 0" to actual JDN
	jdn += (days2years[temp] & 0xfffffff) + 1721060;
	jdn |= days2years[temp] & 0x80000000;		// copy the leap year bit
	return jdn;
}

另见

文章

外部链接