如何在C ++中获取当前时间和日期?

634

是否有一种跨平台的方法来在C++中获取当前日期和时间?


3
如果Ockonal仍在活跃,他应该将接受的答案更改为C++11方法。这个问题似乎仍然有很多人查看。 - JSQuareD
2
C语言版本:https://dev59.com/EHM_5IYBdhLWcg3wSBEU - Ciro Santilli OurBigBook.com
3
即使经过这么长时间后再看这个问题,我仍然认为使用 C 中的 tm 结构更好。C++11 方法只返回自 Unix 纪元以来的时间戳,而问题是如何获取日期和时间。 - Snackoverflow
5
哇,这个问题已经有 1,110,886 次浏览了!人们真的很喜欢 C++! - User123
4
不,他们只是讨厌::std::chrono。它是难以理解的胡言乱语。 - Yttrill
26个回答

890
自从 C++11,您可以使用 std::chrono::system_clock::now()
例如 (复制自 en.cppreference.com):
#include <iostream>
#include <chrono>
#include <ctime>    

int main()
{
    auto start = std::chrono::system_clock::now();
    // Some computation here
    auto end = std::chrono::system_clock::now();
 
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::time_t end_time = std::chrono::system_clock::to_time_t(end);
 
    std::cout << "finished computation at " << std::ctime(&end_time)
              << "elapsed time: " << elapsed_seconds.count() << "s"
              << std::endl;
}

这应该打印出类似于这样的内容:
finished computation at Mon Oct  2 00:59:08 2017
elapsed time: 1.88232s

40
应该给这个点赞,因为这是当前C++中最便携和简单的方法。 - Johannes
5
@Johannes,我刚刚添加了我的答案。按这个速度,到2017年8月15日16:31 UTC,这将成为最佳答案 :-) - user325117
72
没有使用获得的值的示例,这个回答的用处非常有限。例如,如何打印它、获取本地时间、与其他日期/时间进行比较? - Steed
40
这是最糟糕的答案。它使其他关于C++11的回答变得重复,但又没有解释任何内容,只是一个“仅链接”的答案。 - v010dya
11
没有比这个答案更直接的方式了。OP问:“是否有一种跨平台的方法在C++中获取当前日期和时间?”这个问题恰好给出了答案。如果您对如何从“ stream”获取string,或如何正确格式化time_point<>感到困惑,请继续提出另一个问题或在谷歌上搜索它。 - Tarc
显示剩余7条评论

542

C++与C共享其日期/时间函数。对于C++程序员来说,tm结构可能是最容易使用的 - 以下代码打印出今天的日期:

#include <ctime>
#include <iostream>

int main() {
    std::time_t t = std::time(0);   // get time now
    std::tm* now = std::localtime(&t);
    std::cout << (now->tm_year + 1900) << '-' 
         << (now->tm_mon + 1) << '-'
         <<  now->tm_mday
         << "\n";
}

28
如果您想要一个日期字符串,请结合使用ctime()和这个答案。 - ralphtheninja
3
删除 struct tm 实例,直接调用 delete 可行吗? - Petr
5
你只需要对使用 new 分配的内存调用 delete。 - iheanyi
5
好的,但是你仍然从localtime()函数得到一个指针,那么结构体实例是在堆上分配还是没有?这意味着除非你以某种方式清除它,否则它不会被清除。我从来没有说要使用 delete(C++关键字)删除它,我只是认为它应该以某种方式被删除 :) 或者谁将为您执行此操作? - Petr
9
@Petr,你不需要释放它,因为它是静态分配的,请参考这个主题的链接:https://dev59.com/BGoy5IYBdhLWcg3wN7i8。 - Brandin
显示剩余10条评论

222
您可以尝试以下跨平台代码来获取当前日期/时间:
#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>

// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string currentDateTime() {
    time_t     now = time(0);
    struct tm  tstruct;
    char       buf[80];
    tstruct = *localtime(&now);
    // Visit http://en.cppreference.com/w/cpp/chrono/c/strftime
    // for more information about date/time format
    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);

    return buf;
}

int main() {
    std::cout << "currentDateTime()=" << currentDateTime() << std::endl;
    getchar();  // wait for keyboard input
}

输出:

currentDateTime()=2012-05-06.21:47:59

请访问此处了解有关日期/时间格式的更多信息。


你好。我在函数“currentDateTime()”内部使用“buf”分配有一个小问题。这个变量在函数返回后该如何保留?谢谢。 - Léa Massiot
9
返回类型是“const std::string”,因此它通过值返回,然后复制缓冲区的副本,再释放它。 - barranquero
5
为什么要返回const值?这是没有意义的。 - Lightness Races in Orbit
跨平台解决方案加1! - Ziagl
现在,localtime已经被弃用,取而代之的是localtime_s,其语法在不同的C实现中有所不同。微软的版本如下:errno_t err = localtime_s(&tstruct, &now); - Antony Hatchkins

142

标准C库提供了time()函数。该函数返回自纪元以来的秒数,可以使用标准C函数将其转换为日期和H:M:S格式。此外,Boost还提供了一个时间/日期库可供参考。

time_t  timev;
time(&timev);

24
下面anon的回答结构更好,提供了一个更好的例子。 - Maxwell175
4
他问的是C++而不是C。请注意区分。 - jterm
4
没问题,C 和 C++ 共享完全相同的时间库,只是导入名称不同,仅此而已。 - Joseph Farah

50

一个老问题的新回答:

这个问题没有指定时区。有两种合理的可能性:

  1. 在协调世界时 (UTC)。
  2. 在计算机本地时区。

对于第一种情况,您可以使用这个日期库和下面的程序:

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

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << system_clock::now() << '\n';
}

它只是为我输出了:

2015-08-18 22:08:18.944211

日期库本质上只是为 std::chrono::system_clock::time_point 添加了一个流操作符。它还添加了许多其他很好的功能,但在这个简单的程序中没有使用。

如果您喜欢2(本地时间),那么有一个基于 日期库 构建的 时区库。这两个库都是开源的跨平台的,假设编译器支持C++11或C++14。

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

int
main()
{
    using namespace date;
    using namespace std::chrono;
    auto local = make_zoned(current_zone(), system_clock::now());
    std::cout << local << '\n';
}

对我来说只是输出:

2015-08-18 18:08:18.944211 EDT
make_zoned( date::current_zone(), std::chrono::system_clock::now())的结果类型是date::zoned_time,它是一个date::time_zone和一个std::chrono::system_clock::time_point的配对。这个配对表示本地时间,但根据您查询它的方式,也可以表示UTC。

根据上面的输出,您可以看到我的电脑当前位于一个UTC偏移量为-4小时,缩写为EDT的时区。

如果需要使用其他时区,也可以实现。例如,要查找澳大利亚悉尼的当前时间,只需更改变量local的构造方式:

auto local = make_zoned("Australia/Sydney", system_clock::now());

输出结果变为:

2015-08-19 08:08:18.944211 AEST

针对C++20的更新

此库现在已经广泛应用于C++20。命名空间date已经消失,现在所有内容都在命名空间std::chrono中。使用zoned_time代替make_time。删除头文件"date.h""tz.h",只需使用<chrono>

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    auto local = zoned_time{current_zone(), system_clock::now()};
    std::cout << local << '\n';  // 2021-05-03 15:02:44.130182 EDT
}

当我写下这段话时,一些平台上的部分实现才刚刚开始出现。


localtime 不应该给我返回我的时区时间吗? - Jonathan Mee
是的,localtime 函数几乎总是以秒为精度提供本地时区的时间。但有时由于线程安全问题会失败,并且它永远无法提供亚秒级别的精度。 - Howard Hinnant
1
如果您能提供UTC的更新,那将非常棒。因为明显的std::cout << std::chrono::system_clock::now();会失败。 - 463035818_is_not_a_number
显而易见的应该可以工作。也许你的std::lib供应商还没有实现它?http://eel.is/c++draft/time.clock.system.nonmembers#lib:operator%3c%3c,sys_time - Howard Hinnant
我尝试使用gnu++20,但出现了以下错误:“error: ‘zoned_time’ was not declared in this scope” - q0987
这里是gcc实现C++20库特性的状态:https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2020 - Howard Hinnant

31

C++标准库没有提供适当的日期类型。C++从C继承了日期和时间操作的结构体和函数,以及一些考虑本地化的日期/时间输入输出函数。

// Current date/time based on current system
time_t now = time(0);

// Convert now to tm struct for local timezone
tm* localtm = localtime(&now);
cout << "The local date and time is: " << asctime(localtm) << endl;

// Convert now to tm struct for UTC
tm* gmtm = gmtime(&now);
if (gmtm != NULL) {
cout << "The UTC date and time is: " << asctime(gmtm) << endl;
}
else {
cerr << "Failed to get the UTC date and time" << endl;
return EXIT_FAILURE;
}

25
auto time = std::time(nullptr);
std::cout << std::put_time(std::localtime(&time), "%F %T%z"); // ISO 8601 format.

使用std::time()std::chrono::system_clock::now()(或其他clock type)获取当前时间。

std::put_time()(C++11)和strftime()(C)提供了许多格式化程序来输出这些时间。

#include <iomanip>
#include <iostream>

int main() {
    auto time = std::time(nullptr);
    std::cout
        // ISO 8601: %Y-%m-%d %H:%M:%S, e.g. 2017-07-31 00:42:00+0200.
        << std::put_time(std::gmtime(&time), "%F %T%z") << '\n'
        // %m/%d/%y, e.g. 07/31/17
        << std::put_time(std::gmtime(&time), "%D"); 
}

的顺序很重要:
std::cout << std::put_time(std::gmtime(&time), "%c %A %Z") << std::endl;
// Mon Jul 31 00:00:42 2017 Monday GMT
std::cout << std::put_time(std::gmtime(&time), "%Z %c %A") << std::endl;
// GMT Mon Jul 31 00:00:42 2017 Monday

strftime() 的格式化方式类似于:

char output[100];
if (std::strftime(output, sizeof(output), "%F", std::gmtime(&time))) {
    std::cout << output << '\n'; // %Y-%m-%d, e.g. 2017-07-31
}

通常,大写格式化程序表示“完整版本”,小写表示缩写(例如,Y:2017,y:17)。

本地设置会改变输出结果:

#include <iomanip>
#include <iostream>
int main() {
    auto time = std::time(nullptr);
    std::cout << "undef: " << std::put_time(std::gmtime(&time), "%c") << '\n';
    std::cout.imbue(std::locale("en_US.utf8"));
    std::cout << "en_US: " << std::put_time(std::gmtime(&time), "%c") << '\n';
    std::cout.imbue(std::locale("en_GB.utf8"));
    std::cout << "en_GB: " << std::put_time(std::gmtime(&time), "%c") << '\n';
    std::cout.imbue(std::locale("de_DE.utf8"));
    std::cout << "de_DE: " << std::put_time(std::gmtime(&time), "%c") << '\n';
    std::cout.imbue(std::locale("ja_JP.utf8"));
    std::cout << "ja_JP: " << std::put_time(std::gmtime(&time), "%c") << '\n';
    std::cout.imbue(std::locale("ru_RU.utf8"));
    std::cout << "ru_RU: " << std::put_time(std::gmtime(&time), "%c");        
}

可能的输出(ColiruCompiler Explorer):
undef: Tue Aug  1 08:29:30 2017
en_US: Tue 01 Aug 2017 08:29:30 AM GMT
en_GB: Tue 01 Aug 2017 08:29:30 GMT
de_DE: Di 01 Aug 2017 08:29:30 GMT
ja_JP: 2017年08月01日 08時29分30秒
ru_RU: Вт 01 авг 2017 08:29:30

我已经使用std::gmtime()将时间转换为UTC。std::localtime()可用于将时间转换为本地时间。
请注意,其他答案中提到的asctime()/ctime()现在已被标记为过时,应优先使用strftime()

std::put_time() 无法使用 std::chrono::system_clock::now() 的输出。 - remcycles
1
你可以使用std::chrono::system_clock::to_time_t()来将系统时钟的输出转换为时间。 - Roi Danton

21
(对于同样在寻找答案的读者)

还有一个名为Boost::date_time的库:

#include <boost/date_time/posix_time/posix_time.hpp>

boost::posix_time::ptime date_time = boost::posix_time::microsec_clock::universal_time();

14
#include <stdio.h>
#include <time.h>

int main ()
{
  time_t rawtime;
  struct tm * timeinfo;

  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  printf ( "Current local time and date: %s", asctime (timeinfo) );

  return 0;
} 

12

是的,您可以使用当前加注区域指定的格式规则来进行此操作:

#include <iostream>
#include <iterator>
#include <string>

class timefmt
{
public:
    timefmt(std::string fmt)
        : format(fmt) { }

    friend std::ostream& operator <<(std::ostream &, timefmt const &);

private:
    std::string format;
};

std::ostream& operator <<(std::ostream& os, timefmt const& mt)
{
    std::ostream::sentry s(os);

    if (s)
    {
        std::time_t t = std::time(0);
        std::tm const* tm = std::localtime(&t);
        std::ostreambuf_iterator<char> out(os);

        std::use_facet<std::time_put<char>>(os.getloc())
            .put(out, os, os.fill(),
                 tm, &mt.format[0], &mt.format[0] + mt.format.size());
    }

    os.width(0);

    return os;
}

int main()
{
    std::cout << timefmt("%c");
}

输出:2013年9月6日星期五 20:33:31

2
在我看来,这实际上是最好的答案,因为它是唯一一个尊重区域设置并且编程细节非常关注的答案(你不经常看到ostream::sentry). - DevSolar
@DevSolar 谢谢。虽然我不会说这是最好的实现,但我见过更好的实现。但我认为这已经足够作为一个例子了 :) - David G
对我来说编译不通过。作为一个新手,我无法评论原因。 - historystamp

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