boost local_date_time CET to UTC - c++

I try to convert a boost local_date_time to UTC but I'm confused about the returned time of utc_time(). Here is a simplified code :
#include "boost/date_time/local_time/local_time.hpp"
int main()
{
using namespace boost::gregorian;
using namespace boost::local_time;
using namespace boost::posix_time;
ptime dt = ptime(date(2015, Mar, 2), hours(0));
time_zone_ptr tz_cet(new boost::local_time::posix_time_zone("CET"));
local_date_time local_dt = boost::local_time::local_date_time(dt, tz_cet);
std::cout << local_dt << std::endl;
std::cout << local_dt.utc_time() << std::endl;
time_zone_ptr tz_utc(new boost::local_time::posix_time_zone("UTC"));
std::cout << local_dt.local_time_in(tz_utc) << std::endl;
}
output:
2015-Mar-02 00:00:00 CET
2015-Mar-02 00:00:00
2015-Mar-02 00:00:00 UTC
UTC should be 1 hour behind CET (Central European Time).
Is this a bug or am I missing something?

The boost::local_time::posix_time_zone("CET") constructor call creates a zone with the CET abbreviation and missing information about offset from UTC, time shift for DST, etc, i.e. the calls boost::local_time::posix_time_zone("CET") and boost::local_time::posix_time_zone("UTC") are different only in the TZ abbreviation names, the rest is the same. The coliru code demonstrates it. The base_utc_offset method calls of the both TZs return 00:00:00.
To fix the issue is necessary either to set time parameters of the CET zone, something like, "CET+01:00:00" or to use the tz_database class to load the timezones from a CSV file.
The following code is the original modified code demonstrating how to fix the problem. Please note that the CET time zone description is not complete and provided only as an example.
#include "boost/date_time/local_time/local_time.hpp"
#include <iostream>
int main()
{
using namespace boost::gregorian;
using namespace boost::local_time;
using namespace boost::posix_time;
ptime dt = ptime(date(2015, Mar, 2), hours(0));
time_zone_ptr tz_cet(new boost::local_time::posix_time_zone("CET+01:00:00"));
local_date_time local_dt = boost::local_time::local_date_time(dt, tz_cet);
std::cout << local_dt << std::endl;
std::cout << local_dt.utc_time() << std::endl;
time_zone_ptr tz_utc(new boost::local_time::posix_time_zone("UTC"));
std::cout << local_dt.local_time_in(tz_utc) << std::endl;
}
The same code on coliru is available by this link.

Related

C++ - Calculate the millisecond from ptime in total seconds

How do i calculate the millisecond difference from the following Ptime ,I am using boost::ptime
I'm trying to calculate the time_duration in milliseconds to find the difference. i get value like 999975 but expected value is 975
ptime PreviousgpsTime = Mon Jun 28 17:07:10.054 2021
ptime NextgpsTime = Mon Jun 28 17:07:11.025 2021
double totalDiff = (NextgpsTime-PreviousgpsTime).total_milliseconds();
How to fix this and get the actual time duration.
Live On Coliru:
#include <boost/date_time/posix_time/posix_time.hpp>
int main()
{
using namespace boost::posix_time;
ptime PreviousgpsTime = time_from_string("2021-Jun-28 17:07:10.054");
ptime NextgpsTime = time_from_string("2021-Jun-28 17:07:11.025");
long totalDiff = (NextgpsTime - PreviousgpsTime).total_milliseconds();
std::cout << "From " << PreviousgpsTime << " to " << NextgpsTime << " is " << totalDiff << "ms\n";
}
Prints
From 2021-Jun-28 17:07:10.054000 to 2021-Jun-28 17:07:11.025000 is 971ms

C++ Parsing TimeZone From Date String

Hello I have the following date that I am consuming from an api
string sToParse = "2020-04-17T09:30:00-04:00";
which should be in human form "Friday, April 17, 2020 08:30:00" central time
or epoch of 1587130200
however this code
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%Z" };
istringstream ss{ sToParse };
tm dt;
ss >> get_time(&dt, dateTimeFormat.c_str());
cout << mktime(&dt) << endl;
Gives me an epoch of 1587137400 which is a human format of "Friday, April 17, 2020 10:30:00 AM" which is two hours difference. How do i get the %Z to process the timezone appropriately?
Thanks in advance for any help you can give
C++20 will do this:
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%z" };
istringstream ss{ sToParse };
sys_seconds dt;
ss >> parse(dateTimeFormat, dt);
cout << dt << '\n';
cout << dt.time_since_epoch() << '\n';
}
Output:
2020-04-17 13:30:00
1587130200s
This gets the "epoch time" you're looking for. The big difference is the use of %z instead of %Z. %z is the command for parsing the offset. %Z parses time zone abbreviation.
This doesn't get the "human time" you're expecting. The time printed out above is UTC. This is clearly correct on inspection: 13:30:00 is 4 hours after 09:30:00.
If you are wanting local time, it would be 2020-04-17 09:30:00, same as the input. To come up with 08:30:00 would require more information than you are providing above (e.g. output in some time zone other than that which has a UTC offset of -4h at this local time).
Also it is in general not possible to go from a UTC offset to a time zone name or abbreviation because more than one time zone will generally have the same UTC offset at any point in time.
If the C++20 <chrono> header isn't available for you (to the best of my knowledge it is not yet available anywhere), you can use a free, open-source preview of C+++20 <chrono>. For this problem, one only needs the header-only "date.h" from this preview. And everything is in namespace date instead of namespace std::chrono. It would look like this:
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%Y-%m-%dT%H:%M:%S%z" };
istringstream ss{ sToParse };
sys_seconds dt;
ss >> parse(dateTimeFormat, dt);
cout << dt << '\n';
cout << dt.time_since_epoch() << '\n';
}
Update
With the new knowledge that the "expected human form" of the time should be US Central Time ("America/Chicago" in IANA terms), I'm updating the example code to show how that can be handled.
#include "date/tz.h"
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
string sToParse = "2020-04-17T09:30:00-04:00";
cout << "raw: " << sToParse << endl;
static const std::string dateTimeFormat { "%FT%T%z" };
istringstream ss{ sToParse };
sys_seconds utc;
ss >> parse(dateTimeFormat, utc);
zoned_seconds cst{"America/Chicago", utc};
cout << utc.time_since_epoch() << '\n';
cout << format("%F %T %Z\n", utc);
cout << format("%F %T %Z\n", cst);
}
A few changes above:
A new header is required to handle the time zone issues: "tz.h" (only in the C++20 preview library, not in C++20).
For parsing I've substituted "%Y-%m-%dT%H:%M:%S%z" for "%FT%T%z". These are equivalent. %F is just shorthand for %Y-%m-%d and %T is shorthand for %H:%M:%S. This change is not required.
I've renamed dt to utc to emphasize that this variable holds a UTC time point. This change is not required.
The new line constructs a zoned_time (with seconds precision) with the desired destination time zone ("America/Chicago"), and the UTC time point. This creates an object that knows all about the local time at this time point and in this time zone.
Then everything is printed out using the date::format function and the formatting string "%F %T %Z". %Z is used to output the time zone abbreviation to make the output more readable. In C++20, this will be std::format, and the formatting string will be "{:%F %T %Z}".
The output is now:
raw: 2020-04-17T09:30:00-04:00
1587130200s
2020-04-17 13:30:00 UTC
2020-04-17 08:30:00 CDT
If your computer's current time zone setting happens to be US Central, then the line that constructs zoned_seconds can also look like:
zoned_seconds cst{current_zone(), utc};
Or conversely, you can use this line to find the local time at utc in any time zone which your computer is set to.
Note that whether the time zone is specified with a name such as "America/Chicago", or with current_zone(), any changes of UTC offset within the specified time zone (such as daylight saving time) will be correctly taken into account.
With the preview C+++20 library, the use of the header "tz.h" is not header-only. It requires a single source file, tz.cpp. Here are instructions on how to compile it. But if you are using a fully conforming C++20 <chrono>, then the above will just work by removing #include "date/tz.h", using namespace date;, and adjusting the formatting string as noted in the 5th bullet above.

Conversion of times in C++

This is what I am trying to do:
Get the local time (from the system);
Convert that time to the UTC format and associate it with some member variable of current object.
Later on, given the timezone of the user, I wish to convert it into the correct local time and display it to the user.
Looking up few things on SO and CppReference, I could come up with the following snippet:
#include <iostream>
#include <iomanip>
#include <ctime>
#include <string>
using namespace std;
int main()
{
time_t lt = std::time(0);
//time(0) gives current time, but LTime shows the UTC time (not local time)
string LTime = std::ctime(&lt); //localtime() gives error
cout<<LTime;
//timestamp = mktime(&tm) - timezone;
//time_t timestamp = mktime(&tm) - _timezone;
//std::cout << "timestamp: " << std::put_time(timestamp, "%c %Z") << '\n';
return 0;
}
The example on cppreference.com illustrates how the value can be printed using put_time(); but how to store it in a variable?
How to convert the UTC time format to current timezone (given some timezone as the input)? I tried using the commented code above as per this link but it does not take any parameter.
You can use local time get the local time and gmt time for UTC
You can set the Time zone using the list Time zone wiki
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t result = std::time(nullptr);
auto local = std::asctime(std::localtime(&result));
std::cout <<local;
std::cout << "UTC: " << std::put_time(std::gmtime(&result), "%c %Z") << '\n';
putenv("TZ=Asia/Singapore");
local = std::asctime(std::localtime(&result));
std::cout <<"Asia/Singapore Time "<<local;
}
Output
Thu Sep 14 21:59:37 2017
UTC: Fri Sep 15 01:59:37 2017 UTC
Asia/Singapore Time Fri Sep 15 09:59:37 2017
Program ended with exit code: 0

Converting 13 decimals to datetime

I have a project about cars with GPS. I need to return the start and the finish moment for each car.
So we have:
time_t x, y;
Because I will use later them for a transformation.
I have a problem. I read from an external file data in this format:
auto1
1439467747492
auto1
1439467748512
...etc.
auto1->name of the car;
1439467747492->the moment in time of the car
I tried to get the first position of the first moment and the last moment for each car. This is the code in C++:
long test = momenti[choice1]/1000;
time_t x = test;
cout << " Momentul initial:\n " << ctime(&x) << endl;
long test1 = momentf[choice1] / 1000;
time_t y = test1;
cout << " Momentul final:\n " << ctime(&y) << endl;
I receive the same date for every car. Is something like momenti[i]=momentf[i]
What did I do wrong?
It is not good. According epoch converter we should get this : GMT: Thu, 13 Aug 2015 12:09:07 GMT
Here is how you can get this output with C++11/14 and using this free, open source date library which extends the C++ <chrono> library to handle dates.
#include "date.h"
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace std;
using namespace date;
using time_point = std::chrono::time_point<system_clock, milliseconds>;
auto tp = time_point{1439467747492ms};
auto dp = floor<days>(tp);
auto time = make_time(tp - dp);
auto ymd = year_month_day{dp};
cout << "GMT: " << weekday{dp} << ", " << ymd.day() << ' ' << ymd.month()
<< ' ' << ymd.year() << ' ' << time << " GMT\n";
}
Output:
GMT: Thu, 13 Aug 2015 12:09:07.492 GMT
I threw in the fractional seconds for fun, and it seemed a shame to waste them (the C lib won't give them to you). If you really don't want them, it is easy to fix:
auto time = make_time(floor<seconds>(tp) - dp);
Now the output is:
GMT: Thu, 13 Aug 2015 12:09:07 GMT
You need C++14 for the 1439467747492ms above. If you only have C++11 you can sub in this instead: milliseconds{1439467747492}. If you only have C++03, then you are 13 years behind the times and stuck with ctime. ;-)
The chrono solution will offer you greater type safety, more flexibility, and greater performance.
If i can fix and the latitude and longitude problem would be great lol
If you can translate latitude and longitude into an IANA timezone name (and there are tools to do this), I've got a IANA timezone database parser for you which interoperates with <chrono> and "date.h".
#include <iostream>
#include <cstring>
#include <time.h>
using namespace std;
int main()
{
long test = 1439467747492;
time_t x = test;
cout << ctime( &x ) << endl;
return 0;
}
Produces
Tue Sep 18 20:15:32 1990

Get time difference with DST considered

I am using Boost.Date_time to get the time difference between two dates. I want the code to consider DST change as well during these days and give me the correct interval.
Consider this example. On 1-Nov-2015, the DST is going to change in USA. At 2:00 hours, the clock will be moved back to 1:00. The output of the below code doesn't reflect that. It gives 23 hours as the difference.
date d1(2015, 11, 1);
ptime nov1_00(d1, hours(0));
ptime nov1_23(d1, hours(23));
seconds = (nov1_23 - nov1_00).total_seconds();
Output:
2015-Nov-01 00:00:00. 2015-Nov-01 23:00:00. Seconds: 82800
Is there a way in boost to specify the DST requirement in this scenario?
You should be using local times:
Live On Coliru
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/local_time/local_date_time.hpp>
#include <boost/date_time/local_time/local_time_io.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
int main() {
namespace lt = boost::local_time;
namespace pt = boost::posix_time;
using date = boost::gregorian::date;
lt::tz_database db;
db.load_from_file("/home/sehe/custom/boost/libs/date_time/data/date_time_zonespec.csv");
//for (auto region : db.region_list()) std::cout << region << "\n";
auto NY = db.time_zone_from_region("America/New_York");
date const d1(2015, 11, 1);
lt::local_date_time nov1_00(d1, pt::hours(0), NY, true);
lt::local_date_time nov1_23(d1, pt::hours(23), NY, false);
lt::local_time_period period(nov1_00, nov1_23);
std::cout << "period: " << period << "\n";
std::cout << "duration: " << period.length() << "\n";
// if you insist:
auto seconds = (nov1_23 - nov1_00).total_seconds();
std::cout << "seconds: " << seconds << "\n";
}
Prints:
period: [2015-Nov-01 00:00:00 EDT/2015-Nov-01 22:59:59.999999 EST]
duration: 24:00:00
seconds: 86400