How do I get the current UTC offset (as in time zone, but just the UTC offset of the current moment)?
I need an answer like "+02:00".
There are two parts to this question:
Get the UTC offset as a boost::posix_time::time_duration
Format the time_duration as specified
Apparently, getting the local time zone is not exposed very well in a widely implemented API. We can, however, get it by taking the difference of a moment relative to UTC and the same moment relative to the current time zone, like this:
boost::posix_time::time_duration get_utc_offset() {
using namespace boost::posix_time;
// boost::date_time::c_local_adjustor uses the C-API to adjust a
// moment given in utc to the same moment in the local time zone.
typedef boost::date_time::c_local_adjustor<ptime> local_adj;
const ptime utc_now = second_clock::universal_time();
const ptime now = local_adj::utc_to_local(utc_now);
return now - utc_now;
}
Formatting the offset as specified is just a matter of imbuing the right time_facet:
std::string get_utc_offset_string() {
std::stringstream out;
using namespace boost::posix_time;
time_facet* tf = new time_facet();
tf->time_duration_format("%+%H:%M");
out.imbue(std::locale(out.getloc(), tf));
out << get_utc_offset();
return out.str();
}
Now, get_utc_offset_string() will yield the desired result.
Since C++11 you can use chrono and std::put_time:
#include <chrono>
#include <iomanip>
#include <iostream>
int main ()
{
using sc = std::chrono::system_clock;
auto tm = sc::to_time_t(sc::now());
std::cout << std::put_time(std::localtime(&tm), "formatted time: %Y-%m-%dT%X%z\n");
std::cout << "just the offset: " << std::put_time(std::localtime(&tm), "%z\n");
}
This produces the following output:
formatted time: 2018-02-15T10:25:27+0100
just the offset: +0100
Related
I am working on c++ real time application which is doing lot of date manipulations. For performance reasons, I made the UTC offset as configurable value which is read only once at the time of application initialization. But it is causing issues in DST zones.
When DST Changes happens, My UTC offset variable contain wrong value.
Calculating the Offset every time is not a optimal solution for me.
So is there anyway to notify my application about DST changes? So I can calculate the offset only when it need to modified.
Using the draft C++20 <chrono> facilities you can discover the std::chrono::system_clock::time_point for the next UTC offset change for any time zone, and then std::this_thread::sleep_until that time_point. When you wake, do whatever it is you want to do, such as compute a new UTC offset.
The new draft C++20 <chrono> library has been prototyped and is available as a free, open-source library under namespace date. This library is portable across VS, gcc and clang, and operates with C++11 and later.
Here is a sketch of how this might be coded:
#include "date/tz.h"
#include <thread>
template <class F>
void
on_utc_offset_change(date::time_zone const* tz, F f)
{
using namespace date;
using namespace std;
using namespace std::chrono;
while (true)
{
auto info = tz->get_info(system_clock::now());
f(info);
this_thread::sleep_until(info.end);
}
}
A time_zone has a get_info(system_clock::time_point) member function that returns a sys_info. The sys_info contains all information about a time_zone for a particular point in time:
struct sys_info
{
sys_seconds begin;
sys_seconds end;
std::chrono::seconds offset;
std::chrono::minutes save;
std::string abbrev;
};
The begin and end members are seconds-precision system_clock time_points that delineate the range [begin, end) for which this time_zone has this UTC offset and abbreviation (abbrev).
This function might be called like this:
auto lambda = [](date::sys_info const& info)
{
using namespace date;
std::cerr << "Current UTC offset: " << info.offset << '\n';
std::cerr << "Current tz abbreviation: " << info.abbrev << '\n';
std::cerr << "Sleeping until " << info.end << " UTC\n";
};
std::thread{on_utc_offset_change<decltype(lambda)>,
date::current_zone(),
lambda}.detach();
This detaches a thread that runs forever and every time the UTC offset changes for the computer's current time_zone (at the time the thread was launched), it prints out current information, for example.
Current UTC offset: -14400s
Current tz abbreviation: EDT
Sleeping until 2018-11-04 06:00:00 UTC
Alternatively you could run this for a specific time_zone which is not the computer's currently set time_zone with:
std::thread{on_utc_offset_change<decltype(lambda)>,
date::locate_zone("America/New_York"),
lambda}.detach();
I'm trying to get the current year stored in a date from before 1970 using an std::chrono::time_point<std::chrono::system_clock>, however I've run into an issue regarding the reading from its contents into a std::tm struct.
I convert the time_point to a time_t first, after which I read its values to get the tm_year value. However, when trying to do so, the code fails when using localtime_s, however it succeeds when I'm using gmtime_s. This is only for dates before 1-1-1970, dates after that work fine using both functions.
The code below reproduces the error. If terstGmTimeVsLocalTime is called with utc=true it works, if it is called with utc=false it doesn't produce the correct output.
#include <iomanip>
#include <time.h>
#include <iostream>
void testGmTimeVsLocaltime(const bool& utc) {
// Create time
std::tm timeInfoWrite = std::tm();
timeInfoWrite.tm_year = 1969 - 1900; // Year to parse, here it is 1969
timeInfoWrite.tm_mon = 0;
timeInfoWrite.tm_mday = 1;
timeInfoWrite.tm_hour = 1;
timeInfoWrite.tm_min = 0;
timeInfoWrite.tm_sec = 0;
timeInfoWrite.tm_isdst = -1;
std::chrono::time_point<std::chrono::system_clock> timePoint = std::chrono::system_clock::from_time_t(utc ? _mkgmtime(&timeInfoWrite) : std::mktime(&timeInfoWrite));
// Convert to time_t
std::time_t timeT = std::chrono::system_clock::to_time_t(timePoint);
// Read values
std::tm timeInfoRead;
if (utc) {
gmtime_s(&timeInfoRead, &timeT);
} else {
localtime_s(&timeInfoRead, &timeT);
}
// Output result
std::cout << (timeInfoRead.tm_year + 1900) << '\n';
// Wait for input
std::getchar();
}
int main() {
testGmTimeVsLocaltime(true); // Set to false to show bug
return 0;
}
utc=true outputs 1969, as would be expected. However, utc=false outputs 1899 (presumably since an error occurs and tm_year gets set to -1).
Is there anything I'm missing? The documentation doesn't specifically specify that localtime_s should fail for dates before 1-1-1970.
I'm on Windows 10 x64 if it makes a difference.
Using Howard Hinnant's free, open-source date lib, you can completely side-step the clumsy, error and bug-prone C api, and work directly with a modern <chrono>-based system:
#include "chrono_io.h"
#include "date.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
sys_days timePoint = timeInfoWrite; // this is a chrono::time_point
std::cout << timePoint.time_since_epoch() << '\n'; // -365 days
// Convert to time_t
// no need
// Read values
year_month_day timeInfoRead = timePoint;
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-365[86400]s
1969
There are literals to make it easy to fill in a year_month_day struct which is the analog to the year, month and day parts of a tm. You can easily convert this to a std::chrono::time_point<system_clock, days> (sys_days). This is the same as a system_clock::time_point, but with a precision of days instead. It itself will implicitly convert to a seconds-precision time_point (typedef'd to sys_seconds), or to a system_clock::time_point.
Above I just output its time_since_epoch() which shows that it is -365 days prior to the epoch.
There's never really any need to convert to C API data structures, but it is easy if you want to. For example, assuming time_t is seconds since 1970-01-01:
std::time_t timeT = sys_seconds{timePoint}.time_since_epoch().count();
std::cout << timeT << '\n';
which outputs:
-31536000
The reverse conversion (back to year_month_day) is just as easy. If you want to convert from timeT it is just slightly more involved:
year_month_day timeInfoRead = floor<days>(sys_seconds{seconds{timeT}});
This first converts time_t to chrono::seconds, and then to a seconds-precsion time_point, and then to a days-precsion time_point, finally to the year_month_day field type (tm-like).
Finally year_month_day has a year() getter member function which is streamable. You can explicitly convert year to int if desired:
int{timeInfoRead.year()}
But I think it best to keep things like years, months and days as distinct types so that the compiler can help you catch when you accidentally mix them up.
Finally, if you really meant that you wanted 1969-01-01 00:00:00 in your computer's local timezone, there's a library to do that as well. And it is just a minor modification of the simple program above.
#include "tz.h"
#include <iostream>
void
testGmTimeVsLocaltime()
{
using namespace date;
using namespace std::chrono;
// Create time
auto timeInfoWrite = 1969_y/jan/1;
auto timePoint = make_zoned(current_zone(), local_days{timeInfoWrite});
// Convert to time_t
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
std::cout << timeT << '\n';
// Read values
timePoint = sys_seconds{seconds{timeT}};
year_month_day timeInfoRead{floor<days>(timePoint.get_local_time())};
// Output result
std::cout << timeInfoRead.year() << '\n';
}
int
main()
{
testGmTimeVsLocaltime();
}
Output:
-31518000
1969
Now you create a zoned_seconds using the computer's current_zone() timezone, and converting your timeInfoWrite to local_days instead of to sys_days.
You can get the local time or the system time out of timePoint. For converting to time_t, system time makes the most sense:
std::time_t timeT = timePoint.get_sys_time().time_since_epoch().count();
And now the output (for me) is 5h later (18000s).
-31518000
You can get back either the local year, or the system (UTC) year, by either using .get_local_time() or .get_sys_time(). For me it makes no difference ("America/New_York"). But if you're in "Australia/Sydney", you'll get 1968 if you request the UTC year instead of 1969. And that's all very easy to simulate by simply substituting "Australia/Sydney" or "America/New_York" for current_zone() in the program above.
Yes, it works on Windows, VS-2013 and later. There is some installation required for the timezone lib: https://howardhinnant.github.io/date/tz.html#Installation
I have a time_t that represents the time in seconds since epoch. Those seconds refer to the local time.
I want to convert them to UTC.
Is there a way to do this in C++?
I'm going to show two ways of doing this:
Using the C API.
Using a modern C++11/14 library based on top of <chrono>.
For the purposes of this demo, I'm assuming that the current number of seconds in the local time zone is 1,470,003,841. My local time zone is America/New_York, and so the results I get reflect that we are currently at -0400 UTC.
First the C API:
This API is not type-safe and is very error prone. I made several mistakes just while coding up this answer, but I was able to quickly detect these mistakes because I was checking the answers against the 2nd technique.
#include <ctime>
#include <iostream>
int
main()
{
std::time_t lt = 1470003841;
auto local_field = *std::gmtime(<);
local_field.tm_isdst = -1;
auto utc = std::mktime(&local_field);
std::cout << utc << '\n'; // 1470018241
char buf[30];
std::strftime(buf, sizeof(buf), "%F %T %Z\n", &local_field);
std::cout << buf;
auto utc_field = *std::gmtime(&utc);
std::strftime(buf, sizeof(buf), "%F %T UTC\n", &utc_field);
std::cout << buf;
}
First I initialize the time_t. Now there is no C API to go from a local time_t to a UTC time_t. However you can use gmtime to go from a UTC time_t to a UTC tm (from serial to field type, all in UTC). So the first step is to lie to gmtime, telling it you've got a UTC time_t. And then when you get the result back you just pretend you've got a local tm instead of a UTC tm. Clear so far? This is:
auto local_field = *std::gmtime(<);
Now before you go (and I personally messed this part up the first time through) you have to augment this field type to say that you don't know if it is currently daylight saving or not. This causes subsequent steps to figure that out for you:
local_field.tm_isdst = -1;
Next you can use make_time to convert a local tm to a UTC time_t:
auto utc = std::mktime(&local_field);
You can print that out, and for me it is:
1470018241
which is 4h greater. The rest of the function is to print out these times in human readable format so that you can debug this stuff. For me it output:
2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC
A modern C++ API:
There exist no facilities in the std::lib to do this. However you can use this free, open source (MIT license) library for this.
#include "date/tz.h"
#include <iostream>
int
main()
{
using namespace date;
using namespace std::chrono_literals;
auto zt = make_zoned(current_zone(), local_seconds{1470003841s});
std::cout << zt.get_sys_time().time_since_epoch() << '\n'; // 1470018241s
std::cout << zt << '\n';
std::cout << zt.get_sys_time() << " UTC\n";
}
The first step is to create the local time in terms of seconds since the epoch:
local_seconds{1470003841s}
The next thing to do is to create a zoned_time which is a pairing of this local time and the current time zone:
auto zt = make_zoned(current_zone(), local_seconds(1470003841s));
Then you can simply print out the UTC number of seconds of this pairing:
std::cout << zt.get_sys_time().time_since_epoch() << '\n';
This output for me:
1470018241s
(4h later than the input). To print out this result as I did in the C API:
std::cout << zt << '\n';
std::cout << zt.get_sys_time() << " UTC\n";
which outputs:
2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC
In this modern C++ approach, the local time and the UTC time are different types, making it much more likely that I catch accidental mixing of these two concepts at compile time (as opposed to creating run time errors).
Update for C++20
The second technique will be available in C++20 with the following syntax:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
zoned_time zt{current_zone(), local_seconds{1470003841s}};
std::cout << zt.get_sys_time().time_since_epoch() << '\n'; // 1470018241s
std::cout << zt << '\n';
std::cout << zt.get_sys_time() << " UTC\n";
}
You can use gmtime:
Convert time_t to tm as UTC time Uses the value pointed by timer to
fill a tm structure with the values that represent the corresponding
time, expressed as a UTC time (i.e., the time at the GMT timezone).
(c) http://www.cplusplus.com/reference/ctime/gmtime/
If you are okay with using Abseil's time library, one other way to do this is:
auto civil_second =
absl::LocalTimeZone().At(absl::FromTimeT(<your time_t>)).cs;
time_t time_in_utc = absl::ToTimeT(absl::FromCivil(civil_second, absl::UTCTimeZone()));
(Maybe there is a simpler set of calls in the library to do this, but I have not explored further. :))
Normaly, you would convert from time_t to struct tm and there aren't many examples of converting from time_t to time_t in a different time zone (UTC in case of the OP's question). I wrote these 2 functions for that exact purpose. They may be useful when you are only in a need ot using time_t but in a specific time zone.
time_t TimeAsGMT(time_t t)
{
std::chrono::zoned_time zt{"UTC", std::chrono::system_clock::from_time_t(t)};
return std::chrono::system_clock::to_time_t(zt.get_sys_time());
}
or if you want the current time as UTC in the form of time_t
time_t CurTimeAsGMT()
{
std::chrono::zoned_time zt{"UTC", std::chrono::system_clock::now()}; // Get the time in UTC time zone
return std::chrono::system_clock::to_time_t(zt.get_sys_time()); // return this time as time_t
}
If you run both functions and compare the initial value and the result value, you will see that the difference matches the difference between your current time (at your current time zone) and UTC / GMT time zone.
Hello I'm trying to get time elapsed since epoch using boost in UTC but it seems that microsec_clock::universal_time(); doesn't return UTC time, instead it returns time in timezone of PC.
How can I get current time in miliseconds in UTC using boost?
Here is my code that I'm using
const long long unix_timestmap_now()
{
ptime time_t_epoch(date(1970, 1, 1));
ptime now = microsec_clock::universal_time();
time_duration diff = now - time_t_epoch;
return diff.total_milliseconds();;
}
Why you use a boost? All needed (which refers to the time) moved to the STL in C ++ .
It is important - not everyone knows that "unix timestamp" at a time is the same for the whole world, ie if the check time on the server in Russia, and for example on a server in the USA, the value will be the same (of course under the condition that both servers correct time right), it differs only in its transformation into understandable for people of form, depending on the server settings. And of course the reverse priobrazovanie will also vary if you do not set the time zone.
Tested on cpp.sh
#include <iostream>
#include <chrono>
int main ()
{
using namespace std::chrono;
system_clock::time_point tp = system_clock::now();
system_clock::duration dtn = tp.time_since_epoch();
std::cout << "current time since epoch, expressed in:" << std::endl;
std::cout << "milliseconds: " << duration_cast<milliseconds>(dtn).count();
std::cout << std::endl;
return 0;
}
I have to instantiate an object of a custom library class that takes nanoseconds since 'epoch' in UTC time to construct:
class utc_time
{
public:
utc_time(TYPE nanoseconds_since_epoch):
_nanoseconds_since_epoch(nanoseconds_since_epoch){}
private:
TYPE _nanoseconds_since_epoch;
};
what I have as my input is nanoseconds since 'midnight' in UTC time. Naturally, I need to get the epoch till last midnight nanoseconds(in UTC) to add it to my input and supply it to my class constructor.
I know we have gtime that may be helpful, but I dont know how to extract the required information.
I appreciate your clues
In C++11 and later, <chrono> can be used to do this very easily:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using days = duration<int, ratio<86400>>;
nanoseconds last_midnight =
time_point_cast<days>(system_clock::now()).time_since_epoch();
cout << last_midnight.count() << '\n';
}
In deed, nanoseconds since Epoch = nanoseconds since midnight + 1e9 * calendar time of last midnight. You lack the latter value. You can built it with a conjunction of ::gmtime() and ::mktime().
#include <ctime>
std::time_t last_midnight()
{
// compute "now"
std::tm& tm = *::gmtime(NULL);
// move it to "last midnight"
tm.tm_hour = 0;
tm.tm_min = 0;
tm.tm_sec = 0;
// get time_t back
return ::mktime(&tm);
}
You may find interest in using ::gmtime_r() (re-entrant version) instead of ::gmtime().