The Boost C++ Libraries

Location-dependent Times

Unlike the location-independent times introduced in the previous section, location-dependent times account for time zones. Boost.DateTime provides the class boost::local_time::local_date_time, which is defined in boost/date_time/local_time/local_time.hpp. This class stores time-zone related data using boost::local_time::posix_time_zone.

Example 36.17. Using boost::local_time::local_date_time
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

using namespace boost::local_time;
using namespace boost::posix_time;
using namespace boost::gregorian;

int main()
{
  time_zone_ptr tz{new posix_time_zone{"CET+1"}};
  ptime pt{date{2014, 5, 12}, time_duration{12, 0, 0}};
  local_date_time dt{pt, tz};
  std::cout << dt.utc_time() << '\n';
  std::cout << dt << '\n';
  std::cout << dt.local_time() << '\n';
  std::cout << dt.zone_name() << '\n';
}

The constructor of boost::local_time::local_date_time expects its first parameter to be an object of type boost::posix_time::ptime and its second parameter to be an object of type boost::local_time::time_zone_ptr. boost::local_time::time_zone_ptr is a type definition for boost::shared_ptr<boost::local_time::time_zone>. The type definition is based on boost::local_time::time_zone, not boost::local_time::posix_time_zone. That’s fine because boost::local_time::posix_time_zone is derived from boost::local_time::time_zone. This makes it possible to extend Boost.DateTime with user-defined types for time zones.

No object of type boost::local_time::posix_time_zone is passed. Instead, a smart pointer referring to the object is passed. This allows multiple objects of type boost::local_time::local_date_time to share time-zone data. When the last object is destroyed, the object representing the time zone will automatically be released.

To create an object of type boost::local_time::posix_time_zone, a string describing the time zone is passed to the constructor as the only parameter. Example 36.17 specifies Central Europe as the time zone (CET is the abbreviation for Central European Time). Since CET is one hour ahead of UTC, the deviation is represented as +1. Boost.DateTime is not able to interpret abbreviations for time zones and thus does not know the meaning of CET. Therefore, the deviation must always be provided in hours; use the value +0 if there is no deviation.

The program writes the strings 2014-May-12 12:00:00, 2014-May-12 13:00:00 CET, 2014-May-12 13:00:00, and CET to the standard output stream. Values used to initialize objects of type boost::posix_time::ptime and boost::local_time::local_date_time always relate to the UTC time zone by default. When an object of type boost::local_time::local_date_time is written to the standard output stream or a call to the member function local_time() is made, the deviation in hours is used to calculate the local time.

Example 36.18. Location-dependent points in time and different time zones
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

using namespace boost::local_time;
using namespace boost::posix_time;
using namespace boost::gregorian;

int main()
{
  time_zone_ptr tz{new posix_time_zone{"CET+1"}};

  ptime pt{date{2014, 5, 12}, time_duration{12, 0, 0}};
  local_date_time dt{pt, tz};
  std::cout << dt.local_time() << '\n';

  time_zone_ptr tz2{new posix_time_zone{"EET+2"}};
  std::cout << dt.local_time_in(tz2).local_time() << '\n';
}

With local_time(), the deviation for the time zone is respected. In order to calculate the CET time, one hour needs to be added to the UTC time of 12 PM stored in dt, since CET is one hour ahead of UTC. That’s why local_time() writes 2014-May-12 13:00:00 to standard output in Example 36.18.

In contrast, the member function local_time_in() interprets the time stored in dt as being in the time zone that is passed as a parameter. This means that 12 PM UTC equals 2 PM EET which stands for Eastern European Time and is two hours ahead of UTC.

Finally, Boost.DateTime provides the class boost::local_time::local_time_period for location-dependent periods.

Example 36.19. Using boost::local_time::local_time_period
#include <boost/date_time/local_time/local_time.hpp>
#include <iostream>

using namespace boost::local_time;
using namespace boost::posix_time;
using namespace boost::gregorian;

int main()
{
  time_zone_ptr tz{new posix_time_zone{"CET+0"}};

  ptime pt1{date{2014, 12, 5}, time_duration{12, 0, 0}};
  local_date_time dt1{pt1, tz};

  ptime pt2{date{2014, 12, 5}, time_duration{18, 0, 0}};
  local_date_time dt2{pt2, tz};

  local_time_period tp{dt1, dt2};

  std::cout.setf(std::ios::boolalpha);
  std::cout << tp.contains(dt1) << '\n';
  std::cout << tp.contains(dt2) << '\n';
}

The constructor of boost::local_time::local_time_period in Example 36.19 expects two parameters of type boost::local_time::local_date_time. As with other types provided for periods, the second parameter, which represents the end time, is not part of the period. With the help of member functions such as contains(), intersection(), merge(), and others, you can process periods based on boost::local_time::local_time_period.