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

llycmphe  于 2023-03-20  发布在  其他
关注(0)|答案(8)|浏览(241)

我一直在升级一些旧的代码,并一直试图更新到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(或类似的)以类似的格式输出当前时间和日期,但不确定如何进行。任何帮助将不胜感激。谢谢

oo7oh9g9

oo7oh9g91#

<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或类似函数可能在您的平台上可用。
更新:
使用霍华德Hinnant的date library的新版本,您可以编写:

#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年7月24日05:15:34. 043473124 UTC”的内容。
另外,返回const对象在C++11中已变得不受欢迎;const的返回值不能被移出。我还删除了尾随const,因为尾随const只对成员函数有效,而这个函数不需要是成员。

3duebb1j

3duebb1j2#

下面是一个C++20解决方案:

#include <chrono>
#include <format>

std::string get_current_time_and_date()
{
    auto const time = std::chrono::current_zone()
        ->to_local(std::chrono::system_clock::now());
    return std::format("{:%Y-%m-%d %X}", time);
}

std::chrono::time_zone::to_local将系统时钟时间点(std::chrono::time_point<std::chrono::system_clock, TDuration>)转换为本地时间点(std::chrono::local_time<TDuration>)。然后,可以使用std::format和类似于strftime的格式选项来格式化此本地时间点。
目前,只有MSVC实现了std::format。日历和时区的添加目前“部分”由Clang和GCC实现,但请在这里查看更新状态:https://en.cppreference.com/w/cpp/compiler_support。有关chrono库的详细信息,请阅读此处:https://en.cppreference.com/w/cpp/chrono .

f8rj6qna

f8rj6qna3#

举个例子:

#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;

}

输出如下:

t30tvxxf

t30tvxxf4#

为了获取毫秒,我使用了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/

0aydgbwb

0aydgbwb5#

bames53解决方案很好,但不能在我的VS2017上编译。带有ctime的解决方案不能编译,因为localtime非常不受欢迎。带有date.h的解决方案不能用当前的date.h编译。我刚刚删除了github,尽管文档中说应该这样做,因为今天不能按原样流传输。我省略了include,但下面是可以工作的代码:

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解决方案并删除我的。我的文字只是不适合在评论。我相信它可以保存许多人从悲伤。

vfwfrxfs

vfwfrxfs6#

fmt库能够格式化tm结构:它与strftime具有相同的规范。

#include <ctime>
#include <fmt/chrono.h>

std::string current_datetime(void)
{
  std::time_t tt = std::time(nullptr);
  std::tm *tm = std::localtime(&tt);
  return fmt::format("{:%Y%m%d}", *tm);
}
9bfwbjaz

9bfwbjaz7#

虽然已经给出了正确答案,但我决定再实现一个输出秒的小数部分的解决方案。
您可能注意到,在我的代码中,有时我会从time_t- std::chrono::seconds(1)中减去一秒,这是因为根据documentationto_time_t()可能会舍入值而不是截断值(根据doc“If std::time_t has lower precision,it is implementation defined that value is rounded or truncated”),因此我必须减去1秒以使其成为截断时间。
Try it online!

#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>

std::string FormatTime(std::chrono::system_clock::time_point tp) {
    std::stringstream ss;
    auto t = std::chrono::system_clock::to_time_t(tp);
    auto tp2 = std::chrono::system_clock::from_time_t(t);
    if (tp2 > tp)
        t = std::chrono::system_clock::to_time_t(tp - std::chrono::seconds(1));
    ss  << std::put_time(std::localtime(&t), "%Y-%m-%d %T")
        << "." << std::setfill('0') << std::setw(3)
        << (std::chrono::duration_cast<std::chrono::milliseconds>(
           tp.time_since_epoch()).count() % 1000);
    return ss.str();
}

std::string CurrentTimeStr() {
    return FormatTime(std::chrono::system_clock::now());
}

#include <iostream>

int main() {
    std::cout << CurrentTimeStr() << std::endl;
}

输出示例:

2021-12-02 04:10:51.876

正如@AndyK所建议的,从C++20开始,您可以使用std::chrono::current_zone()及其方法to_local(),它们返回std::chrono::local_time,通过输出到std::ostringstream或通过std::format()直接转换为您想要的字符串格式。

#include <chrono>
#include <string>
#include <sstream>
#include <iostream>

std::string CurrentTimeStr() {
    return (std::ostringstream{} << std::chrono::current_zone()->to_local(
        std::chrono::system_clock::now())).str().substr(0, 23);
}

int main() {
    std::cout << CurrentTimeStr() << std::endl;
}

但是现在并不是所有的编译器都支持这个current_zone()函数,在线GodBolt服务器在 Backbone.js CLang和GCC上编译失败,但是MSVC编译得很好。虽然我本地笔记本电脑安装的CLang也编译了它。

ozxc1zmp

ozxc1zmp8#

您可以通过使用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"));
}

相关问题