TimelineCpp20CoreLanguage

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

A new type of the chrono extension in C++20 is a calendar date. C++20 offers various ways to create a calendar date and interact with them.

 

TimelineCpp20CoreLanguage

It took me a while to understand the almost twenty calendar-related data types. For that reason, I start with a calendar date. As in my last post, “Calendar and Time-Zones in C++20: Time of Day “, I use the date library from Howard Hinnant as the prototype of the new chrono extension.

 

Calendar Date

A calendar date is a date that consists of a year, a month, and a day. Consequently, C++20 has a specific data type std::chrono::year_month_day. C++20 has way more to offer. Both tables present the first overview.

calendar1

calendar2

 

 

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.

     

    Let’s start simple. The following program createCalendar.cpp shows various ways to create calendar-related dates.

     

    // createCalendar.cpp
    
    #include <iostream>
    #include "date.h"
     
    int main() {
    
        std::cout << std::endl;
        
        using namespace date;
    
        constexpr auto yearMonthDay{year(1940)/month(6)/day(26)};            // (1)
        std::cout << yearMonthDay << " ";
        std::cout << date::year_month_day(1940_y, June, 26_d) << std::endl;  // (2)
    
        std::cout << std::endl;
    
        constexpr auto yearMonthDayLast{year(2010)/March/last};              // (3)
        std::cout << yearMonthDayLast << " ";
        std::cout << date::year_month_day_last(2010_y, month_day_last(month(3))) <<  std::endl;
    
        constexpr auto yearMonthWeekday{year(2020)/March/Thursday[2]};       // (4)
        std::cout << yearMonthWeekday << " ";
        std::cout << date::year_month_weekday(2020_y, month(March), Thursday[2]) <<  std::endl;
    
        constexpr auto yearMonthWeekdayLast{year(2010)/March/Monday[last]};  // (5)
        std::cout << yearMonthWeekdayLast << " ";
        std::cout << date::year_month_weekday_last(2010_y, month(March), weekday_last(Monday)) <<  std::endl;
    
        std::cout << std::endl;
    
        constexpr auto day_{day(19)};          // (5)
        std::cout << day_  << " ";
        std::cout << date::day(19) << std::endl;
    
        constexpr auto month_{month(1)};       // (6)
        std::cout << month_  << " ";
        std::cout << date::month(1) << std::endl;
    
        constexpr auto year_{year(1988)};      // (7)
        std::cout << year_  << " ";
        std::cout << date::year(1988) << std::endl;
    
        constexpr auto weekday_{weekday(5)};
        std::cout << weekday_  << " ";
        std::cout << date::weekday(5) << std::endl;
     
        constexpr auto yearMonth{year(1988)/1};
        std::cout << yearMonth  << " ";
        std::cout << date::year_month(year(1988), January) << std::endl;
     
        constexpr auto monthDay{10/day(22)};
        std::cout << monthDay <<  " ";
        std::cout << date::month_day(October, day(22)) << std::endl;
    
        constexpr auto monthDayLast{June/last};
        std::cout << monthDayLast << " ";
        std::cout << date::month_day_last(month(6)) << std::endl;
     
        constexpr auto monthWeekday{2/Monday[3]};
        std::cout << monthWeekday << " ";
        std::cout << date::month_weekday(February, Monday[3]) << std::endl;
     
        constexpr auto monthWeekDayLast{June/Sunday[last]};
        std::cout << monthWeekDayLast << " ";
        std::cout << date::month_weekday_last(June, weekday_last(Sunday)) << std::endl;
    
        std::cout << std::endl;
    
    }
    

     

    There are essentially two ways to create a calendar date. You can use the so-called cute syntax yearMonthDay{year(1940)/month(6)/day(26)} (line 1), or you can use the explicit type date::year_month_day(1940_y, June, 26_d) (line 2). To not overwhelm you, I am delaying my explanation of the cute syntax to the next section of this post. The explicit type is quite interesting because it uses the date time literals 1940_y, 26_d, and the predefined constant June. With C++20, the date literals 1940_y and 26_d are written without an underscore: 1940y  and 26d. This was the prominent part.

    Line (3), line (4), and line (5) offer convenient ways to create calendar dates.

    • Line (3): the last day of March 2010: {year(2010)/March/last} or year_month_day_last(2010_y, month_day_last(month(3))
    • Line (4): the second Thursday of March 2020: {year(2020)/March/Thursday[2]} or year_month_weekday(2020_y, month(March), Thursday[2])
    • Line (5): the last Monday of March 2010: {year(2010)/March/Monday[last]} or year_month_weekday_last(2010_y, month(March), weekday_last(Monday))

    The remaining calendar types stand for a day (line 6), a month (line 7), or a year (line 8). You can combine them as basic building blocks for fully specified calendar dates, such as lines (3) to (4).

    Before I dive more into the details, here is the program’s output.

    calendarDate

    As promised, let me write about the cute syntax.

    Cute Syntax

    The cute syntax consists of overloaded division operators to specify a calendar date. The overloaded operators support time literals (e.g.: 2020_y, 31_d) and constants (January, February, March, April, May, June, July, August, September, October, November, December).

    The following three combinations of year, month, and day are possible using the cute syntax.

    1. year/month/day
    2. day/month/year
    3. month/day/year

    These combinations are not arbitrarily chosen because they are the used ones worldwide. Each other combination is not allowed

    Consequently, when you choose the type year, month, or day for the first argument, the type for the remaining two arguments is no longer necessary, and an integral would do the job.

     

    // cuteSyntax.cpp
    
    #include <iostream>
    #include "date.h"
    
    int main() {
    
        std::cout << std::endl;
    
        using namespace date;
    
        constexpr auto yearMonthDay{year(1966)/6/26};
        std::cout << yearMonthDay << std::endl;
    
        constexpr auto dayMonthYear{day(26)/6/1966};
        std::cout << dayMonthYear << std::endl;
    
        constexpr auto monthDayYear{month(6)/26/1966};
        std::cout << monthDayYear << std::endl;
    
        constexpr auto yearDayMonth{year(1966)/month(26)/6};  //(1)
        std::cout << yearDayMonth << std::endl;
    
        std::cout << std::endl;
    
    }
    

     

    The combination year/day/month (line 1) is not allowed and causes a run-time message.

    cuteSyntaxI assume you want to display a calendar date {year(2010)/March/last} in a readable form, such as 2020-03-31. This is a job for the local_days or sys_days operator.

    Displaying Calendar Dates

    Thanks to std::chrono::local_days or std::chrono::sys_days, you can convert calendar dates to a std::chrono::time_point representing the same date as this year_month_day. I use std::chrono::sys_days in my example. std::chrono::sys_days is based on std::chrono::system_clock. Let me convert the calendar dates (line (3) – line (5) from the previous program createCalendar.cpp.

     

    // sysDays.cpp
    
    #include <iostream>
    #include "date.h"
     
    int main() {
    
        std::cout << std::endl;
        
        using namespace date;
    
        constexpr auto yearMonthDayLast{year(2010)/March/last};
        std::cout << "sys_days(yearMonthDayLast): " << sys_days(yearMonthDayLast)  <<  std::endl;
    
        constexpr auto yearMonthWeekday{year(2020)/March/Thursday[2]};
        std::cout << "sys_days(yearMonthWeekday): " <<  sys_days(yearMonthWeekday) << std::endl;
    
        constexpr auto yearMonthWeekdayLast{year(2010)/March/Monday[last]};
        std::cout << "sys_days(yearMonthWeekdayLast): " << sys_days(yearMonthWeekdayLast) << std::endl;
    
        std::cout << std::endl;
    
        constexpr auto leapDate{year(2012)/February/last};                // (1)
        std::cout << "sys_days(leapDate): " << sys_days(leapDate) << std::endl;
    
        constexpr auto noLeapDate{year(2013)/February/last};              // (2)
        std::cout << "sys_day(noLeapDate): " << sys_days(noLeapDate) << std::endl;
    
        std::cout << std::endl;
    
    }   
    

     

    The std::chrono::last constant let me quickly determine how many days a month has. Consequently, the output shows that 2012 is a leap year but not 2013.

    sysDays

    What’s next?

    Working with calendar dates becomes powerful when you check if a calendar date is valid or when you add a time duration.

     

    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

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Contact Me

    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 *