TimelineCpp20CoreLanguage

Calendar and Time-Zones in C++20: Time-Zones

This post concludes my introduction to the chrono extension in C++20. Today I present the time-zones functionality.

 TimelineCpp20CoreLanguage

I should have written today I mainly present the time-zones functionality in C++20. Before I write about the time zones in C++20, I want to present the online resource Examples and Recipes from Howard Hinnant, which has about 40 examples of the new chrono functionality. Presumably, the chrono extension in C++20 is not easy to get; therefore it’s pretty essential to have so many examples. You should use these examples as a starting point for further experiments and sharpen your understanding. You can also add your recipes.

To get an idea of Examples and Recipes, I want to present a program for Roland Bock that calculates ordinal dates.

Calculating Ordinal Dates

An ordinal date consists of a year and a day of year (1st of January being day 1, 31st of December being day 365 or day 366). The year can be obtained directly from year_month_day. And calculating the day is wonderfully easy. In the code below we make us of the fact that year_month_day can deal with invalid dates like the 0th of January:” (Roland Bock)

I added the necessary headers to Roland’s program.

// ordinalDate.cpp

#include "date.h"
#include <iomanip>
#include <iostream>

int main()
{
   using namespace date;
   
   const auto time = std::chrono::system_clock::now();
   const auto daypoint = floor<days>(time);                    // (1) 
   const auto ymd = year_month_day{daypoint};         
   
   // calculating the year and the day of the year
   const auto year = ymd.year();
   const auto year_day = daypoint - sys_days{year/January/0}; // (2) 
                                                              // (3)
   std::cout << year << '-' << std::setfill('0') << std::setw(3) << year_day.count() << std::endl;
   
   // inverse calculation and check
   assert(ymd == year_month_day{sys_days{year/January/0} + year_day});
}

 

I want to add a few remarks to the program. Line (1) truncates the current time point. The value is used in the following line to initialize a calendar date. Line (2) calculates the time duration between the two time points. Both time points have the resolution day. Finally, year_day.count() inline (3) returns the time duration in days.ordinalDate2

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    My following examples of time zones are also inspired by the already mentioned web resource Examples and Recipes.

    Times-Zones

    First, a time zone is a region and its entire history of the date, such as daylight saving time or leap seconds. The time-zone library in C++20 is a complete parser of the IANA timezone database. The following table should give you a first idea of the new functionality.

    timeZone

    I use in my examples the function std::chrono::zones_time , which is essentially a time zone combined with a time point.

    Before I show you two examples, I want to make a short remark. To compile a program using the time-zone library, you have to compile the tz.cpp file and link it against the curl library. The curl library is necessary to get the current IANA timezone database. The following command line for G++ should give you the idea:

    g++ localTime.cpp -I <Path to data/tz.h> tz.cpp -std=c++17 -lcurl -o localTime
    

     

    My first program is straightforward. It displays the UTC and the local time.

    UTC Time and Local Time

    The UTC or Coordinated Univeral Time is the primary time standard worldwide. A computer uses Unix time which is a very close approximation of UTC. The UNIX time is the number of seconds since the Unix epoch. The Unix epoch is 00:00:00 UTC on 1 January 1970.

    std::chrono::system_clock::now() inline (1) returns in the following program localTime.cpp the Unix time.

     

    // localTime.cpp
    
    #include "date/tz.h"
    #include <iostream>
    
    int main() {
    
        std::cout << std::endl;
    
        using namespace date;
     
        std::cout << "UTC  time" << std::endl;             // (1)
        auto utcTime = std::chrono::system_clock::now();
        std::cout << "  " << utcTime << std::endl;
        std::cout << "  " << date::floor<std::chrono::seconds>(utcTime) << '\n':
    
        std::cout << std::endl;
        
        std::cout << "Local time" << std::endl;            // (2)
        auto localTime = date::make_zoned(date::current_zone(), utcTime);
        std::cout << "  " << localTime << std::endl;
        std::cout << "  " << date::floor<std::chrono::seconds>(localTime.get_local_time()) 
                << std::endl;
    
        auto offset = localTime.get_info().offset;         // (3)
        std::cout << "  UTC offset: "  << offset << std::endl;
    
        std::cout << std::endl;
    
    }
    

     

    I have not added too much to the program. The code block beginning with line (1) gets the current time point, truncates it to seconds, and displays it. The call date::make_zoned creates  std::chrono::zoned_time localTime. The following call localTime.get_local_time() returns the stored time point as a local time. This time point is also truncated to seconds. localTime (line 3) can also be used to get information about the time zone. In this case, I’m interested in the offset to the UTC.

    localTime

    My last program answers a crucial question when I teach in a different time zone: When should I start my online class?

    Various Time Zones for Online Classes

    The program onlineClass.cpp answers the following question: How late is it in given time zones, when I start an online class at the 7h, 13h, or 17h local time (Germany)?

    The online class should start on the 1st of February 2021, taking 4 hours. Because daylight saves time, the calendar date is essential to get the correct answer.

     

    // onlineClass.cpp
    
    #include "date/tz.h"
    #include <algorithm>
    #include <iomanip>
    #include <iostream>
    
    template <typename ZonedTime>
    auto getMinutes(const ZonedTime& zonedTime) {                         // (1)
        return date::floor<std::chrono::minutes>(zonedTime.get_local_time());
    }
    
    void printStartEndTimes(const date::local_days& localDay,            // (2)
                            const std::chrono::hours& h, 
                            const std::chrono::hours& durationClass,
                            const std::initializer_list<std::string>& timeZones ){
        
        date::zoned_time startDate{date::current_zone(), localDay + h};  // (4)
        date::zoned_time endDate{date::current_zone(), localDay + h + durationClass};
        std::cout << "Local time: ["  << getMinutes(startDate) << ", " 
                                      << getMinutes(endDate) << "]" << std::endl;
    // (5)
    longestStringSize = std::max(timeZones, [](const std::string& a, const std::string& b) { return a.size() < b.size(); }).size(); for (auto timeZone: timeZones) { // (6) std::cout << " " << std::setw(longestStringSize + 1) << std::left << timeZone << "[" << getMinutes(date::zoned_time(timeZone, startDate)) << ", " << getMinutes(date::zoned_time(timeZone, endDate)) << "]" << std::endl; } } int main() { using namespace std::string_literals; using namespace std::chrono; std::cout << std::endl; constexpr auto classDay{date::year(2021)/2/1}; constexpr auto durationClass = 4h; auto timeZones = {"America/Los_Angeles"s, "America/Denver"s, "America/New_York"s, "Europe/London"s, "Europe/Minsk"s, "Europe/Moscow"s, "Asia/Kolkata"s, "Asia/Novosibirsk"s, "Asia/Singapore"s, "Australia/Perth"s, "Australia/Sydney"s}; for (auto startTime: {7h, 13h, 17h}) { // (3) printStartEndTimes(date::local_days{classDay}, startTime, durationClass, timeZones); std::cout << std::endl; } }

     

    Before I dive into the functions getMinutes (line 1) and printStartEndTimes (line 2), let me say a few words about the main function. The main function defines the day of the class, the duration of the class, and all time zones. Finally, the range-based for-loop (line 3) iterates through all potential starting points for an online class. All necessary information is displayed thanks to the function
    (line 2).

    The few lines beginning with line (4) calculate the startDate and endDate of my training by adding the start and class duration to the calendar date. Both values are displayed with the help of the function getMinutes (line 1). date::floor<std::chrono::minutes>(zonedTime.get_local_time()) gets the stored time point out of the std::chrono::zoned_time and truncates the value to the minute resolution. To properly align the output of the program, line (5) determines the size of the longest of all time-zone names. Line (6) iterates through all time zones and displays the name of the time-zone and the beginning and end of each online class. A few calendar dates even cross the day boundaries.onlineClass

    There is more to write about in the extended Chrono library. For example, C++20 offers new clocks such as std::chrono::utc_clock that include leap seconds, or the std::chrono::tai_clock that represents the International Atomic Time (TAI). Additionally, thanks to the new formatting library in C++20, time durations can be nicely formatted. This feature is not available so far. If you want to study the formatting rules for time durations, here are they: std::formatter.

    What’s next?

    You may have a lot of fun if you want to compare signed and unsigned integrals. This fun ends with C++20.

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery,and Matt Godbolt.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Modernes C++ GmbH

    Modernes C++ Mentoring (English)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *