替代Solaris上的timegm

时间:2016-12-01 06:45:53

标签: c++ solaris solaris-10

我有一个最初是为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解决方案,尽管我不想开始批量重写以使用一些额外的时间库。

2 个答案:

答案 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来测试它。