转换为 unix 时间戳不正确

发布于 2024-10-11 13:26:31 字数 1500 浏览 8 评论 0原文

我有一个我编写的函数(如果有一个好的标准替代品,请告诉我...)

time_t get_unix_time(string time_str) {
    time_t loctime;
    time(&loctime);

    struct tm *given_time;
    time_str = time_str.substr(0, time_str.find_first_of('.'));

    replace(time_str.begin(), time_str.end(), ':', ',');
    replace(time_str.begin(), time_str.end(), '-', ',');
    replace(time_str.begin(), time_str.end(), '/', ',');
    replace(time_str.begin(), time_str.end(), ' ', ',');

    given_time = localtime(&loctime);
    vector<string> trecord = split_string(time_str, ',');

    given_time->tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time->tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time->tm_mday = atoi(trecord.at(2).c_str());
    given_time->tm_hour = atoi(trecord.at(3).c_str());
    given_time->tm_min  = atoi(trecord.at(4).c_str());
    given_time->tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(given_time);
}

该函数的输入 (time_str) 的格式为 1970-01-01 00:00:00.0< /强>。 split_string() 函数将字符串 time_str 拆分为一个向量,其中包含:

{ 1970, 01, 01, 00, 00, 00 }

,用于填充给定_time 结构。

我编写了一个函数来测试它,并准确地传递了该输入(纪元的开始)。但是,它返回的时间是 21600,即 1970-01-01 06:00:00,或 UTC+6。预期输出为 0(纪元的开始)。

注意:我所在的时区是美国中部时区,即 UTC - 6。1970 年 1 月 1 日午夜(CST),UTC 时间为 1970 年 1 月 1 日 06:00:00。

我的函数中是否有任何内容使其特定于我的时区?我在这个函数中做错了什么吗,或者我可以做一些不同的事情来使其独立于区域,或者至少始终是 UTC。

I have a function that I wrote (if there is a good standard substitute, please let me know...)

time_t get_unix_time(string time_str) {
    time_t loctime;
    time(&loctime);

    struct tm *given_time;
    time_str = time_str.substr(0, time_str.find_first_of('.'));

    replace(time_str.begin(), time_str.end(), ':', ',');
    replace(time_str.begin(), time_str.end(), '-', ',');
    replace(time_str.begin(), time_str.end(), '/', ',');
    replace(time_str.begin(), time_str.end(), ' ', ',');

    given_time = localtime(&loctime);
    vector<string> trecord = split_string(time_str, ',');

    given_time->tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time->tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time->tm_mday = atoi(trecord.at(2).c_str());
    given_time->tm_hour = atoi(trecord.at(3).c_str());
    given_time->tm_min  = atoi(trecord.at(4).c_str());
    given_time->tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(given_time);
}

The input (time_str) to the function is of the format 1970-01-01 00:00:00.0. The split_string() function splits the string time_str into a vector containing:

{ 1970, 01, 01, 00, 00, 00 }

which is used to fill in the given_time structure.

I wrote a function to test it, and passed it exactly that input (start of epoch). However, the time it gives me back is 21600, which is 1970-01-01 06:00:00, or UTC+6. The expected output is 0 (start of the epoch).

Note: that I am in the US-Central time zone, which is UTC - 6. At midnight on 1st Jan 1970 CST, time @ UTC would be 1st Jan 1970 06:00:00.

Is there anything in my function that is making it specific to my timezone? Am I doing something wrong in this function, or can I do something different to make it zone independent, or at least always UTC.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

半边脸i 2024-10-18 13:26:31

如果您使用 glibc,则可以使用 timegm 函数,它是 mktime 的一个版本,它始终将时间解释为位于 GMT 时区。不幸的是,该函数的文档基本上指出它不能使用标准库调用来实现。所以除非你拥有它,否则你有点运气不好。

If you are using glibc you have the timegm function at your disposal, which is a version of mktime that always interprets the time as if it were in the GMT timezone. Unfortunately, the documentation for that function basically states that it cannot otherwise be implemented using standard library calls. So you're sort of out of luck unless you have it.

归属感 2024-10-18 13:26:31

mktime 采用本地时区的时间。因此,如果您传递1970-01-01 00:00:00当地时间,它会返回1970-01-01 06:00:00 UTC,因为它应该。

作为替代方案,如果您使用 glibc,则可以调用 timegm。如果您不使用 glibc,则在调用 mktime 时,可以通过修改 TZ 环境变量来临时将本地时间更改为 UTC,如 timegm 手册页中所述:

time_t my_timegm (struct tm *tm) {
    time_t ret;
    char *tz;
    tz = getenv("TZ");
    setenv("TZ", "", 1);
    tzset();
    ret = mktime(tm);
    if (tz)
        setenv("TZ", tz, 1);
    else
        unsetenv("TZ");
    tzset();
    return ret;
}

此外,您对 localtime 的调用是不必要的,您可能应该设置 given_time->tm_isdst,以避免可能的夏令时问题。

mktime takes a time in the local time zone. So, if you pass it 1970-01-01 00:00:00 local time, it returns 1970-01-01 06:00:00 UTC, as it should.

As an alternative, you can call timegm, if you're using glibc. If you're not using glibc, you temporarily change the local time to UTC when calling mktime by messing with the TZ environment variable, as described on the timegm manpage:

time_t my_timegm (struct tm *tm) {
    time_t ret;
    char *tz;
    tz = getenv("TZ");
    setenv("TZ", "", 1);
    tzset();
    ret = mktime(tm);
    if (tz)
        setenv("TZ", tz, 1);
    else
        unsetenv("TZ");
    tzset();
    return ret;
}

Also, your call to localtime is unnecessary, and you probably ought to set given_time->tm_isdst, to avoid possible daylight savings time issues.

向日葵 2024-10-18 13:26:31

也许您应该使用 gmtime 而不是 time 来摆脱时区问题。

编辑:
我真的不明白为什么你用当前时间填充结构,然后覆盖它的所有组件。为什么不只是:

time_t get_unix_time(const string& time_str)
{
    vector<string> trecord = split_string(time_str, ',');

    tm given_time;
    given_time.tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time.tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time.tm_mday = atoi(trecord.at(2).c_str());
    given_time.tm_hour = atoi(trecord.at(3).c_str());
    given_time.tm_min  = atoi(trecord.at(4).c_str());
    given_time.tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(&given_time);
}

另一个编辑:

呃,mktime也考虑当地时间。除了将时区区域设置设置为 UTC 之外,我不太确定如何解决此问题。

Maybe you should use gmtime instead of time, to rid yourself of timezone issues.

Edit:
I don't really understand why you fill the structure with the current time, then overwrite all its components. Why not just:

time_t get_unix_time(const string& time_str)
{
    vector<string> trecord = split_string(time_str, ',');

    tm given_time;
    given_time.tm_year = atoi(trecord.at(0).c_str()) - 1900;
    given_time.tm_mon  = atoi(trecord.at(1).c_str()) - 1;
    given_time.tm_mday = atoi(trecord.at(2).c_str());
    given_time.tm_hour = atoi(trecord.at(3).c_str());
    given_time.tm_min  = atoi(trecord.at(4).c_str());
    given_time.tm_sec  = atoi(trecord.at(5).c_str());

    return mktime(&given_time);
}

Another edit:

Ugh, mktime considers local time too. I'm not really sure how you can get around this other than setting your timezone locale to UTC.

固执像三岁 2024-10-18 13:26:31

只需避免这些尴尬的函数并自己进行数学计算即可。 POSIX 指定 time_t 是自“纪元”(1970-01-01 00:00:00 GMT)以来以秒为形式的算术类型,没有任何闰秒废话(所有天都是 86400 日历秒,与SI秒相差很小),因此除了一点闰年逻辑之外,计算非常简单。

像这样的日历计算是标准的入门编程练习,因此我相信您可以解决它或在网络上找到解决方案。

顺便说一句,也许 ISO C 和 POSIX 省略这样一个函数的原因是,与涉及时区的转换可以任意复杂并且只有主机的库可以在不同的应用程序之间可靠且一致地执行不同,GMT 转换是纯算术,没有外部参数。

Just avoid these awkward functions and do the math yourself. POSIX specifies that time_t is an arithmetic type in the form of seconds since "the epoch" (1970-01-01 00:00:00 GMT) without any leapsecond nonsense (all days are exactly 86400 calendar seconds, which differ from SI seconds by a tiny amount), so aside from a little leapyear logic, the computation is extremely straightforward.

Calendar calculations like this are a standard introductory programming exercise so I'm sure you can work it out or find solutions on the web.

As an aside, perhaps the reason ISO C and POSIX omit such a function is that, unlike conversions involving timezones which can be arbitrarily complex and which only the host's library can perform reliably and consistently across different applications, GMT conversions are pure arithmetic with no external parameters.

趁微风不噪 2024-10-18 13:26:31

当您调用 mktime 时,它​​会将参数解释为本地时间。
您还使用了“localtime”之类的功能,这些功能似乎没有用,我认为您可以放弃它们。

When you call mktime, it interpretes the parameter as a local time.
You have also used function like "localtime" that seems to be useless and I think you can drop them.

む无字情书 2024-10-18 13:26:31

您可以围绕 strptime 编写一个包装器来进行解析。

struct tm given_time;

strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &given_time);

return mktime(&given_time);

@Josh Kelley 的回答彻底解释了时区问题。

You could write a wrapper around strptime to do the parsing.

struct tm given_time;

strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &given_time);

return mktime(&given_time);

@Josh Kelley's answer explains the timezone issue thoroughly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文