如何将 ISO8601 解析为 time_t?
How to parse ISO8601 into a time_t?
将 ISO8601 日期时间解析为 time_t 的正确方法是什么?
输入字符串是 ISO8601 日期时间的特定变体:
1991-02-03T04:05:06.000-07:00
(I do not need to worry about the 'Z' or implied localtime variants)
我可以使用 strptime()
来解析小数秒,但是手册页提到了 setlocale()
所以我担心我需要对此做些什么。 可以吗? 还是仅用于月份和日期名称?
似乎没有任何方法可以跳过(或处理)strptime 中的小数秒,而且我的版本似乎也不支持“%z”(而且 tm_gmtoff
是非标准的),所以我一直在解析输入的小数秒和时区偏移 'by hand'。很简单。
所以我假设我可以修改 tm_min
我从 strptime 得到的 TZ 偏移分钟数。 正确吗?
然后我们来到mktime()
。强制它在 UTC 中运行的预期方式似乎是:
get TZ, clear TZ, tzset()
, mktime()
, reset TZ, tzset()
(there is a timegm()
but is non-standard)
我要处理很多这样的字符串,我不关心这个程序中的任何其他时间处理,所以这似乎是很多毫无价值的开销,我可以清除吗TZ和tzset()
开头有过一次吗?
I can use strptime()
to parse up to the fractional seconds, but the man page mentions setlocale()
so I worry that I need to do something with that. Do I?
是的,不幸的是;根据区域设置,%S 可能会消耗小数秒,并且可能会查找小数逗号而不是小数点。
就个人而言,我会完全手动完成此操作,使用 strtok
和 strtol
,填写 struct tm
的适当字段。您不必为 mktime
填写 tm_yday
和 tm_wday
。
I assume I can just modify tm_min
I got from strptime with the number of minutes of TZ offset. Correct?
这比看起来要难。根据时区偏移量的实际值,您需要调整 tm_hr
以及 tm_min
(实际上,常见情况是整数小时,因此您需要调整 tm_hr
而不是 tm_min
),如果调整将时间推到一天的边界上,您将需要标准化小时并确定日、月和年。
您还必须确保 tm_isdst
和 tm_gmtoff
为零且 tm_zone
为 NULL。
Can I just clear TZ and tzset() once at the beginning?
在 "expected way" 工作的系统上,是的。但是,"expected way" 不能保证有效,事实上,如果您没有 timegm
,我希望它 not 有效。
使用timegm
。如果你没有 timegm
, get it from gnulib
.
事实证明,编写自己的极简主义 'mktime w/o timezone nonsense' 并不难。
#define divis(y,n) (((y) % (n)) == 0)
#define isLY(y) (divis((y),4) && (!divis((y),100) || divis((y),400)))
#define nLY(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
static int mdays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
/*
* mktime implicitly applies the local timezone, this doesn't.
* This also only works with valid values, no checking or normalizing happens.
*/
static time_t epoch (
struct tm * tm
) {
int years = tm->tm_year + 1900;
int months = tm->tm_mon;
int days = tm->tm_mday - 1;
int hours = tm->tm_hour;
int minutes = tm->tm_min;
int seconds = tm->tm_sec;
if ((months > 1) && isLY(years)) ++days;
while (months-- > 0) days += mdays[months];
days += (365 * (years - 1970)) + nLY(years);
return (time_t)((86400 * days) + (3600 * hours) + (60 * minutes) + seconds);
}
所以,我将把它与@zwol 的回答中的建议结合起来,只解析字符串 'by hand' 而不必处理 strptime()
、mktime()
和 struct tm
可能的特质。
将 ISO8601 日期时间解析为 time_t 的正确方法是什么?
输入字符串是 ISO8601 日期时间的特定变体:
1991-02-03T04:05:06.000-07:00
(I do not need to worry about the 'Z' or implied localtime variants)
我可以使用 strptime()
来解析小数秒,但是手册页提到了 setlocale()
所以我担心我需要对此做些什么。 可以吗? 还是仅用于月份和日期名称?
似乎没有任何方法可以跳过(或处理)strptime 中的小数秒,而且我的版本似乎也不支持“%z”(而且 tm_gmtoff
是非标准的),所以我一直在解析输入的小数秒和时区偏移 'by hand'。很简单。
所以我假设我可以修改 tm_min
我从 strptime 得到的 TZ 偏移分钟数。 正确吗?
然后我们来到mktime()
。强制它在 UTC 中运行的预期方式似乎是:
get TZ, clear TZ,
tzset()
,mktime()
, reset TZ,tzset()
(there is atimegm()
but is non-standard)
我要处理很多这样的字符串,我不关心这个程序中的任何其他时间处理,所以这似乎是很多毫无价值的开销,我可以清除吗TZ和tzset()
开头有过一次吗?
I can use
strptime()
to parse up to the fractional seconds, but the man page mentionssetlocale()
so I worry that I need to do something with that. Do I?
是的,不幸的是;根据区域设置,%S 可能会消耗小数秒,并且可能会查找小数逗号而不是小数点。
就个人而言,我会完全手动完成此操作,使用 strtok
和 strtol
,填写 struct tm
的适当字段。您不必为 mktime
填写 tm_yday
和 tm_wday
。
I assume I can just modify
tm_min
I got from strptime with the number of minutes of TZ offset. Correct?
这比看起来要难。根据时区偏移量的实际值,您需要调整 tm_hr
以及 tm_min
(实际上,常见情况是整数小时,因此您需要调整 tm_hr
而不是 tm_min
),如果调整将时间推到一天的边界上,您将需要标准化小时并确定日、月和年。
您还必须确保 tm_isdst
和 tm_gmtoff
为零且 tm_zone
为 NULL。
Can I just clear TZ and tzset() once at the beginning?
在 "expected way" 工作的系统上,是的。但是,"expected way" 不能保证有效,事实上,如果您没有 timegm
,我希望它 not 有效。
使用timegm
。如果你没有 timegm
, get it from gnulib
.
事实证明,编写自己的极简主义 'mktime w/o timezone nonsense' 并不难。
#define divis(y,n) (((y) % (n)) == 0)
#define isLY(y) (divis((y),4) && (!divis((y),100) || divis((y),400)))
#define nLY(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
static int mdays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
/*
* mktime implicitly applies the local timezone, this doesn't.
* This also only works with valid values, no checking or normalizing happens.
*/
static time_t epoch (
struct tm * tm
) {
int years = tm->tm_year + 1900;
int months = tm->tm_mon;
int days = tm->tm_mday - 1;
int hours = tm->tm_hour;
int minutes = tm->tm_min;
int seconds = tm->tm_sec;
if ((months > 1) && isLY(years)) ++days;
while (months-- > 0) days += mdays[months];
days += (365 * (years - 1970)) + nLY(years);
return (time_t)((86400 * days) + (3600 * hours) + (60 * minutes) + seconds);
}
所以,我将把它与@zwol 的回答中的建议结合起来,只解析字符串 'by hand' 而不必处理 strptime()
、mktime()
和 struct tm
可能的特质。