将unix时间戳转换为没有系统库的日期

我正在构建一个嵌入式项目,它显示从显示器上的GPS模块检索的时间,但我还想显示当前日期。 我目前有时间作为unix时间戳,而progject是用C语言编写的。

我正在寻找一种从时间戳计算当前UTC日期的方法,考虑到闰年? 请记住,这是针对没有FPU的嵌入式项目,因此模拟浮点数学,尽可能地避免它的性能。

编辑

在看了@R …的代码之后,我决定自己写一篇文章并提出以下内容。

void calcDate(struct tm *tm) { uint32_t seconds, minutes, hours, days, year, month; uint32_t dayOfWeek; seconds = gpsGetEpoch(); /* calculate minutes */ minutes = seconds / 60; seconds -= minutes * 60; /* calculate hours */ hours = minutes / 60; minutes -= hours * 60; /* calculate days */ days = hours / 24; hours -= days * 24; /* Unix time starts in 1970 on a Thursday */ year = 1970; dayOfWeek = 4; while(1) { bool leapYear = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); uint16_t daysInYear = leapYear ? 366 : 365; if (days >= daysInYear) { dayOfWeek += leapYear ? 2 : 1; days -= daysInYear; if (dayOfWeek >= 7) dayOfWeek -= 7; ++year; } else { tm->tm_yday = days; dayOfWeek += days; dayOfWeek %= 7; /* calculate the month and day */ static const uint8_t daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; for(month = 0; month = dim) days -= dim; else break; } break; } } tm->tm_sec = seconds; tm->tm_min = minutes; tm->tm_hour = hours; tm->tm_mday = days + 1; tm->tm_mon = month; tm->tm_year = year; tm->tm_wday = dayOfWeek; } 

首先除以86400; 余数可以用来获得结果的HH:MM:SS部分。 现在,你自1970年1月1日起离开了很多天。然后,我将把它作为一个常数调整为自2000年3月1日以来的天数(可能是负数); 这是因为2000年是闰年周期的400的倍数,这使得计算使用分区已经过了多少闰年变得容易(或者至少更容易)。

我将向您介绍我的实现,而不是试图更详细地解释这一点:

http://git.musl-libc.org/cgit/musl/tree/src/time/__secs_to_tm.c?h=v0.9.15

目前尚不清楚为什么你不能使用标准库; 如果大小是个问题,那么只有代码使用的库组件会被链接,而time_tstruct tm转换将非常小,但更重要的是正确和有效。

但是,更好的问题是为什么不直接使用GPS模块中的数据? 它位于标准RMC句子的第八个字段中,几乎可以肯定由设备输出。

2011年11月25日的例子:

$ GPRMC,001225,A,2832.1834,N,08101.0536,W,12,25,251211,1.2,E,A * 03

这是mktime()的可移植实现。 它包括对您可能删除的DST的支持,以便仅减少UTC的大小。 它还可以对数据进行规范化(例如,如果您有65秒,它会增加分钟并将秒数设置为5,因此可能会有一些您不需要的开销。

它似乎比你已经达到的解决方案更复杂; 你可能想考虑是否有原因? 我或许可以将它们作为测试(在PC而不是嵌入式)上实现,并迭代大量的纪元时间值,并将结果与​​PC编译器自己的std::mktime (使用C ++将避免名称冲突,而不必改名)。 如果它们都产生相同的结果,那么根据需要使用最快/最小的实现,否则使用正确的实现!

我认为典型的库mktime执行二进制收敛,比较localtime()与目标的返回。 这比直接的日历计算效率低,但我认为这样做是为了确保从struct tmtime_t (反之亦然)的往返转换产生相同的结果。 我上面建议的可移植实现使用相同的收敛技术,但替换了localtime()以删除库依赖项。 因此,在反思时,我怀疑直接计算方法在您的情况下更可取,因为您不需要可逆性 – 只要它当然是正确的。