6

I have a UTC offset that is not known until run-time, and is not necessarily an integral number of hours. The IANA time zone database isn't a good match for this.

What is the simplest user-written time zone that can handle this?

1 Answer 1

8

Occasionally the IANA time zone database doesn't quite do everything you want. The <chrono> library allows you to use zoned_time with a time zone and/or pointer to time_zone of your own making. Below is an example which supplies a custom time_zone called OffsetZone which can hold a UTC offset with minutes precision determined at run time.

#include <chrono>

class OffsetZone
{
    std::chrono::minutes offset_;

public:
    explicit OffsetZone(std::chrono::minutes offset)
        : offset_{offset}
        {}

    template <class Duration>
        auto
        to_local(std::chrono::sys_time<Duration> tp) const
        {
            return std::chrono::local_time{(tp + offset_).time_since_epoch()};
        }

    template <class Duration>
        auto
        to_sys(std::chrono::local_time<Duration> tp) const
        {
            return std::chrono::sys_time{(tp - offset_).time_since_epoch()};
        }
};

This is about as simple as it gets with a user-written time_zone. But it can get much more elaborate as you need more functionality. But with just this simple example one can:

  • Construct the time_zone.
  • Install the time_zone into a zoned_time.
  • Get the sys_time out of the zoned_time.
  • Get the local_time out of the zoned_time.

Example:

#include <iostream>

int
main()
{
    using namespace std::chrono;
    auto offset = 3h + 45min;
    OffsetZone tz{offset};
    auto tp_utc = sys_days{2025y/5/3} + 22h;
    zoned_time zt{&tz, tp_utc};
    std::cout << zt.get_sys_time() << " UTC\n";
    std::cout << zt.get_local_time() << '\n';
}

The example above creates a UTC offset of 3 hours plus 45 minutes. This is stored in a non-constexpr variable to emphasize that this does not have to be compile-time information (maybe it was parsed from a file). This offset is used to construct the OffsetZone on the stack. And then a pointer to this "time zone" is used as the first argument to std::chrono::zoned_time.

Output:

2025-05-03 22:00:00 UTC
2025-05-04 01:45:00

Since we constructed the zoned_time with a sys_time, when we get the sys_time back out, it is the same time that was input. And the local_time is 3 hours, 45 minutes later. But one could instead construct the zoned_time with a local_time just by using local_days in place of sys_days:

Example:

#include <iostream>

int
main()
{
    using namespace std::chrono;
    auto offset = 3h + 45min;
    OffsetZone tz{offset};
    auto tp_loc = local_days{2025y/5/4} + 1h + 45min;
    zoned_time zt{&tz, tp_loc};
    std::cout << zt.get_sys_time() << " UTC\n";
    std::cout << zt.get_local_time() << '\n';
}

Output:

2025-05-03 22:00:00 UTC
2025-05-04 01:45:00

You don't have to use a built-in pointer to your time zone. You could just as easily use unique_ptr, shared_ptr, or whatever smart pointer is right for your application.

One can even have OffsetZone serve as its own smart pointer by giving it a member operator->() that returns itself:

const OffsetZone* operator->() const {return this;}

This allows you to embed the OffsetZone directly into the zoned_time instead of pointing to an externally held OffsetZone:

zoned_time zt{OffsetZone{offset}, tp_utc};

Once constructed in this fashion, use of the zoned_time continues as shown before.

I should also emphasize that one can use the time zone directly, without the use of a zoned_time (just like with std::chrono::time_zone):

Example:

#include <cassert>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    auto offset = 3h + 45min;
    OffsetZone tz{offset};
    auto tp_loc = local_days{2025y/5/4} + 1h + 45min;
    auto tp_utc = tz.to_sys(tp_loc);
    auto tp_loc2 = tz.to_local(tp_utc);
    assert(tp_loc == tp_loc2);
    std::cout << tp_utc << " UTC\n";
    std::cout << tp_loc2 << '\n';
}

Output:

2025-05-03 22:00:00 UTC
2025-05-04 01:45:00
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.