Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert boost ptime from local time to UTC

I have a boost::posix_time::ptime object (Boost v1.60) that has date and time information in the system's timezone. I need to convert this to a unix timestamp in UTC.

time_t convertLocalPtimeToTimestamp(const boost::posix_time::ptime& pt)
{
        using namespace boost::local_time;
        static const time_t t_null = 0;
        static struct tm* tm_local = localtime(&t_null);
        static time_zone_ptr zone(new posix_time_zone(tm_local->tm_zone));
        LOG(debug) << "Zone " << zone->to_posix_string();

        local_date_time az(pt.date(), pt.time_of_day(), zone, local_date_time::EXCEPTION_ON_ERROR);
        LOG(debug) << "local_date_time: " << az;
        LOG(debug) << "local_time: " << az.local_time();
        LOG(debug) << "utc_time: " << az.utc_time();
        struct tm t = to_tm(az);
        time_t ts = mktime(&t);

        return ts;
}

The result in my case (Europe/Madrid) is:

Zone CET+00
local_date_time: 2016-Oct-05 17:36:27.701162 CET
local_time: 2016-Oct-05 17:36:27.701162
utc_time: 2016-Oct-05 17:36:27.701162
1475685387

There are various errors in this result:

  • Timezone should be detected as daylight saving: CEST (+0200) not CET (+0100)
  • Even without DST detection, utc_time should be different from local_time.
  • Finally the timestamp should represent UTC time, not local time.

Any help would be appreciated.

like image 832
JanCG Avatar asked Mar 10 '23 23:03

JanCG


1 Answers

Here's my Boost implementation of the problem to solve.

I did not want to use another third party library, and I had problems in Windows with jgaida's answer (tm_zone and tm_gmtoff are not members of tm).

I tested this code by changing the time zone in my Windows 10 PC several times.

The edge cases "(UTC-12:00) International Date Line West" and "(UTC+14:00) Kiritimati Island)" were also tested and the results were successful.

time_t convertLocalPtimeToTimestamp (const boost::posix_time::ptime& pt)
{
   using namespace boost::posix_time;
   using namespace boost::local_time;

   _tzset (); // This is needed if the time zone changes after the program starts.

   // Grab copies of the current time in local and UTC form.
   auto p_time = microsec_clock::universal_time (); // UTC.
   auto lp_time = boost::date_time::c_local_adjustor<ptime>::utc_to_local (p_time);

   // Calculate the difference between the UTC and local time and put it in a string.
   // This will yield "-07:00:00" for PST and "-08:00:00" for PDT.
   auto time_diff = to_simple_string (lp_time - p_time);

   // Convert the ptime to a local_date_time object using the local time zone.
   // We will create the time zone with the time difference string generated above.
   local_date_time local_time (p_time, time_zone_ptr (new posix_time_zone (time_diff)));

   // Calculate the difference in milliseconds between the UTC and local time.
   auto time_t_diff = to_time_t (p_time) - to_time_t (local_time.local_time ());

   // Return the given time in ms plus the time_t difference (to get the UTC ms).
   return to_time_t (pt) + time_t_diff;
}
like image 159
Zo_ Avatar answered Mar 19 '23 10:03

Zo_