UTC时间转换为GPS week和GPS秒

UTC时间采用国际原子时守时,其精度非常之高,但是由地球自转的天文测量得到的“世界时”越来越慢,所以需要“修改”UTC时间,使其与“世界时”同步。
而GPS时间(GPST)是GPS系统内部所采用的时间系统,时间零点定义为1980年1月5日夜晚与1980年1月6日凌晨之间0点,GPS时间也采用原子时进行守时,GPS week即从时间零点开始经过的周数,GPS秒即本GPS周开始后进过的秒数。
UTC时间和GPS时间,他们的时间起点不同,且UTC时间是为了与世界时通过而经过调整的,所以UTC时间是更慢,GPS时间是更快的,UTC 时间+leap second = GPS时间。

将UTC时间转换为GPS时间有两种方法:
1.基本思路计算出总共的秒数,然后通过计算总秒数包含了多少整年,整年减掉后取余,计算年内多少整月,依次类推就可以计算出最后utc时刻的年月日时分秒.毫秒值了。
转换过程中需要主要的年中的闰年处理,还有GPS时与utc时的闰秒问题,如果是转换为北京时间要求时区的问题需要考虑。
2.将UTC时间转换为儒略日,GPS的起始时间是1980.1.6 00:00:00,对应的儒略日是2444244.5, 将UTC的儒略日减去2444244.5即当前时间相对于1980.1.6. 00:00:00的儒略日天数差,一周是7天,这样很方便的将儒略日转为周内秒 。

本文介绍的方法是基于第二种:
1.0版本

typedef struct GPST_ST
{
	int wn;//GPS 周
	long sn;//GPS 秒
	double tos;
}GPST_ST;

typedef struct JULIANDAY_ST
{
	long day;
	long sn;
	double tos;
}JULIANDAY_ST;

void utc_to_julianday(struct tm * utc_time,  JULIANDAY_ST*pjd)
{
	double ut;
	if(utc_time->tm_year < 1900)
	{
		if(utc_time->tm_year < 80)
			utc_time->tm_year += 2000;
		else
			utc_time->tm_year += 1900;
	}
	utc_time->tm_mon = utc_time->tm_year + 1;
	ut = utc_time->tm_hour + utc_time->tm_min/60.0 + utc_time->tm_sec/3600.0
	if(utc_time->tm_mon <=2)
	{
		utc_time->tm_year -=1;
		utc_time->tm_mon+=12;		
    }
    //这种算法有问题,没有处理进位,但是当秒数达到一天要进位的时候,day值却归零了   
   pjd->day = (int)(365.25*(utc_time->tm_year + 4712)) - (int)(utc_time->tm_year/100) + (int)(utc_time->tm_year/400) + int(30.61*(utc_time->tm_mon+1) + utc_time->tm_mday - 61.5);
    pjd->sn = ((utc_time->tm_hour + 12)%24)*3600 + utc_time->tm_min*60 + (int)utc_time->tm_sec;
    pjd->tos = utc_time->tm_sec - (int)utc_time->tm_sec;
}

void julianday_to_gpstime( JULIANDAY_ST*pjd, GPST_ST *pgt)
{
		long day = pjd->day;
		long sn = pjd->sn;
		double tos = pjd->tos;
		double x = day + (sn + tos)/(60.0*60.0*24);
		pgt->wn = (int)((x-2444244.5)/7);
		//在这里加跳秒是有问题的,因为加了跳秒不会进位
		pgt->sn = (int)((((double)day - 2444244.5) - (double)pgt->wn*7)*86400)+sn+18;
		pgt->tos = tos;	
}

void utc_to_gps(struct tm* utcTime, GPST_ST *pgt)
{
JULIANDAY_ST pjd;
memset(&pjd, 0, sizeof(pjd));
utc_to_julianday(utcTime, &pjd);
julianday_to_gpstime(&pjd, pgt);
}

2.0版本

typedef struct GPST_ST
{
	int wn;//GPS 周
	long sn;//GPS 秒
	double tos;
}GPST_ST;

typedef struct JULIANDAY_ST
{
	long day;
	long sn;
	double tos;
}JULIANDAY_ST;

void utc_to_julianday(struct tm * utc_time,  JULIANDAY_ST*pjd)
{
	double ut;
	if(utc_time->tm_year < 1900)
	{
		if(utc_time->tm_year < 80)
			utc_time->tm_year += 2000;
		else
			utc_time->tm_year += 1900;
	}
	utc_time->tm_mon = utc_time->tm_year + 1;
	ut = utc_time->tm_hour + utc_time->tm_min/60.0 + utc_time->tm_sec/3600.0
	if(utc_time->tm_mon <=2)
	{
		utc_time->tm_year -=1;
		utc_time->tm_mon+=12;		
    }
    //这种算法有问题,没有处理进位
    // pjd->day = (int)(365.25*(utc_time->tm_year + 4712)) - (int)(utc_time->tm_year/100) + (int)(utc_time->tm_year/400) + int(30.61*(utc_time->tm_mon+1) + utc_time->tm_mday - 61.5);
    //这个公式跟上述公式是等价的,1720981.5是将上述的公式的常量值加减后的结果,但是这个值只有在这100年时这个值,因为year/100 + year/400后得到的值在2300年就会发生变化,那再使用1720981.5就不正确的了,另外30.6001的精度和30.61也差不多,不知道这二者不同带来啥影响。
    pjd->day = (int)(365.25*(utc_time->tm_year) + (int)(30.6001*(utc_time->tm_mon+1))+utc_time->tm_mday + (int)(ut/24+1720981.5)
    pjd->sn = ((utc_time->tm_hour + 12)%24)*3600 + utc_time->tm_min*60 + (int)utc_time->tm_sec;
    pjd->tos = utc_time->tm_sec - (int)utc_time->tm_sec;
}

void julianday_to_gpstime( JULIANDAY_ST*pjd, GPST_ST *pgt)
{
		long day = pjd->day;
		long sn = pjd->sn;
		double tos = pjd->tos;
		double x = day + (sn + tos)/(60.0*60.0*24);
		pgt->wn = (int)((x-2444244.5)/7);
		pgt->sn = (int)((((double)day - 2444244.5) - (double)pgt->wn*7)*86400)+sn;
		pgt->tos = tos;	
}

void utc_to_gps(struct tm* utcTime, GPST_ST *pgt)
{
JULIANDAY_ST pjd;
memset(&pjd, 0, sizeof(pjd));
//处理跳秒值,将当前utc时间加上跳秒值,并处理进位的问题,进位主要是大小月以及闰年问题,并且注意月和年的处理。
datetime_add_sec(utcTime, LEAP_SECOND);
utc_to_julianday(utcTime, &pjd);
julianday_to_gpstime(&pjd, pgt);
}

加跳秒算法
https://blog.csdn.net/m0_37141848/article/details/118785220?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2-118785220-blog-122755831.pc_relevant_multi_platform_whitelistv1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2-118785220-blog-122755831.pc_relevant_multi_platform_whitelistv1&utm_relevant_index=5
闰年算法
http://c.biancheng.net/view/575.html

UTC时间转儒略日参考文档:
https://blog.csdn.net/qq_24172609/article/details/112244135

可以使用以下网址进行验证:
https://ytliu0.github.io/ChineseCalendar/Julian_simp.html
https://labsat.cn/index.php/cn/products-cn/9-customers/252-calculators-cn
http://leapsecond.com/java/gpsclock.htm

你可能感兴趣的:(服务器,linux,网络)