Dealing with time zone conversions (C++ / Boost)

August 4, 2016 - one comment. Posted by in Programming, Uncategorized.

Recently I was tasked with writing some code to convert between arbitrary time zones. I did some research and there are a few good libraries out there for C++ that make this task easy. I decided out implementation would use boost. We already use boost to handle various other things within our code base and some of the other solutions I found would require introducing some new dependencies I wasn’t comfortable with for this particular project.

I ended up using boost’s timezone database to store all of the available timezones. Although boost includes a sample timezone database I ended coordinating with the web guys, they are using moment.js and provided me with the timezone file they are using. My implementation uses a local resource which is a duplicate of this file but it can also update itself in the event that the timezone data changes (If you would like a copy shoot me an email).

The timezone data is in POSIX TZ format, now.. an interesting thing about boost is the way UTF offset are handled. I ended up having to invert the values for the timezone in order to get the calculations to work correctly. The function I used looks like this :

void TimeConversion::POSIXToBOOST(std::string& posixTZ)
{
    boost::local_time::posix_time_zone tz(posixTZ);

    //This conversion is required because boost expects offset inverse of standard format.
    //
    if (posixTZ.length() > 3)
    {
        uint32_t pos = tz.std_zone_abbrev().length();

        auto isMinus = posixTZ.at(pos) == '-';
        auto isZero = posixTZ.at(pos) == '0';

        if (isMinus)
        {
            posixTZ.replace(pos, 1, "");
        }
        else if (!isZero)
        {
            posixTZ.insert(pos, "-");
        }
    }
}

Now after I was done importing into the boost tz database, I wrote a few functions to do the actual conversion between time zones. The functions take the desired regions for which the conversion needs to happen.

boost::posix_time::ptime TimeConversion::ConvertTime(const std::string& timezoneRegion, const boost::posix_time::ptime& original, const std::string& convertToTimezoneRegion) const
{
    auto srcTimezone = m_timeZoneDB.time_zone_from_region(timezoneRegion);
    auto dstTimezone = m_timeZoneDB.time_zone_from_region(convertToTimezoneRegion);

    boost::local_time::local_date_time srcDateTime(original.date(), original.time_of_day(), srcTimezone, boost::local_time::local_date_time_base<>::NOT_DATE_TIME_ON_ERROR);

    return srcDateTime.local_time_in(dstTimezone).local_time();
}

boost::posix_time::ptime TimeConversion::ConvertTimeLocal(const std::string& timezoneRegion, const boost::posix_time::ptime& original) const
{
    auto srcTimezone = m_timeZoneDB.time_zone_from_region(timezoneRegion);

    boost::local_time::local_date_time srcDateTime(original.date(), original.time_of_day(), srcTimezone, boost::local_time::local_date_time_base<>::NOT_DATE_TIME_ON_ERROR);

    auto totalOffset = GetUTCOffset() - (srcDateTime.local_time() - srcDateTime.utc_time());

    return srcDateTime.local_time() + totalOffset;
}

Finally, in order for this to all work on windows (our special snowflake) I had to write some special code to convert the windows timezone names to the standard region names. I was able to find someone who had went through the trouble of creating a table which had the mappings I needed. I load these from a file with support for updates from our server. You can find it here. If it goes offline for some reason you can email me to request a copy. I converted it from XML to JSON for our purposes as it was easier to consume that way. The function listed below gives me the timezone in use on the machine, I then map this using the file above to the appropriate region.

std::string NinjaAgentCommon::GetWindowsTimeZone()
{
    // Windows Timezone info.
    TIME_ZONE_INFORMATION tzi;
   GetTimeZoneInformation(&tzi);

    // Timezone string
    return WCHAR2StdString(tzi.StandardName);
}

This library was a close runner up

https://howardhinnant.github.io/date/tz.html

This timezone library is probably one of the best I found, and I would not hesitate to use it under different circumstances. It provides a straight forward way to do time zone conversions as well as being cross platform and using the latest IANA timezone database.

 

Share Button

1 comment

  • Great article! I was considering using boost.

    Thanks for the great article!

    respond

Leave a comment

Share Button

Sign Up for the Newsletter

Get the latest updates.

RSS Game News

  • Layoffs loom at Radiant Worlds after SkySaga development halts 08/22/2017
    With development stalled, Radiant Worlds was unable to renew its contract with its publisher, cutting the studio off from its only income source and putting every position within the development house in jeopardy. ...
  • Blog: A gentle introduction to Steamworks 08/22/2017
    If you're just getting started with trying to implement Steam into your Unity game, it can be hard to know where to look. Here's a guide that should help you kick on with Steamworks. ...