如何将ISO8601解析为time_t?

时间:2019-06-10 16:09:58

标签: c timezone locale iso8601

将ISO8601日期时间解析为time_t的正确方法是什么?

输入字符串是ISO8601日期时间的特定变体:

  

1991-02-03T04:05:06.000-07:00
  (我不必担心'Z'或隐含的本地时间变体)

我可以使用strptime()来解析小数秒,但是手册页中提到了setlocale(),所以我担心我需要为此做些事情。 我可以吗?还是仅用于月份和日期名称?

似乎没有任何方法可以跳过(或处理)strptime中的小数秒,而且我的版本似乎也无论如何都不支持'%z'(并且tm_gmtoff不是-standard),因此我无法解析“手动”输入的小数秒和时区偏移量。很容易。

所以我想我可以用strptime修改的tm_min的TZ偏移量的分钟数。 正确吗?

然后我们来到mktime()。似乎强制它在UTC中起作用的预期方式是:

  

获取TZ,清除TZ,tzset()mktime(),重置TZ,tzset()
  (有一个timegm(),但不是标准的)

我将要处理很多这样的字符串,并且我不在乎此程序中的任何其他时间,因此这似乎是很多毫无用处的开销,我可以清除TZ和{{ 1}}刚开始一次?

2 个答案:

答案 0 :(得分:2)

  

我可以使用strptime()来解析小数秒,但是手册页中提到了setlocale(),所以我担心我需要为此做些事情。我可以吗?

是的,很不幸;根据地区的不同,%S可能会消耗小数秒,并且可能会寻找小数点逗号而不是小数点。

我个人将完全手动完成此操作,并使用strtokstrtol,并填写struct tm的适当字段。您无需填写tm_ydaytm_wday即可使mktime正常工作。

  

我假设我可以用strptime修改的tm_min的TZ偏移量的分钟数。是吗?

这比看起来要难。根据时区偏移量的实际值,您将需要同时调整tm_hrtm_min(实际上,通常情况是整小时数,因此您需要调整{{1 }},而不是tm_hr),并且如果调整将时间推到一天的边界上,您将需要对小时进行归一化并确定日期,月份和年份。

还必须确保tm_mintm_isdst为零,而tm_gmtoff为NULL。

  

我可以一开始就清除一次TZ和tzset()吗?

在“预期方式”有效的系统上,可以。但是,不能保证“预期的方式”有效,实际上,如果您没有tm_zone,我希望它有效。

使用timegm。如果您没有timegm,则get it from gnulib

答案 1 :(得分:1)

结果证明,编写自己的极简主义的“不带时区废话的mktime”并不难。

let jsObj = {
	"arrow-alt-circle-down": [
		512,
		512,
		[],
		"f358",
		"M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM212 140v116h-70.9c-10.7 0-16.1 13-8.5 20.5l114.9 114.3c4.7 4.7 12.2 4.7 16.9 0l114.9-114.3c7.6-7.6 2.2-20.5-8.5-20.5H300V140c0-6.6-5.4-12-12-12h-64c-6.6 0-12 5.4-12 12z"
	],
	"other-fields": "preserved",
};

delete jsObj['arrow-alt-circle-down'];
console.log(jsObj);

因此,我将其与@zwol答案中的建议结合起来,以“手动”解析字符串,而不必处理#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); } strptime()和{{1} }的可能特质。