【问题标题】:convert from struct tm to std::time_t and convert back date will be changed从 struct tm 转换为 std::time_t 并转换回日期将被更改
【发布时间】:2021-07-21 11:10:43
【问题描述】:

我尝试从 struct tm 转换为 std::time_t 使用以下示例代码:

void test_time_t() {
    tm time;
    time.tm_year = 2004-1900;
    time.tm_mon = 11;
    time.tm_mday = 5;
    time.tm_hour = 12;
    time.tm_min = 2;
    char buff[25];
    strftime(buff, 20, "%Y %b %d %H:%M",&time);
    printf("%s\n",buff);
    auto t = std::mktime(&time);
    struct tm *tmp = localtime(&t);
    strftime(buff, 20, "%Y %b %d %H:%M",tmp);
    printf("%s\n",buff);
}

这将输出:

2004 Dec 05 12:02
2005 Jun 16 22:41

日期改变了,谁能告诉我我在这里做错了什么? 我认为时区不会导致日期如此不同

【问题讨论】:

  • 无法重现online,我的代码显示可能是时区造成的。
  • 那些structs 不应该在那里,并将声明tm tm; 重命名为其他名称。
  • @prehistoricpenguin 来自你的在线代码,我得到以下结果:2004 Dec 05 12:02 1969 Dec 31 23:59
  • 地狱时区添加六个月。这是为了什么,火星?
  • @Casey 我尝试删除 struct 并将 tm 重命名为 time ,在我的机器上结果相同

标签: c++ time


【解决方案1】:

你需要初始化你的time:

tm time{}; // zero-initialized

我只是忘记了 tm 是一个 C 结构。

这很常见。但是,您可以继承 std::tm 并在代码中使用您自己的类型。

struct tm_ext : std::tm {
    tm_ext() : std::tm{} {}; // zero initialize on default construction
};

您现在可以使用tm_ext 而不会错过初始化:

tm_ext time; // now fine

当您使用它时,您甚至可以为其添加一些其他便利功能。

struct tm_ext : std::tm {

    tm_ext() : std::tm{} {}; // zero initialize on default construction

    explicit tm_ext(int year, int mon = 1, int mday = 1, int hour = 0,
           int min = 0, int sec = 0, int isdst = 0) :
        tm_ext() // delegate to default constructor
    {
        tm_year = year - 1900;
        tm_mon = mon - 1;
        tm_mday = mday;
        tm_hour = hour;
        tm_min = min;
        tm_sec = sec;
        // A negative value of tm_isdst causes mktime to attempt to determine if
        // Daylight Saving Time was in effect.
        tm_isdst = isdst;

        errno = 0;
        if(std::mktime(this) == -1 && errno != 0) {
            throw std::runtime_error("mktime failed");
        }
    }

    tm_ext(const std::tm& t) : std::tm(t) {} // conversion ctor

    operator std::time_t () const { // implicit conversion to time_t
        tm_ext copy(*this);
        errno = 0;
        return std::mktime(&copy);
    }

    // implicit conversion to a pointer - perhaps an exaggeration
    operator const tm_ext* () const { return this; }

    bool set_localtime(const std::time_t& t) {
        std::tm* tmp = std::localtime(&t);
        if(not tmp) return false;
        *this = *tmp;
        return true;
    }

    bool set_utc(const std::time_t& t) {
        std::tm* tmp = std::gmtime(&t);
        if(not tmp) return false;
        *this = *tmp;
        return true;
    }
};

并使用它:

void test_time_t() {
    tm_ext time(2004, 12, 5, 12, 2); // use real world values
    
    char buff[25];
    // implicit conversion to a   const tm_ext*  below:
    strftime(buff, 20, "%Y %b %d %H:%M", time);
    printf("%s\n",buff);
    
    std::time_t t = time; // implicit conversion from tm_ext to time_t

    tm_ext tmp;
    if(tmp.set_localtime(t)) std::cout << "successfully set localtime\n";

    // implicit conversion to a   const tm_ext*  below:
    strftime(buff, 20, "%Y %b %d %H:%M", tmp);

    printf("%s\n",buff);
}

不过,在过火之前,不妨先看看 Howard Hinnant 的 date.h

【讨论】:

  • 我只是忘了tm是一个C结构。
  • @prehistoricpenguin 轻松搞定。我添加了一些关于如何处理的想法。
  • @TedLyngmo 太酷了。只是提到 boost DateTime 是一个相关的库,供来这里的人可能喜欢使用。
  • @prehistoricpenguin 是的,还有 Howard Hinnant 的 date.h - 在摆弄这个时应该强制添加一个链接 - 但我忘了:-)
  • 注意:如果您的编译器是最新的并支持 2020 C++ 标准修订版,那么 date.h 几乎内置于 &lt;chrono&gt; 库中。
猜你喜欢
  • 2015-05-06
  • 2018-06-04
  • 2019-04-12
  • 1970-01-01
  • 2015-09-09
  • 2016-11-01
  • 2014-02-02
  • 2016-05-23
  • 2012-06-22
相关资源
最近更新 更多