Reputation: 143
I faced with problem of correct way to store and work with date and time by specific locale or stamp including nanoseconds: yyyyMMdd-HH:MM:SS.nnnnnnnnn
(example: 20211215-06:36:01.571670316).
Option 1
I need to store the date time including nanoseconds so I found few examples with std::chrono::nanoseconds
. As I understand it is a period from 1970 (std::chrono::duration
) and I can take days, hours, minuts etc. include nanoseconds (got here)
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<8>>::type> Days; // UTC: +8:00
Days days = std::chrono::duration_cast<Days>(duration);
duration -= days;
auto hours = std::chrono::duration_cast<std::chrono::hours>(duration);
duration -= hours;
auto minutes = std::chrono::duration_cast<std::chrono::minutes>(duration);
duration -= minutes;
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
duration -= seconds;
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
duration -= milliseconds;
auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration);
duration -= microseconds;
auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
std::cout << hours.count() << ":"
<< minutes.count() << ":"
<< seconds.count() << "."
<< milliseconds.count()
<< microseconds.count()
<< nanoseconds.count() << std::endl;
Question 1.1: How can I print this stored date time std::chrono::duration
as std::string
or char*
using locale or stamp yyyyMMdd-HH:MM:SS.nnnnnnnnn
?
Question 1.2 How can I parse std::string
or char*
with same locale or stamp as std::chrono::duration
to save it?
Question 1.3 Are there any other ways to use std::chrono::duration
for date time store, print and parce as I need?
Option 2
I also tried to use next approach (got here). Here the date and time use one source it's std::chrono::time_point
, the nanoseconds added as additional part by cast to the std::chrono::duration
:
std::chrono::time_point now = std::chrono::high_resolution_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
auto tm = *std::gmtime(&time);
auto epoch = now.time_since_epoch();
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch).count() % 1000000000;
std::ostringstream oss;
oss << std::put_time(&tm, "%Y%m%d-%T.");
auto str = oss.str();
std::cout << str << ns ;
out: 20220110-04:00:25.576973219
As I see everything looks good, we use only std::chrono::time_point to store date and time, but I don't really think it's good way to use lot of additional casts, like std::chrono::duration
for nanoseconds and std::ostringstream
to string.
So then I have another questions:
Question 2.1 Is it a good way to store print and parse date time or I can do it witout lot of cast?
Question 2.2 What is the correct approach to get std::chrono::time_point
from std::string
or char*
using locale or stamp yyyyMMdd-HH:MM:SS.nnnnnnnnn
?
Unfortunately c++20 std::format
doesn't work with gcc
Additional information:
gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
cmake --version
cmake version 3.16.3
set(CMAKE_CXX_STANDARD 23)
BTW Clion write cmake version is 3.21.1
Upvotes: 0
Views: 2614
Reputation: 219428
Since your question is tagged C++20, I'm going to show a C++20 solution, even though your compiler does not yet implement these parts of C++20. However, there exists a free, open-source, header-only preview of this part of C++20 that you can use in the interim which gives you a very nice migration path to C++20. Additionally the C++20 tools in this area are far easier to use than in prior C++ standards.
#include <cassert>
#include <chrono>
#include <format>
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace std::chrono;
stringstream io;
sys_time<nanoseconds> now = system_clock::now();
io << format("{:%Y%m%d-%T}", now); // store
cout << io.str() << '\n'; // 20220110-15:13:19.576742000
now = {}; // "zero out" now just to tell if the parse works
io >> parse("%Y%m%d-%T", now); // parse
assert(!io.fail()); // another way to tell if the parse works
cout << now << '\n'; // 2022-01-10 15:13:19.576742000
}
auto
in place of sys_time<nanoseconds>
, but this makes the precision platform-dependent. E.g. macOS would give you microseconds.To use the free, open-source, header-only preview:
#include <format>
with #include "date/date.h"
.using namespace date;
"{:%Y%m%d-%T}"
to "%Y%m%d-%T"
Upvotes: 1