Close Menu
GeekBlog

    Subscribe to Updates

    Get the latest creative news from FooBar about art, design and business.

    What's Hot

    Trump Renamed AI “Super Intelligence.” The Word Already Meant Something Else.

    October 1, 2026

    Pixel Watch 2 Support Ends Today: What You Lose and What to Do Next

    October 1, 2026

    Singapore Built a Dating App That Pays for Your First Date. There Is a Catch About Who Can Use It.

    October 1, 2026
    Facebook
    GeekBlog
    • Home
    • Mobile
    • Tech News
    • Blog
    • Gaming
    • Smartwatch
    • How-To Guides
    • AI & Software
    Facebook
    GeekBlog
    Home»Blog»How to Convert GMT Time to Other Time Zones in C++
    Blog

    How to Convert GMT Time to Other Time Zones in C++

    Ethan CaldwellBy Ethan CaldwellSeptember 23, 202611 Mins Read
    Share Facebook Twitter Pinterest LinkedIn Tumblr Email Copy Link
    Round clock with a colorful world map face, illustrating converting GMT to other time zones in C++
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link

    To convert a GMT time to another time zone in C++, store the GMT moment in a std::chrono::sys_seconds and wrap it in a std::chrono::zoned_time with an IANA zone name such as America/New_York. The library applies the offset and daylight saving rules in force on that date, so you never add or subtract hours yourself.

    Quick answer: Build a sys_seconds from your GMT value, write std::chrono::zoned_time local{"America/Chicago", gmt}; and print it with std::format("{:%F %T %Z}", local). This works on GCC 13 or newer (GCC 14 adds std::chrono::parse) and on MSVC since Visual Studio 2019 16.10. Clang’s own libc++ still treats it as experimental, so with libc++ or an older compiler use Howard Hinnant’s date library.

    Every program below was compiled on Ubuntu 24.04 with g++-14 -std=c++20 -Wall -Wextra (GCC 14.2) without warnings, and each output block is what it printed, using tzdata 2026a. One surprise: the stock GCC 13.3 also ran the zoned_time examples, because libstdc++ gained time zone support in GCC 13.1. It only lacks std::chrono::parse, added in GCC 14.

    Which compilers support C++20 time zones in 2026

    Support depends on the standard library, not the compiler front end: Clang 18 on Ubuntu uses libstdc++ by default and compiled our first example with identical output. This is the picture as of September 2026.

    Toolchainzoned_time and tzdbchrono::parseZone data source
    GCC 13 (libstdc++)Yes, since 13.1NoSystem tzdata.zi, with an embedded fallback copy
    GCC 14 and 15YesYesSame as GCC 13
    GCC 16Yes, and C++20 is the default dialectYesSame; current_zone() also works on Windows
    MSVCYes, since Visual Studio 2019 16.10YesWindows ICU (Windows 10 version 1903 or later), updated by Windows Update
    Clang with libc++Experimental, needs -fexperimental-libraryNot implemented yetSystem tzdata.zi on Linux

    GCC 13 to 15 label C++20 library support experimental; GCC 16.1, released April 30, 2026, drops that label. On MSVC, chrono formatting works under /std:c++20 since Visual Studio 2022 version 17.2.

    Convert a GMT time with zoned_time

    sys_seconds is a time point on system_clock, which counts seconds since 1970 in UTC and ignores leap seconds. That is what a GMT timestamp from a log or an API means in practice.

    #include <chrono>
    #include <format>
    #include <iostream>
    
    int main() {
        using namespace std::chrono;
    
        // A fixed GMT instant: September 23, 2026 at 14:30:00
        sys_seconds gmt = sys_days{2026y / September / 23} + 14h + 30min;
        std::cout << std::format("GMT                  {:%F %T}\n", gmt);
    
        for (const char* name : {"America/New_York", "America/Chicago", "America/Phoenix",
                                 "America/Los_Angeles", "Europe/London", "Asia/Kolkata",
                                 "Etc/GMT+5"}) {
            zoned_time local{name, gmt};
            std::cout << std::format("{:<20} {:%F %T %Z (%z)}\n", name, local);
        }
    }
    $ g++-14 -std=c++20 -Wall -Wextra gmt_to_zones.cpp -o gmt_to_zones && ./gmt_to_zones
    GMT                  2026-09-23 14:30:00
    America/New_York     2026-09-23 10:30:00 EDT (-0400)
    America/Chicago      2026-09-23 09:30:00 CDT (-0500)
    America/Phoenix      2026-09-23 07:30:00 MST (-0700)
    America/Los_Angeles  2026-09-23 07:30:00 PDT (-0700)
    Europe/London        2026-09-23 15:30:00 BST (+0100)
    Asia/Kolkata         2026-09-23 20:00:00 IST (+0530)
    Etc/GMT+5            2026-09-23 09:30:00 -05 (-0500)

    Phoenix and Los Angeles show the same clock time but different abbreviations, because Arizona does not observe daylight saving time. Kolkata uses a half hour offset. %Z prints the abbreviation and %z the numeric offset, which is what a machine should read back. For many values, call locate_zone() once and reuse the pointer. The last line is a trap explained below.

    Parsing a GMT string first

    std::chrono::parse reads text straight into a sys_seconds and sets the fail bit when the format does not match.

    #include <chrono>
    #include <format>
    #include <iostream>
    #include <sstream>
    #include <string>
    
    // Parse "YYYY-MM-DD HH:MM:SS" as GMT/UTC. Returns false on bad input.
    bool parse_gmt(const std::string& text, std::chrono::sys_seconds& out) {
        std::istringstream in{text};
        in >> std::chrono::parse("%F %T", out);
        return !in.fail();
    }
    
    int main() {
        using namespace std::chrono;
    
        for (std::string text : {"2026-09-23 14:30:00", "09/23/2026 2:30 PM"}) {
            sys_seconds gmt;
            if (!parse_gmt(text, gmt)) {
                std::cout << "could not parse: " << text << '\n';
                continue;
            }
            zoned_time ny{"America/New_York", gmt};
            zoned_time la{"America/Los_Angeles", gmt};
            std::cout << std::format("{} GMT\n  New York:    {:%F %R %Z}\n  Los Angeles: {:%F %R %Z}\n",
                                     text, ny, la);
        }
    }

    Recommended for you:

    Russia’s Sovereign Internet Law Explained: What Runet Rules Prohibit
    Blog·Sep 23, 2026

    Russia’s Sovereign Internet Law Explained: What Runet Rules Prohibit

    $ g++-14 -std=c++20 -Wall -Wextra parse_gmt.cpp -o parse_gmt && ./parse_gmt
    2026-09-23 14:30:00 GMT
      New York:    2026-09-23 10:30 EDT
      Los Angeles: 2026-09-23 07:30 PDT
    could not parse: 09/23/2026 2:30 PM

    On GCC 13.3 the same file fails to compile:

    $ g++-13 -std=c++20 -Wall -Wextra parse_gmt.cpp -o parse_gmt
    parse_gmt.cpp:10:24: error: 'parse' is not a member of 'std::chrono'
    Tip: For ISO 8601 text ending in Z (2026-09-23T14:30:00Z) use the format "%FT%TZ". For text with a numeric offset (2026-09-23T10:30:00-04:00) use "%FT%T%Ez". Both produced 14:30:00 GMT in our tests. For the current time, use floor<seconds>(system_clock::now()).

    Why a fixed offset gives the wrong answer

    The classic bug is a hard coded offset: “Eastern is GMT minus five.” In New York that holds for about four months a year.

    #include <chrono>
    #include <format>
    #include <iostream>
    
    int main() {
        using namespace std::chrono;
        const time_zone* ny = locate_zone("America/New_York");
    
        for (sys_days day : {sys_days{2026y / January / 15}, sys_days{2026y / July / 15}}) {
            sys_seconds gmt = day + 17h;
            auto fixed = gmt - 5h;          // "Eastern is GMT minus 5", hard coded
            zoned_time real{ny, gmt};       // rules from the tz database
            std::cout << std::format("GMT {:%F %R} | fixed: {:%R} | tzdb: {:%R %Z}\n",
                                     gmt, fixed, real);
        }
    }
    $ ./fixed_offset_bug
    GMT 2026-01-15 17:00 | fixed: 12:00 | tzdb: 12:00 EST
    GMT 2026-07-15 17:00 | fixed: 12:00 | tzdb: 13:00 EDT

    In July the constant is an hour off. Offsets also change by law: IANA tz release 2026d, published September 11, 2026, records Canada’s Northwest Territories moving to a permanent offset six hours behind UTC. A constant never picks that up; the tz database does once the machine’s data is updated.

    GMT versus UTC, and the Etc/GMT trap

    Strictly, GMT is the old astronomical time of the Greenwich meridian and UTC is the atomic scale kept close to it with leap seconds. For conversions both are the same zero offset. In C++ they differ only in leap seconds: utc_clock counts them (27 so far, per get_leap_second_info in our test) and system_clock does not.

    Two traps remain. Etc/GMT+5 uses the POSIX sign convention, so it is five hours behind GMT. And Europe/London switches to BST in summer, so if a spec says “GMT” but means UK time, use Europe/London.

    From local time back to GMT: gaps and overlaps

    A local clock time maps to one GMT instant, to none (the hour skipped in spring) or to two (the hour repeated in fall). time_zone::to_sys() throws in the last two cases unless you choose.

    #include <chrono>
    #include <format>
    #include <iostream>
    
    int main() {
        using namespace std::chrono;
        const time_zone* ny = locate_zone("America/New_York");
    
        local_seconds meeting = local_days{2026y / September / 23} + 10h + 30min;
        std::cout << std::format("10:30 New York = {:%F %T} GMT\n", ny->to_sys(meeting));
    
        // 2:30 AM on March 8, 2026 never happens: clocks jump from 2:00 to 3:00
        local_seconds skipped = local_days{2026y / March / 8} + 2h + 30min;
        try {
            std::cout << std::format("{:%T}\n", ny->to_sys(skipped));
        } catch (const nonexistent_local_time& e) {
            std::cout << e.what() << '\n';
        }
    
        // 1:30 AM on November 1, 2026 happens twice: clocks fall back from 2:00 to 1:00
        local_seconds twice = local_days{2026y / November / 1} + 1h + 30min;
        std::cout << std::format("1:30 AM on Nov 1 = {:%T} or {:%T} GMT\n",
                                 ny->to_sys(twice, choose::earliest),
                                 ny->to_sys(twice, choose::latest));
    }
    $ ./local_to_gmt
    10:30 New York = 2026-09-23 14:30:00 GMT
    2026-03-08 02:30:00 is in a gap between
    2026-03-08 02:00:00 EST and
    2026-03-08 03:00:00 EDT which are both equivalent to
    2026-03-08 07:00:00 UTC
    1:30 AM on Nov 1 = 05:30:00 or 06:30:00 GMT

    In production, pick a policy with choose::earliest or choose::latest, which never throw; for a skipped time both return the jump itself, 07:00 GMT. To reject bad input, catch nonexistent_local_time and ambiguous_local_time as in our guide on how to catch exceptions in C++. Store GMT and convert only for display; a job that fires at a local wall time can use sleep_until, covered in how to add a delay in C++.

    Fallbacks: the date library and plain C

    Howard Hinnant’s date library

    On older compilers, C++17 or libc++, use Howard Hinnant’s date library. Slightly modified versions of its date.h and tz.h were voted into the C++20 draft in March 2018, so the API is nearly identical. Compile src/tz.cpp too; USE_OS_TZDB=1 reads the zone files in /usr/share/zoneinfo.

    // Fallback for compilers without C++20 time zones: github.com/HowardHinnant/date
    #include "date/tz.h"
    #include <chrono>
    #include <iomanip>
    #include <iostream>
    
    int main() {
        using namespace date;          // only date, never also std::chrono (ambiguous in C++20)
        namespace ch = std::chrono;
    
        sys_seconds gmt = sys_days{2026_y / September / 23} + ch::hours{14} + ch::minutes{30};
        for (const char* name : {"America/New_York", "America/Los_Angeles", "Asia/Kolkata"}) {
            auto local = make_zoned(name, gmt);
            std::cout << std::left << std::setw(21) << name
                      << date::format("%F %T %Z (%z)", local) << '\n';
        }
    }
    $ g++-13 -std=c++17 -Wall -Wextra -DUSE_OS_TZDB=1 -Idate/include \
          hinnant_date.cpp date/src/tz.cpp -o hinnant_date && ./hinnant_date
    America/New_York     2026-09-23 10:30:00 EDT (-0400)
    America/Los_Angeles  2026-09-23 07:30:00 PDT (-0700)
    Asia/Kolkata         2026-09-23 20:00:00 IST (+0530)

    It also builds with g++-14 -std=c++20. Our first draft did not: with both using namespace date; and using namespace std::chrono;, C++20 mode fails with reference to 'sys_days' is ambiguous.

    C and POSIX: TZ, tzset and localtime_r

    Plain C has no zone objects. On POSIX systems you set TZ, call tzset(), and let localtime_r() convert a time_t.

    #define _POSIX_C_SOURCE 200809L
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void) {
        time_t gmt = 1790173800;   /* 2026-09-23 14:30:00 GMT */
        const char *zones[] = {"America/New_York", "Asia/Kolkata", "Not/A_Zone"};
    
        for (int i = 0; i < 3; i++) {
            struct tm local;
            char buf[64];
            setenv("TZ", zones[i], 1);   /* process wide, not thread safe */
            tzset();
            localtime_r(&gmt, &local);
            strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S %Z (%z)", &local);
            printf("%-18s %s\n", zones[i], buf);
        }
        return 0;
    }
    $ gcc-14 -std=c17 -Wall -Wextra posix_tz.c -o posix_tz && ./posix_tz
    America/New_York   2026-09-23 10:30:00 EDT (-0400)
    Asia/Kolkata       2026-09-23 20:00:00 IST (+0530)
    Not/A_Zone         2026-09-23 14:30:00 Not (+0000)

    Note the last line: glibc treats an unknown zone as UTC and invents the abbreviation “Not”. TZ is also process wide, so this is unsafe while other threads format times (see our guide to threads in C++).

    Troubleshooting

    Recommended for you:

    How to Launch MODX on A2 Hosting (Now Hosting.com)
    Blog·Sep 23, 2026

    How to Launch MODX on A2 Hosting (Now Hosting.com)

    current_zone() returns UTC even though TZ is set

    libstdc++ reads the /etc/localtime symlink, then /etc/timezone, then falls back to UTC. On Linux it ignores TZ (the GCC 14 and 16 sources check it only on AIX); with TZ=America/Denver our container still reported Etc/UTC. Pass the zone name from configuration.

    Conversions silently use old rules

    Print get_tzdb().version. With /usr/share/zoneinfo hidden, our binary switched to the copy embedded in libstdc++ and reported tzdb version: 2024a without any error. Install and update tzdata (apt-get install -y tzdata); long running services can call std::chrono::reload_tzdb().

    runtime_error: cannot locate zone

    Our test printed std::chrono::tzdb: cannot locate zone: Not/A_Zone. Use IANA names. PDT is not a zone, and EST is a legacy fixed offset: in July it printed EST -0500 while America/New_York printed EDT -0400.

    parse is not a member of std::chrono

    You are on GCC 13 or libc++. Upgrade to GCC 14, or use date::parse from the date library.

    Frequently asked questions

    Is GMT the same as UTC in C++?

    For conversions, yes. The "GMT" and "UTC" zones both have a zero offset, and system_clock time points represent both. The only observable difference is leap seconds: utc_clock counts them and system_clock does not. Use sys_seconds for GMT timestamps unless you need exact elapsed seconds across leap seconds.

    Does zoned_time handle daylight saving time automatically?

    Yes. zoned_time applies the rules that were in force on the date you convert, including historical changes, so January and July results differ correctly. The direction that needs care is local time back to GMT, because skipped and repeated hours throw unless you pass choose::earliest or choose::latest.

    Can I use abbreviations like EST or PST as zone names?

    No. Abbreviations are ambiguous (in our tests CST appeared for Chicago, Shanghai and Havana), most are not zone names, and EST is a fixed offset with no daylight saving. Use IANA names such as America/Chicago. Abbreviations are fine in output through %Z if you also record the numeric offset.

    Which header and compiler flags do I need?

    Include <chrono> for the time zone types and <format> for std::format. With GCC compile with -std=c++20 or newer (GCC 16 defaults to C++20), and with MSVC use /std:c++20. libstdc++ needs no extra link flags, while libc++ still requires -fexperimental-library.

    The bottom line

    Keep GMT in a sys_seconds and convert with zoned_time and a real zone name only when a person needs to read the result. That habit removes the fixed offset, half hour zone and daylight saving bugs at once.

    GCC 13 or newer and current MSVC have what you need (GCC 14 for parse). On older compilers or libc++, the date library offers the same API. Either way, keep your tz data current.

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Telegram Email Copy Link
    Previous ArticleRussia’s Sovereign Internet Law Explained: What Runet Rules Prohibit
    Next Article Mercor Competitor Deccan AI Raises $25M, Sources Experts From India
    Ethan Caldwell

      Ethan Caldwell is GeekBlog's resident Apple specialist, covering the entire Apple ecosystem: iPhone, iPad, Mac, Apple Watch, AirPods and the software that ties them together. A longtime iOS user and gadget collector, Ethan tracks Cupertino's every move, breaking down Apple keynotes, A- and M-series chip benchmarks, iOS feature updates and the rumor mill into clear, practical takes that help readers decide whether the latest Apple hardware is worth the upgrade.

      Related Posts

      10 Mins Read

      Google Ads Keyword Planner: How It Shows the Most Relevant Keywords

      11 Mins Read

      How to Use Remarketing Techniques for Better Conversions

      11 Mins Read

      How to Conduct A/B Testing for Marketing Campaigns

      10 Mins Read

      AMP for WP Plugin Vulnerability: What Was Fixed and What to Do

      11 Mins Read

      How to Create a Facebook Business Page in 2026

      11 Mins Read

      Russia’s Sovereign Internet Law Explained: What Runet Rules Prohibit

      Top Posts

      Best Free Online Music Apps in 2026

      July 7, 20263 Views

      Chromebook vs PC: Which One Should You Actually Buy?

      July 7, 20262 Views

      The Light Flip Wants to Sell You a Phone That Does Less

      July 28, 20261 Views
      Stay In Touch
      • Facebook

      Subscribe to Updates

      Get the latest tech news from FooBar about tech, design and biz.

      Most Popular

      How to Convert HEIC to JPG on iPhone, Mac, Android and Windows

      September 3, 20266 Views

      Gal Gadot’s Lawyers Spent Six Months on One AI Clause. Then SAG Called Them for Pointers.

      September 2, 20265 Views

      The Mesh Router Placement Strategy That Finally Gave Me Full Home Coverage

      September 9, 20263 Views
      Our Picks

      Trump Renamed AI “Super Intelligence.” The Word Already Meant Something Else.

      October 1, 2026

      Pixel Watch 2 Support Ends Today: What You Lose and What to Do Next

      October 1, 2026

      Singapore Built a Dating App That Pays for Your First Date. There Is a Catch About Who Can Use It.

      October 1, 2026

      Subscribe to Updates

      Get the latest creative news from FooBar about art, design and business.

      HEICJPG.online - Convert HEIC to JPG online
      Facebook
      • About Us
      • Contact us
      • Privacy Policy
      • Disclaimer
      • Terms and Conditions
      • Editorial Policy
      • Cookie Policy
      • Your Privacy Choices
      © 2026 GeekBlog

      Type above and press Enter to search. Press Esc to cancel.