Reputation:
Coming from C# I'm a bit lost with the datetime functionality in C++. I am simply looking to convert from a string in the format 2023-01-12T07:00:00+08:00 to the number of seconds since 1-1-2023 UTC.
And the reverse, i.e. an int of the number of seconds since the start of 2023 to a string in the format "%Y-%m-%dT%H:%M:%S%z". Any code or pointers in the right direction would be greatly appreciated.
Have tried various options using chrono and time_t which seems to work:
std::time_t getTime(const std::string& dateTime) {
std::chrono::sys_time<std::chrono::seconds> tTime;
std::istringstream stream(dateTime);
std::chrono::from_stream(stream, "%Y-%m-%dT%H:%M:%S%z", tTime);
return std::chrono::system_clock::to_time_t(tTime);
}
const time_t EPOCH_2023 = getTime("2023-01-01T00:00:00+00:00");
int stringToIntTime(const std::string& dateTime) {
return static_cast<int>(getTime(dateTime) - EPOCH_2023);
}
to get the int.
But I haven't a clue on doing the reverse.
Upvotes: 1
Views: 181
Reputation: 218700
Here is what I recommend:
#include <chrono>
#include <format>
#include <iostream>
#include <sstream>
using namespace std::chrono_literals;
constexpr std::chrono::sys_seconds EPOCH_2023 = std::chrono::sys_days{2023y/01/01};
int
stringToIntTime(const std::string& dateTime)
{
using namespace std;
using namespace std::chrono;
sys_seconds tTime;
istringstream stream(dateTime);
stream >> parse("%FT%T%Ez", tTime);
return (tTime - EPOCH_2023)/1s;
}
std::string
intToStringTime(int i)
{
using namespace std;
using namespace std::chrono;
sys_seconds t = EPOCH_2023 + seconds{i};
return format("{:%FT%T%Ez}", zoned_time{"Etc/GMT-8", t});
}
int
main()
{
using namespace std;
int i = stringToIntTime("2023-01-12T07:00:00+08:00");
string s = intToStringTime(i);
cout << i << '\n';
cout << s << '\n';
}
Which should output:
946800
2023-01-12T07:00:00+08:00
I've taken the liberty of simplifying your stringToIntTime
somewhat:
Your EPOCH_2023
constant can be made more efficient by storing it in a sys_seconds
type as opposed to a string
, and making it constexpr
. In the object code this will just be a integral literal which is the count of seconds between your epoch and the system_clock
epoch of 1970-01-01.
stringToIntTime
is correct, but I've simplified it down to one function and used parse
in place of from_stream
just for slightly cleaner syntax. parse
is a slightly higher level API.
Also note the use of %Ez
in place of %z
. The former includes the :
separator between the hours and minutes of the UTC offset.
There's no need to go through the C API with time_t
. One can just subtract the parsed UTC time tTime
from your epoch. This results in seconds since your epoch. To convert that to int
, just divide by 1 second.
intToStringTime
starts with converting the int
to seconds and adding that to your epoch. This gives t
the type sys_seconds
and the value of a time_point
with seconds since the system_clock
epoch.
Finally just format t
, using a time zone with the +08:00 UTC offset, using the desired format. Note the use of -8 in the name to give +8 for the offset. This is simply POSIX weirdness that IANA inherits. If some other time zone is desired, just sub that in for "Etc/GMT-8"
.
Note the use of %T
which is a shortcut for %H:%M:%S
and %F
which is a shortcut for %Y-%m-%d
.
Upvotes: 2
Reputation: 79
The best way is probably to use sscanf_s (stdio.h since C11) or strptime (POSIX standard) to convert the string into either individual values or a tm type (time.h), respectively. From there you can use mktime (time.h) to get back a time_t type. Then just subtract them. How to convert a string variable containing time to time_t type in c++?
Upvotes: 0