har*_*mic 5 c++ solaris solaris-10
我有一个最初是为Linux编写的程序,但我现在要求它在Solaris 10上运行.
该程序的一部分使用timegm函数将a struct tm
转换为time_t
epoch秒值.输入时间以UTC为参考.
尝试在Solaris上编译此程序,它失败,因为timegm
找不到.经过一些谷歌搜索后,我意识到很久以前这个功能已经从Solaris中删除了(甚至Linux手册也建议不要使用它,因为它没有标准化).
但是到目前为止,我还没有找到一个替代函数,它接受struct tm
UTC参考并转换为纪元时间.我在网上找到的大多数参考建议使用mktime,但该函数会参考系统本地时区来解释输入.
请注意,我不希望使用tzset
强制时区为UTC,因为这会对程序产生其他副作用.
所以我的问题是:struct tm
在没有timegm
?的情况下,如何将一个相对于UTC表示的故障时间值转换为一个纪元时间?
该程序是用C++编写的,所以我不仅限于C解决方案,尽管我不想开始批量重写以使用一些额外的时间库.
你可以使用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;
}
Run Code Online (Sandbox Code Playgroud)
将{年,月,日}三联转换为tm
自纪元(1970-01-01)以来的天数.从转换这些字段时要小心tm
它们的偏心率(例如tm_year + 1900
).
将此天数乘以86400,并将(小时,分钟,秒)数据添加到tm
(每个转换为秒数).
而且你已经完成了.不要担心闰秒,timegm
也不要担心它们.如果你真的关心闰秒我有一个C++ 11/14解决方案可以解决这个问题,但我猜这比你想要的更多.
不要被上面显示的C++ 14语法所拖延.将此算法转换为C(或任何其他语言)是微不足道的.