3

Based on Get the time zone GMT offset in C

#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */

#include <stdio.h>
#include <time.h>

/* Checking errors returned by system calls was omitted for the sake of readability. */
int main(void)
{
  time_t t = time(NULL);
  struct tm lt = {0};

  localtime_r(&t, &lt);

  printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
  printf("The time zone is '%s'.\n", lt.tm_zone);

  return 0;
}

Output for me is as follows:

The time zone is 'CDT'.

Now I need to create a local time with the given time zone.

http://www.boost.org/doc/libs/1_41_0/doc/html/date_time/local_time.html

time_zone_ptr zone; // how to convert 'CDT' to zone?
local_date_time ldt = local_microsec_clock::local_time(zone);

Question> How can I convert the time zone string 'CDT' to time_zone_ptr?

Thank you

Community
  • 1
  • 1
q0987
  • 34,938
  • 69
  • 242
  • 387
  • First, what is CDT? There are more than timezone using the abbreviation (you managed to **not** show the offset output of your sample...?). Next, if the first program prints that, then it's clearly the default timezone. – sehe Apr 13 '16 at 07:31

2 Answers2

0

You need a timezone database and a region. I can only guess what region you want, e.g. America/Chicago:

CDT will be observed in Chicago until 6 Nov 2016, 02:00

Here's the code:

boost::local_time::tz_database db;
db.load_from_file("/home/sehe/custom/boost/libs/date_time/data/date_time_zonespec.csv");

boost::local_time::local_date_time ldt { 
     boost::posix_time::ptime { {2016,4,1}, {10,15,2} }, 
     db.time_zone_from_region("America/Chicago") };
std::cout << ldt << "\n";

Prints

2016-Apr-01 05:15:02 CDT

Of course, change the path to your local boost library installation.

Listing regions:

To help with the mapping, you could do something like this:

for (auto& region : db.region_list()) {
    if (auto tz = db.time_zone_from_region(region))
    {
        std::cout << region << "\t" << tz->std_zone_abbrev() << "\t"  << tz->std_zone_name() << " (standard)\n";
        std::cout << region << "\t" << tz->dst_zone_abbrev() << "\t"  << tz->dst_zone_name() << " (daylight savings)\n";
    }
}

Which, if filtered for DST prints:

America/Cancun  CST CST (standard)
America/Cancun  CDT CDT (daylight savings)
--
America/Chicago CST Central Standard Time (standard)
America/Chicago CDT Central Daylight Time (daylight savings)
--
America/Havana  CST CST (standard)
America/Havana  CDT CDT (daylight savings)
--
America/Menominee   CST CST (standard)
America/Menominee   CDT CDT (daylight savings)
America/Merida  CST CST (standard)
America/Merida  CDT CDT (daylight savings)
America/Mexico_City CST CST (standard)
America/Mexico_City CDT CDT (daylight savings)
--
America/Monterrey   CST CST (standard)
America/Monterrey   CDT CDT (daylight savings)
--
America/North_Dakota/Center CST CST (standard)
America/North_Dakota/Center CDT CDT (daylight savings)
--
America/Rainy_River CST CST (standard)
America/Rainy_River CDT CDT (daylight savings)
America/Rankin_Inlet    CST CST (standard)
America/Rankin_Inlet    CDT CDT (daylight savings)
--
America/Winnipeg    CST CST (standard)
America/Winnipeg    CDT CDT (daylight savings)
sehe
  • 374,641
  • 47
  • 450
  • 633
0

Interesting question (upvoted). In general, this answer can not be answered without ambiguity. And "CDT"/now is a perfect example to demonstrate this. sehe's answer does a pretty good job of it using boost/datetime. This answer provides even more detail using this free, open source timezone library.

Here's the code, then the explanation, then the output, and then comparison to sehe's answer.

#include "tz.h"
#include <string>
#include <iostream>
#include <vector>

template <class Duration>
std::vector<date::time_zone const*>
find_by_abbrev(date::sys_time<Duration> tp, const std::string& abbrev)
{
    using namespace std::chrono;
    using namespace date;
    std::vector<time_zone const*> results;
    auto& db = get_tzdb();
    for (auto& z : db.zones)
    {
        if (z.get_info(tp).abbrev == abbrev)
            results.push_back(&z);
    }
    return results;
}

int
main()
{
    using namespace std::chrono;
    using namespace date;
    auto now = sys_days{2016_y/4/1} + 10h + 15min + 2s;
    auto v = find_by_abbrev(now, "CDT");
    for (auto zp : v)
        std::cout << make_zoned(zp, now) << " " << zp->name() << '\n';
}

The strategy is to make a list of all time zones currently using "CDT" as an abbreviation. To that end a function is created which takes a std::chrono::time_point<std::chrono::system_clock, Duration> and an abbreviation and returns a a vector<time_zone const*>. Once found, this vector can simply be iterated and information for each time zone can be printed out.

To implement find_by_abbrev, then entire time zone database must be searched. Each time_zone that uses an abbreviation abbrev at time tp is added to the list.

To make these results easy to compare to sehe's answer, I used the same time in my program (instead of the current time).

The program outputs:

2016-04-01 05:15:02 CDT America/Chicago
2016-04-01 06:15:02 CDT America/Havana
2016-04-01 05:15:02 CDT America/Indiana/Knox
2016-04-01 05:15:02 CDT America/Indiana/Tell_City
2016-04-01 05:15:02 CDT America/Matamoros
2016-04-01 05:15:02 CDT America/Menominee
2016-04-01 05:15:02 CDT America/North_Dakota/Beulah
2016-04-01 05:15:02 CDT America/North_Dakota/Center
2016-04-01 05:15:02 CDT America/North_Dakota/New_Salem
2016-04-01 05:15:02 CDT America/Rainy_River
2016-04-01 05:15:02 CDT America/Rankin_Inlet
2016-04-01 05:15:02 CDT America/Resolute
2016-04-01 05:15:02 CDT America/Winnipeg
2016-04-01 05:15:02 CDT CST6CDT

Now what I find especially interesting is to compare this output to sehe's answer which is based on boost/datetime:

This answer omits "America/Cancun" because it isn't currently using the abbreviation CDT, and hasn't since 2014-10-26 07:00:00 UTC.

Both answers show "America/Havana" as a potential CDT timezone, but only this answer shows that "America/Havana" alone has a UTC offset that is one hour less than all of the other candidate timezones.

Other differences continue, but with similar explanations.

This library allows you to control when/how-often you want to update your IANA database, and even offers automated downloading of the latest IANA database if your system has libcurl installed.

And using this library, I've demonstrated that "CDT/now" is not only ambiguous with respect to what IANA timezone should be chosen, but is also ambiguous as to what the current UTC offset of the chosen timezone should be. Typically to solve a problem like this, more a-priori knowledge is required, such as "I know the timestamp refers to one associated with USA" (or whatever).

But once you decide on a zone (by whatever heuristic):

auto zone = locate_zone(chosen_zone);
auto local = zone->to_local(system_clock::now());

and you've got it.

Disclaimer: Requires C++11 or better. This is a fairly modern library. It can not be ported without <chrono> support.

Community
  • 1
  • 1
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577