我有一个最初是为Linux编写的程序,但我现在要求它在Solaris 10上运行。
此计划的一部分使用timegm功能将struct tm
转换为time_t
纪元秒值。输入时间以UTC为参考。
尝试在Solaris上编译此程序,它失败,因为找不到timegm
。经过一些谷歌搜索后,我意识到很久以前这个功能已经从Solaris中删除了(甚至Linux手册也建议不要使用它,因为它没有标准化)。
但是到目前为止,我还没有找到替代函数,它将struct tm
引用为UTC并转换为纪元时间。我在网上找到的大多数参考建议使用mktime,但该函数会参考系统本地时区来解释输入。
请注意,我不希望使用tzset
强制将时区强制为UTC,因为这会对程序产生其他副作用。
所以我的问题是:在没有struct tm
的情况下,如何将timegm
分解时间值(以UTC表示)转换为纪元时间?
该程序是用C ++编写的,所以我不仅限于C解决方案,尽管我不想开始批量重写以使用一些额外的时间库。
答案 0 :(得分:5)
您可以使用days_from_civil
// Returns number of days since civil 1970-01-01. Negative values indicate
// days prior to 1970-01-01.
// Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
// m is in [1, 12]
// d is in [1, last_day_of_month(y, m)]
// y is "approximately" in
// [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
// Exact range of validity is:
// [civil_from_days(numeric_limits<Int>::min()),
// civil_from_days(numeric_limits<Int>::max()-719468)]
template <class Int>
constexpr
Int
days_from_civil(Int y, unsigned m, unsigned d) noexcept
{
static_assert(std::numeric_limits<unsigned>::digits >= 18,
"This algorithm has not been ported to a 16 bit unsigned integer");
static_assert(std::numeric_limits<Int>::digits >= 20,
"This algorithm has not been ported to a 16 bit signed integer");
y -= m <= 2;
const Int era = (y >= 0 ? y : y-399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365]
const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]
return era * 146097 + static_cast<Int>(doe) - 719468;
}
tm
将tm
中的{年,月,日}三元组转换为自纪元(1970-01-01)以来的天数。从tm_year + 1900
转换这些字段时要小心它们的怪癖(例如tm
)。
将此天数乘以86400,并将timegm
中的{小时,分钟,秒}数据添加到每个(每个转换为秒数)。
你已经完成了。不要担心闰秒,{{1}}也不担心它们。如果您真的关注闰秒我有一个described here in detail,但我猜这比您想要的更多。
不要被上面显示的C ++ 14语法推迟。将此算法转换为C(或任何其他语言)是微不足道的。
答案 1 :(得分:0)
每the POSIX standard for tzset()
:
<强>概要强>
#include <time.h> extern int daylight; extern long timezone; extern char *tzname[2]; void tzset(void);
...
tzset()
函数还应设置外部变量日光 如果永远不应用夏令时转换,则为0 使用的时区;否则,非零。 外部变量timezone
应设置为之间的差异,以秒为单位 协调世界时(UTC)和当地标准时间。
您应该可以致电tzset()
来设置timezone
中的值,然后使用mktime()
获取当前时区的时间,然后应用{{1}中的差异变量到timezone
的结果,将结果转换为UTC。
我现在无法访问Solaris来测试它。