简体   繁体   English

如何获取自C ++(MSVS)以来的本地当前时间(以秒为单位)?

[英]How to get the local current time in seconds since epoch in C++ (MSVS)?

I need the local (with timezone offset) current time in seconds since epoch. 我需要自纪元以来以秒为单位的本地(具有时区偏移)当前时间。 The following code looks a bit clumzy because it creates an intermediate temporary structure tm which is superfluous. 以下代码显得有些笨拙,因为它创建了一个多余的中间临时结构tm Why do I have to get time_t then convert it to tm in order to return to time_t ? 为什么我必须先获取time_t,然后将其转换为tm才能返回到time_t Is there a better way? 有没有更好的办法?

time_t ct = time(0);
tm lct = tm();
localtime_s(&lct, &ct);
ct = _mkgmtime(&lct);

If you want to get the local time (with time zone and DST applied) in portable C, then yes, it's generally a two-step procedure: starting with your time-since-the-epoch, first call localtime , then do something with the resulting broken-down struct tm . 如果要在便携式C中获取本地时间(应用了时区和DST),是的,通常需要执行以下两个步骤:从时间开始,首先调用localtime ,然后使用产生的分解struct tm (Usually what I do next is call strftime .) (通常,我接下来要做的就是调用strftime 。)

You can also call ctime to get a local time string directly. 您也可以调用ctime直接获取本地时间字符串。

The reason there are a lot of different function calls involved is that, unfortunately, there are several different time formats in use. 涉及许多不同的函数调用的原因是,不幸的是,使用了几种不同的时间格式。 (And the reason for that is that dates and times are complicated!) You can represent time as seconds-since-1970. (这样做的原因是日期和时间很复杂!)您可以将时间表示为从1970年开始的秒数。 You can represent it as a struct tm . 您可以将其表示为struct tm You can represent it as a string (in one of several zillion formats). 您可以将其表示为字符串(采用数百万个格式之一)。 In Unix and Linux, you can represent it as a struct timeval or a struct timespec . 在Unix和Linux中,您可以将其表示为struct timevalstruct timespec

But one thing there isn't a straightforward or standard way to do, as you've discovered, is get local time as seconds-since-1970. 但是,正如您所发现的那样,没有一种简单或标准的方法可以将本地时间设为1970年以来的秒数。 But the reason for that is that it's not a very useful representation. 但这是因为它不是一个非常有用的表示。 In general, there are two things you might want to do with a date/time value: (1) perform computations on it or (2) display it to the user. 通常,您可能需要对日期/时间值做两件事:(1)对日期/时间值执行计算,或者(2)将其显示给用户。 If you want to display it to the user, you probably want to display it in local time, so there are lots of ways of converting to local time in human-readable format in any format you want. 如果要将其显示给用户,则可能要以本地时间显示,因此有很多方法可以以任何您想要的格式以人类可读的格式转换为本地时间。 (As I said, the usual way is to call localtime , then strftime .) But if you want to perform computations, really the only way to do those is using seconds-since-1970 in UTC, because that makes all the other hairy problems go away. (就像我说的那样,通常的方法是先调用localtime ,然后调用strftime 。)但是,如果要执行计算,实际上唯一的方法是使用UTC的seconds-since-1970以来,因为这会使所有其他麻烦的问题走开。 How many days are there in the month? 一个月有几天? Is it a leap year? 是a年吗? What time zone are we in? 我们在哪个时区? Is daylight saving time in effect? 夏令时有效吗?

If you try to represent local time as seconds-since-1970, though, you're probably fibbing. 但是,如果您尝试将当地时间表示为1970年以来的秒数,则可能是摆弄。 For example, right now, the time is 1460383736, which is 14:08:56 UTC. 例如,现在的时间是1460383736,即世界标准时间14:08:56。 Where I'm sitting, that's 10:08:56 EDT (US Eastern time, DST in effect). 我坐在的时间是美国东部时间10:08:56(美国东部时间,夏令时生效)。 So I suppose I could say that's 1460369336 seconds since 1970, local time. 因此,我想可以说这是自1970年当地时间以来的1460369336秒。 But, again where I'm sitting, 1460369336 seconds ago was not midnight on January 1, 1970 -- it was actually 11 pm on December 31, 1969. It's off by an hour, and the reason is that DST was not in effect on January 1, 1970. 但是,我现在坐在的位置还是1460369336秒钟,这不是1970年1月1日午夜-实际上是1969年12月31日晚上11点。它已经关闭了一个小时,原因是DST并未生效1970年1月1日。

So, bottom line, I would encourage you to rethink the way you're handling local times, because while it's possible to compute this "seconds-since-1970 as local time" value, it's an odd thing to do, and it's likely to cause you various problems which will be much harder to work around than if you used a more straightforward scheme. 因此,最重要的是,我鼓励您重新考虑处理本地时间的方式,因为虽然可以计算“ 1970年以来的秒数作为本地时间”值,但这是一件很奇怪的事情,并且很可能导致您遇到各种问题,这比使用更直接的方案要难得多。


But, if you really want to, here are two ways you might be able to determine the offset between UTC and local time, without calling gmtime or _mkgmtime : 但是,如果您确实愿意,可以使用以下两种方法来确定UTC与本地时间之间的偏移,而无需调用gmtime_mkgmtime

  1. Call localtime , and look at the tm_gmtoff field. 调用localtime ,然后查看tm_gmtoff字段。 (Unfortunately, this field is nonstandard, and not present on all systems.) (不幸的是,该字段是非标准的,并非在所有系统上都存在。)
  2. Call the obsolete ftime function, and look at the timezone field of struct timeb . 调用过时的ftime函数,并查看struct timebtimezone字段。 (Here there are several gotchas: not only is ftime obsolete and nonstandard, but the timezone field is in minutes , and it's positive for zones west of Greenwich, while tm_gmtoff is negative.) (这里有几个陷阱:不仅ftime过时且不标准,而且timezone字段以分钟为单位 ,并且对于格林威治以西的区域为正,而tm_gmtoff为负。)

But, anyway, those would more or less directly give you the number to add to or subtract from your UTC seconds-since-1970 value to get "local" seconds-since-1970. 但是,无论如何,这些都会或多或少直接给您提供您要从1970年以来的UTC秒值中增加或减少的数字,以获得从1970年以来的“本地”秒数。

Here is a way to do this computation using the C++11/14 <chrono> library plus this free, open-source timezone library to do the conversion to local time. 这是一种使用C ++ <chrono>库以及此免费的开源时区库进行此计算的方法,以转换为本地时间。

#include "tz.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;
    auto now = floor<seconds>(system_clock::now());
    auto s = current_zone()->to_local(now) - local_days{1970_y/jan/1};
    cout << s.count() << '\n';
}

You first discover your current IANA timezone with current_zone() . 您首先使用current_zone()发现当前的IANA时区。 Then you get the current time with system_clock::now() and truncate it to seconds . 然后,使用system_clock::now()获得当前时间,并将其截断为seconds Next you can convert that to your local time, and then subtract the result from any epoch you desire (1970-01-01 in this example). 接下来,您可以将其转换为本地时间,然后从所需的任何时期中减去结果(在此示例中为1970-01-01)。

The result is of type std::chrono::seconds . 结果是std::chrono::seconds类型。

All this being said, I share the same reservations about doing this as described in Steve Summit's answer . 综上所述,我对这样做的保留与Steve Summit的回答相同

If you instead decide to represent the timestamp as a string, that is also easily done: 如果您决定将时间戳记表示为字符串,则也很容易做到:

auto now = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
auto str = format("%F %T %z", now);

str has type std::string . str类型为std::string This just output for me: 这只是为我输出:

2016-04-11 11:42:50 -0400

which is my current local time (truncated to seconds), and my current local UTC offset. 这是我当前的本地时间(以秒为单位),以及我当前的本地UTC偏移量。

If in the future you decide that seconds-precision is too coarse, you can easily change the above code to any other precision by just changing one line: 如果将来您认为秒精度太粗糙,则只需更改一行就可以轻松地将上述代码更改为其他精度:

floor<milliseconds>(system_clock::now());

and now the contents of str would look like: 现在str的内容看起来像:

2016-04-11 11:42:50.368 -0400

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM