使用C++获取Unix时间戳

105

如何在C++中获取uint的Unix时间戳?我已经搜索了一些资料,似乎大多数方法都在寻找更加复杂的时间表示方式。我是否可以直接获得它作为一个uint

8个回答

143

C++20引入了一个保证:time_since_epoch是相对于UNIX纪元的,cppreference.com提供了一个示例代码,我已经提取出相关的代码并将单位更改为秒而不是小时:

#include <iostream>
#include <chrono>
 
int main()
{
    const auto p1 = std::chrono::system_clock::now();
 
    std::cout << "seconds since epoch: "
              << std::chrono::duration_cast<std::chrono::seconds>(
                   p1.time_since_epoch()).count() << '\n';
}

如果使用C++17或更早版本,time()是最简单的函数——返回自纪元(Epoch)以来的秒数,对于Linux和UNIX至少是UNIX纪元。这里是Linux manpage

上面链接的cppreference页面给出了如下示例

#include <ctime>
#include <iostream>
 
int main()
{
    std::time_t result = std::time(nullptr);
    std::cout << std::asctime(std::localtime(&result))
              << result << " seconds since the Epoch\n";
}

6
“Epoch”指的是Unix和Linux系统上的Unix纪元,但这并不是普遍适用的。 - MSalters
2
请注意,std::chrono::seconds 的定义duration</*至少35位有符号整数类型*/>。因此,例如32位int可能不足够。 - Paul
请将c++20更改为c++11。 - socketpair
@socketpair:你有任何支持这个变更的文档吗? - Tony Delroy
是的,通过您提供的链接 - cppreference。请注意,该函数自C++11起得到支持。 - undefined
2
@socketpair:该函数自C++11开始支持,但最初与一个未指定的纪元相关(cppreference只是说“时钟的纪元”)。自C++20开始,它被要求与UNIX纪元相关(1970年1月1日UTC 0时)。这个区别在cppreference页面上没有讨论。 - undefined

54
#include <iostream>
#include <ctime>

int main()
{
    std::time_t t = std::time(0);  // t is an integer type
    std::cout << t << " seconds since 01-Jan-1970\n";
    return 0;
}

4
假设std::time()函数返回的是自1970年以来的秒数,这在许多系统(例如POSIX和Windows)上是正确的,但这并不受语言标准的保证。 - Keith Thompson

19

最常见的建议是错误的,你不能仅仅依靠time()。它用于相对时间计算:ISO C++没有规定1970-01-01T00:00Ztime_t(0)

更糟糕的是,你也无法轻松地弄清楚它。当然,你可以使用gmtime找到time_t(0)的日期,但如果那是2000-01-01T00:00Z怎么办?1970-01-01T00:00Z2000-01-01T00:00Z之间有多少秒钟?由于闰秒,它肯定不是60的倍数。


1
在C++中如何获取一个uint Unix时间戳?正如你所说,无论参考日期或适用于间隔计算,你可以稍后调用gmtime()来获取该时间戳所编码的可读表示形式,但问题中请求的功能并不满足time()的要求。 - Tony Delroy
3
要在非UNIX系统上获取UNIX时间戳,您需要知道本地纪元与1970-01-01T00:00Z之间的差异(以秒为单位)。没有可执行此操作的方法。 - MSalters
由于某种原因,我认为这个问题是关于UNIX(或Linux等)机器上的代码,但现在我知道你的意思了。好奇的是:你有没有找到任何实际系统,其中time_t(0)不是1970-01-01T00:00Z?在任何给定的系统上计算出偏移量只需要几分钟的工作时间(将非UNIX time_t(0)获取一个UNIX系统上的time_t),但感谢您解释您的担忧。 - Tony Delroy
7
对于 Visual Studio 来说,它使用的是 UNIX 时间;MSDN(Microsoft Developer Network)解释道:time 函数返回自 1970 年 1 月 1 日零点以来(协调世界时 UTC),根据系统时钟经过的秒数。http://msdn.microsoft.com/en-us/library/1f4c8f33.aspx - Oliver Zendel
2
@TonyD:IBM系统显然是个例外。这并不奇怪,因为他们在1970年之前就已经从事计算机业务了。 - MSalters

13

由于这是谷歌上的第一个结果,并且还没有C++20的答案,因此以下是如何使用std::chrono进行此操作的:

#include <chrono>

//...

using namespace std::chrono;
int64_t timestamp = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();

在 C++ 20 版本之前,system_clock 的时代被视为 Unix 时代是一种事实约定,但它并没有标准化。如果你不使用 C++20,请自行承担风险。


5
C++20正式承认这个时代:http://eel.is/c++draft/time.clock.system.overview - Howard Hinnant

10

我创建了一个包含更多信息的全局定义:

#include <iostream>
#include <ctime>
#include <iomanip>
    
#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)    // only show filename and not it's path (less clutter)
#define INFO std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [INFO] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
#define ERROR std::cout << std::put_time(std::localtime(&time_now), "%y-%m-%d %OH:%OM:%OS") << " [ERROR] " << __FILENAME__ << "(" << __FUNCTION__ << ":" << __LINE__ << ") >> "
    
static std::time_t time_now = std::time(nullptr);

使用方法如下:

INFO << "Hello world" << std::endl;
ERROR << "Goodbye world" << std::endl;

示例输出:

16-06-23 21:33:19 [INFO] main.cpp(main:6) >> Hello world
16-06-23 21:33:19 [ERROR] main.cpp(main:7) >> Goodbye world

把这些代码放在你的头文件中。我觉得这非常有用,可以用于调试等方面。

为什么要使用 #define 而不是函数?函数更加灵活,可以重载,而且使用也更加明显…… - Troyseph
4
因为这样,__FILE__``__FUNCTION__``__LINE__ 的作用将无法实现。这是一个宏。 - xinthose
1
好的!可惜没有更现代化的替代方案 =] - Troyseph
2
为了节省一些工作量,您可以使用“%F %T”来替换“%y-%m-%d %OH:%OM:%OS”。 - Zhang

9
#include <iostream>
#include <sys/time.h>

using namespace std;

int main ()
{
  unsigned long int sec= time(NULL);
  cout<<sec<<endl;
}

time() 返回一个 time_t 类型的结果,原则上可以是有符号、无符号或浮点类型。为什么要将结果存储在 long int 中?而且为什么要使用 <sys/time.h> 而不是标准的 <time.h> - Keith Thompson
我理解,但我认为在任何符合posix标准的操作系统中,都会存在time.h和sys/time.h。此外,您完全正确,因为time_t表示从1970-01-01T00:00Z开始经过的秒数,所以它也可以是负值。 - anijhaw

5

你正在引用一个叫做“文件时间”的变量,它与“系统时间”有所不同处理。 - AntonK

0
这对我来说没问题,只需将纳秒转换为你喜欢的单位,将uint64_t转换为你喜欢的类型即可。
#include <chrono>
uint64_t unix_time()
{
    return std::chrono::duration_cast<std::chrono::nanoseconds>
    (
        std::chrono::system_clock::now().time_since_epoch()
    ).count();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接