【问题标题】:Alternative to timegm on SolarisSolaris 上 timegm 的替代方案
【发布时间】:2016-12-01 06:45:52
【问题描述】:

我有一个最初是为 Linux 编写的程序,但我现在需要让它在 Solaris 10 上运行。

该程序的一部分使用timegm 函数将struct tm 转换为time_t 纪元秒值。输入时间参考 UTC。

试图在 Solaris 上编译这个程序,它失败了,因为找不到timegm。经过一番谷歌搜索后,我意识到这个功能很久以前就从 Solaris 中删除了(甚至 Linux 手册页都建议不要使用它,因为它不是标准化的)。

但是到目前为止,我还没有找到一个替代函数,它需要一个引用 UTC 的 struct tm 并转换为纪元时间。我在网上找到的大多数参考资料都推荐使用mktime,但是该函数会参考系统本地时区来解释输入。

请注意,我不希望使用 tzset 将时区强制为 UTC,因为这会对程序产生其他副作用。

所以我的问题是:在没有timegm 的情况下,如何将struct tm 分解的时间值(以UTC 表示)转换为纪元时间?

该程序是用 C++ 编写的,因此我不限于 C 解决方案,尽管我不希望进行大规模重写以使用一些额外的时间库。

【问题讨论】:

标签: c++ solaris solaris-10


【解决方案1】:

您可以使用days_from_civil,即described here in detail

// 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 中的 {year,month,day} 三元组转换为自纪元 (1970-01-01) 以来的天数。从tm 转换这些字段时要小心,因为它们的怪癖(例如tm_year + 1900)。

将此天数乘以 86400,然后加上来自 tm 的 {hours, minutes, seconds} 数据(每个都转换为秒)。

你就完成了。不要担心闰秒,timegm 也不担心它们。如果您真的关心闰秒,我有一个C++11/14 solution available to deal with that,但我猜这比您想了解的要多。

不要被上面显示的 C++14 语法吓到。将此算法转换为 C(或任何其他语言)是微不足道的。

【讨论】:

  • 不错的一个。你的那个日期算法页面是一个很棒的资源
【解决方案2】:

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() 获取当前时区的时间,然后将timezone 变量中的差异应用于结果mktime() 将该结果转换为 UTC。

我现在无法访问 Solaris 来测试它。

【讨论】:

  • 谢谢。我已经想到了,但是 UTC 和本地时间之间的差异不是恒定的,它取决于转换的时间。例如,如果我将时区中的 '2016-12-01 10:00' 转换为 UTC,由于夏令时,差异将不同于 '2016-06-01 10:00'。
猜你喜欢
  • 2015-06-13
  • 2011-04-04
  • 2019-04-22
  • 2018-08-07
  • 2017-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多