使用std :: chrono在C ++中输出日期和时间


74

我一直在升级一些旧代码,并在可能的情况下尝试更新到c ++ 11。以下代码是我过去在程序中显示时间和日期的方式

#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>

const std::string return_current_time_and_date() const
{
    time_t now = time(0);
    struct tm tstruct;
    char buf[80];
    tstruct = *localtime(&now);
    strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct);
    return buf;
}

我想使用std :: chrono(或类似的格式)以类似的格式输出当前时间和日期,但是不确定如何去做。任何帮助将不胜感激。谢谢


如果已经问过这样的问题,请查询,如果没有,请问。
legends2k


4
使用C ++ 11不会变得更好。chrono的重点在于计时(某件事情花了多长时间),而不是时间类型的东西。不过,您可能会签出Boost Date Time。它具有更强大的日期和时间功能。
内森·恩斯特

使用计时获取日期和时间并输出?请参阅第一个示例
dyp

2
@DyP看起来很有希望,但是我需要从函数中返回一个字符串,并且不确定如何使用std :: put_time
const_ref 2013年

Answers:


105

<chrono>库只处理时间,而不处理日期,除了system_clock可以将其时间点转换为time_t。因此,使用<chrono>日期不会有太大改善。希望我们能chrono::date在不久的将来得到类似的东西。

也就是说,您可以通过<chrono>以下方式使用:

#include <chrono>  // chrono::system_clock
#include <ctime>   // localtime
#include <sstream> // stringstream
#include <iomanip> // put_time
#include <string>  // string

std::string return_current_time_and_date()
{
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
    return ss.str();
}

请注意,这std::localtime可能会导致数据争用。localtime_r或类似的功能可能在您的平台上可用。

更新:

使用Howard Hinnant的日期库的新版本,您可以编写:

#include "date.h"
#include <chrono>
#include <string>
#include <sstream>

std::string return_current_time_and_date() {
  auto now = std::chrono::system_clock::now();
  auto today = date::floor<days>(now);

  std::stringstream ss;
  ss << today << ' ' << date::make_time(now - today) << " UTC";
  return ss.str();
}

这将打印出类似“ 2015-07-24 05:15:34.043473124 UTC”的内容。


无关紧要的是,const在C ++ 11中,返回对象已变得不可取。const返回值不能移出。我还删除了尾随const,因为尾随const仅对成员函数有效,并且此函数无需成为成员。


8
请注意,某些旧的编译器可能无法识别std::put_time。一旦我尝试std::put_time使用g ++编译CentOS 7上的代码,它就会失败。std::put_timeGCC stackoverflow.com/q/14136833/4694036中
LETs

1
是否有类似于std :: put_time的C ++函数,但是要返回字符串?
尼克

@尼克号。C函数strftime使您可以用C字符串填充缓冲区。过时的函数asctime将以固定的时间格式返回C字符串。
bames53 2015年

谢谢,好吧,我想您可以使用字符串流执行put_time
Nick

2
如果您不使用using namespace date;<< today将无法使用。
Orwellophile

16

一个例子:

#include <iostream>
#include <chrono>
#include <ctime>

std::string getTimeStr(){
    std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

    std::string s(30, '\0');
    std::strftime(&s[0], s.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
    return s;
}
int main(){

    std::cout<<getTimeStr()<<std::endl;
    return 0;

}

输出如下:

在此处输入图片说明


1

Downvote:当前答案返回一个30个字符的长字符串,最后带有许多空字符。如果您尝试将某些内容连接到它,它将无法正常工作。我没有提出修改建议,以使其正常工作,但它是由Django的程序员拒绝....
田园贾森-

5

为了获得毫秒数,我使用了chrono和C函数localtime_r,它是线程安全的(与std :: localtime相反)。

#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>


int main() {
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
  std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
  struct tm currentLocalTime;
  localtime_r(&currentTime, &currentLocalTime);
  char timeBuffer[80];
  std::size_t charCount { std::strftime( timeBuffer, 80,
                                         "%D %T",
                                          &currentLocalTime)
                         };

  if (charCount == 0) return -1;

  std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
  return 0;
}

格式:http : //www.cplusplus.com/reference/ctime/strftime/


由于已经导入了iomanip,因此可以通过使用std :: put_time而不是std :: strftime来跳过创建自己的缓冲区的操作。
Bloodgain

您可能会出现半秒钟的时间,因为它to_time_t可能会截断,但也可能会变圆。
罗斯兰

4

bames53解决方案很好,但不能在我的VS2017上编译。使用ctime的解决方案无法编译,因为localtime已被弃用。带有date.h的那个不能与当前date.h一起编译,尽管文档说应该这样做,但我还是摘下了github,因为今天不能按原样进行流处理。我省略了包含,但这里是有效的代码:

void TimeTest()
{
    auto n = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(n);
    std::tm buf;
    localtime_s(&buf, &in_time_t);
    std::cout << std::put_time(&buf, "%Y-%m-%d %X") << std::endl;

}

// I just added date.h from this link's guthub to the project.
// https://howardhinnant.github.io/date/date.html
void TimeTest1() {
    auto now = std::chrono::system_clock::now();
    auto today =  floor<date::days>(std::chrono::system_clock::now());
    std::cout << date::year_month_day{ today } << ' ' << date::make_time(now - today) << std::endl;
}

// output is 
// 2018-04-08 21:19:49
// 2018-04-08 18:19:49.8408289

随时修复bames53解决方案并删除我的。我的文字只适合发表评论。我相信它可以使很多人免于悲痛。


1
如果添加using date::operator<<;,则可以流式传输today而无需将其转换为year_month_day
Howard Hinnant

霍华德,非常感谢您编写和共享此库。到了这一点,我宁愿永远不使用using,因为在我的日子里,由于名称空间冲突而遭受的错误和含糊不清。同样,如果我们很精确,我想指出的是,第一个示例输出本地时间,而第二个示例是世界时。
的Yaniv

1
很高兴我可以提供帮助。 usings在功能范围内,这是一个很好的折衷方案,因为冲突发生时更容易控制。我意识到这并不完美,但这是最好的方法,它是由第三方库编写的std :: types流插入运算符完成的。但是就在上个月,我说服了C ++委员会将该流运算符放入namespace std::chronoC ++ 20中,以便ADL可以找到它。然后,它将不再需要using
Howard Hinnant

关于输出为UTC的良好观察。还提供了一个更高级别的库,该库为操作提供了本地时间。可以是您计算机的当前本地时区,也可以是特定的时区(例如“ America / New_York”)。这是时区库文档
Howard Hinnant

2

您可以使用Boost lexical_cast代替字符串流操作来改善@ bames53的答案。

这是我的工作:

#include <boost/lexical_cast.hpp>
#include <ctime>

std::string return_current_time_and_date() {
    auto current_time = std::time(0);
    return boost::lexical_cast<std::string>(std::put_time(std::gmtime(& current_time), "%Y-%m-%d %X"));
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.