我正在寻找确定NTP时间戳矢量的日期组件的最快方法。
在这种情况下的输入是NTP时间戳或自1900-01-01以来测量的秒数,通过添加2208988800进行和从unix时间开始往返是微不足道的,或者如果是另一种方式则减去。我需要将时间戳分解为其他API的日期组件,这些API仅接受日期作为其组件的具体年,月和日。
使用time.h
(glibc
)中的ANSI C方法,我可以很容易地推导出组件,但对于较大的向量来说,它太慢了。较小的向量可能包含172800个值,但更现实的是,我希望能够尽快使用1314000值来处理向量。
我原本以为我可以自己处理时间并通过迭代减去每个日期组件的第二除数输入的时间戳来消除少量glibc
开销,直到我到达日期,基本上是{{{ 1}}但没有时区和一些额外的(小)开销。
我很快就发现以这种方式解决它仍然很慢。
我正在使用这样的东西:
glibc
是否存在潜伏的算法可以帮助我更快地推导出计算?像Zeller的算法,但从几秒到几天的组件?
谢谢!
答案 0 :(得分:1)
鉴于您的许多连续时间戳很可能在同一个月内,请将其用于您的优势。
Pseudo code
1) Calculate the y,m,d for the given timestamp 't' as you have above.
2) now calculate the t0 = gmtime(y, m, 1) and t1 = gmtime(y, m+1, 1). (Dec + 1 is OK)
3) As long as your timestamps are t0 <= t < t1, a simple add/divide is need to determine the day of the month.
4) Should 't' fall outside the range, go to step 1.
还可以确定当天的开始和结束时间,看看是否适用于下一个时间戳。
答案 1 :(得分:1)
如果您的时间戳在1901年至2099年的日期范围内,您可以利用每四年闰年的事实(这可以进一步扩展到包括1900年以来的日期,因为它不是闰年)。
我从c library I'm working on的日期派生了此代码,但此代码中的差异我使用了Zeller's congruence中的“shift-month”方法。
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
void
dt_to_ymd(unsigned int n, int *yp, int *mp, int *dp) {
unsigned int z, c;
int y, m, d;
assert(n <= 73107); /* 2100-02-28 */
z = n + 307; /* 1 + 306 (306 days between March 1 and December 31) */
y = (4 * z) / 1461;
c = z - (1461 * y - 1) / 4; /* day of the year [1, 366] */
m = (5 * c + 456) / 153; /* month of the year [1, 12] */
d = c - (153 * m - 457) / 5; /* day of the month [1, 31] */
if (m > 12)
y++, m -= 12;
if (yp) *yp = y + 1899;
if (mp) *mp = m;
if (dp) *dp = d;
}
const struct test {
int year;
int month;
int day;
uint64_t timestamp;
} tests[] = {
{ 1900, 1, 1, 0 },
{ 1970, 1, 1, 2208988800 },
{ 1972, 1, 1, 2272060800 },
{ 1999, 12, 31, 3155587200 },
{ 2013, 7, 4, 3581884800 },
{ 2100, 2, 28, 6316444800 },
};
int
main() {
int i, ntests;
ntests = sizeof(tests) / sizeof(*tests);
for (i = 0; i < ntests; i++) {
const struct test t = tests[i];
{
unsigned int n;
int y, m, d;
n = t.timestamp / 86400;
dt_to_ymd(n, &y, &m, &d);
if (t.year != y || t.month != m || t.day != d) {
printf("dt_to_ymd(%u)\n", n);
printf(" got: %.4d-%.2d-%.2d\n", y, m, d);
printf(" exp: %.4d-%.2d-%.2d\n", t.year, t.month, t.day);
}
}
}
return 0;
}