C++11 added a date and time utility library called chrono, available in namespace std::chrono and header <chrono> . The problem with it is that the library is a general purpose one and therefore lacks many useful features, such as working with dates, weeks, calendars, timezones and other related features. Fortunately, a rich date and time library based on chrono has been created by Howard Hinnant and is available on github. The library is called date and is actually a collection of several small libraries:

date: the main library, available in header date.h , defines new date and time classes and operations with them. All the other libraries are based on this one.

, defines new date and time classes and operations with them. All the other libraries are based on this one. timezones: a library for timezones, available in files tz.h / tz.cpp , based on the IANA timezone database

/ , based on the IANA timezone database chrono_io: a library for streaming durations, available in header chrono_io.h

iso_week: a library that implements the ISO week calendar, available in header iso_week.h

julian and islamic: libraries that implement the Julian and Islamic calendars, available in headers julian.h and islamic.h

You can find all the necessary documentation on github. Here are several links:

In this article we will look at some examples for working with dates and ISO weeks. This library introduces many new types to handle various date and time representations. Among these we will look at:

sys_days : A count of days since std::system_clock ‘s epoch. This is a time_point with a resolution of a day, and is implicitly convertible to std::system_clock::time_point , that has a much smaller resolution (millisecond or nanosecond), but not the other way around. To go the other way you must use floor() .

: A count of days since ‘s epoch. This is a with a resolution of a day, and is implicitly convertible to , that has a much smaller resolution (millisecond or nanosecond), but not the other way around. To go the other way you must use . year_month_day : A type that holds a day with fields for year, month (1 to 12) and day (1 to 31).

: A type that holds a day with fields for year, month (1 to 12) and day (1 to 31). year_month_weekday : A type that holds a day with fields for year, month (1 to 12), a day of the week (0 to 6), and an index in the range [1, 5] that indicates the number of the week in the month.

: A type that holds a day with fields for year, month (1 to 12), a day of the week (0 to 6), and an index in the range [1, 5] that indicates the number of the week in the month. year_weeknum_weekday : A type that hold a year, a weeknum (1 to 53) and a weekday (0 to 6). This can convert implicitly to and from a sys_days .

For using the library we need the following:

include header date.h and namespaces date and date::literals

and namespaces and for iso weeks we also need header iso_week.h and namespaces iso_week and iso_week::literals

and namespaces and NOTICE: The namespaces date::literals and iso_week::literals define types and literal operators with the same name and therefore can lead to name collisions; therefore you should only include them in the scope where you need them.

We will use the following lambda expression to print various dates to the console:

auto lprintdate = [](auto const & d) {std::cout << d << std::endl; }; 1 auto lprintdate = [ ] ( auto const & d) {std::cout << d << std::endl; } ;

NOTICE: All the ‘today’ and related dates below are based on 2016-10-31.

Let us look at some examples:

create sys_days objects (including literals): sys_days d1 = 2016_y / oct / 29; sys_days d2 = 29_d / oct / 2016; sys_days d3 = oct / 29 / 2016; auto today = floor<days>(system_clock::now()); lprintdate(d1); // 2016-10-29 lprintdate(d2); // 2016-10-29 lprintdate(d3); // 2016-10-29 lprintdate(today); // 2016-10-31 1 2 3 4 5 6 7 8 9 sys_days d1 = 2016_y / oct / 29 ; sys_days d2 = 29_d / oct / 2016 ; sys_days d3 = oct / 29 / 2016 ; auto today = floor < days > ( system_clock : : now ( ) ) ; lprintdate ( d1 ) ; // 2016-10-29 lprintdate ( d2 ) ; // 2016-10-29 lprintdate ( d3 ) ; // 2016-10-29 lprintdate ( today ) ; // 2016-10-31

objects (including literals): create year_month_day objects (including literals): year_month_day d1 = 2016_y / oct / 29; year_month_day d2 = 29_d / oct / 2016; year_month_day d3 = oct / 29 / 2016; year_month_day today = floor<days>(system_clock::now()); lprintdate(d1); // 2016-10-29 lprintdate(d2); // 2016-10-29 lprintdate(d3); // 2016-10-29 lprintdate(today); // 2016-10-31 1 2 3 4 5 6 7 8 9 year_month_day d1 = 2016_y / oct / 29 ; year_month_day d2 = 29_d / oct / 2016 ; year_month_day d3 = oct / 29 / 2016 ; year_month_day today = floor < days > ( system_clock : : now ( ) ) ; lprintdate ( d1 ) ; // 2016-10-29 lprintdate ( d2 ) ; // 2016-10-29 lprintdate ( d3 ) ; // 2016-10-29 lprintdate ( today ) ; // 2016-10-31

objects (including literals): creating year_month_weekday literals and converting to year_month_day auto wd1 = 2016_y / oct / mon[1]; auto wd2 = mon[1] / oct / 2016; auto wd3 = oct / mon[1] / 2016; lprintdate(wd1); // 2016/Oct/Mon[1] lprintdate(wd2); // 2016/Oct/Mon[1] lprintdate(wd3); // 2016/Oct/Mon[1] auto d1 = year_month_day{ wd1 }; auto d2 = year_month_day{ wd2 }; auto d3 = year_month_day{ wd2 }; lprintdate(d1); // 2016-10-03 lprintdate(d2); // 2016-10-03 lprintdate(d3); // 2016-10-03 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 auto wd1 = 2016_y / oct / mon [ 1 ] ; auto wd2 = mon [ 1 ] / oct / 2016 ; auto wd3 = oct / mon [ 1 ] / 2016 ; lprintdate ( wd1 ) ; // 2016/Oct/Mon[1] lprintdate ( wd2 ) ; // 2016/Oct/Mon[1] lprintdate ( wd3 ) ; // 2016/Oct/Mon[1] auto d1 = year_month_day { wd1 } ; auto d2 = year_month_day { wd2 } ; auto d3 = year_month_day { wd2 } ; lprintdate ( d1 ) ; // 2016-10-03 lprintdate ( d2 ) ; // 2016-10-03 lprintdate ( d3 ) ; // 2016-10-03

literals and converting to create year_month_day values for today, yesterday and tomorrow auto today = floor<days>(system_clock::now()); auto tomorrow = today + days{ 1 }; auto yesterday = today - days{ 1 }; lprintdate(yesterday); // 2016-10-30 lprintdate(today); // 2016-10-31 lprintdate(tomorrow); // 2016-11-01 1 2 3 4 5 6 7 auto today = floor < days > ( system_clock : : now ( ) ) ; auto tomorrow = today + days { 1 } ; auto yesterday = today - days { 1 } ; lprintdate ( yesterday ) ; // 2016-10-30 lprintdate ( today ) ; // 2016-10-31 lprintdate ( tomorrow ) ; // 2016-11-01

values for today, yesterday and tomorrow create year_month_day values for first and last day of the month auto today = year_month_day{ floor<days>(system_clock::now()) }; auto first_day_this_month = year_month_day{ today.year(), today.month(), day{ 1 } }; lprintdate(first_day_this_month);// 2016-10-01 auto d1 = year_month_day_last(today.year(), month_day_last{ today.month() }); auto last_day_this_month = year_month_day{ d1 }; lprintdate(last_day_this_month); // 2016-10-31 auto d2 = year_month_day_last(year{ 2016 }, month_day_last{ month{ 2 } }); auto last_day_feb = year_month_day{ d2 }; lprintdate(last_day_feb); // 2016-02-29 1 2 3 4 5 6 7 8 9 10 11 auto today = year_month_day { floor < days > ( system_clock : : now ( ) ) } ; auto first_day_this_month = year_month_day { today . year ( ) , today . month ( ) , day { 1 } } ; lprintdate ( first_day_this_month ) ; // 2016-10-01 auto d1 = year_month_day_last ( today . year ( ) , month_day_last { today . month ( ) } ) ; auto last_day_this_month = year_month_day { d1 } ; lprintdate ( last_day_this_month ) ; // 2016-10-31 auto d2 = year_month_day_last ( year { 2016 } , month_day_last { month { 2 } } ) ; auto last_day_feb = year_month_day { d2 } ; lprintdate ( last_day_feb ) ; // 2016-02-29 Update: The following, as indicated by Howard Hinnant in the comments, can also be used: year_month_day first_day_this_month = today.year()/today.month()/1; year_month_day last_day_this_month = today.year()/today.month()/last; 1 2 year_month_day first_day_this_month = today . year ( ) / today . month ( ) / 1 ; year_month_day last_day_this_month = today . year ( ) / today . month ( ) / last ;

values for first and last day of the month create iso_week literals auto isod1 = 2016_y / 42 / mon; auto isod2 = 42_w / mon / 2016_y; auto isod3 = mon / 42_w / 2016_y; lprintdate(isod1); // 2016-W44-Mon lprintdate(isod2); // 2016-W44-Mon lprintdate(isod3); // 2016-W44-Mon 1 2 3 4 5 6 7 auto isod1 = 2016_y / 42 / mon ; auto isod2 = 42_w / mon / 2016_y ; auto isod3 = mon / 42_w / 2016_y ; lprintdate ( isod1 ) ; // 2016-W44-Mon lprintdate ( isod2 ) ; // 2016-W44-Mon lprintdate ( isod3 ) ; // 2016-W44-Mon

literals get the iso week number for today auto today = floor<days>(system_clock::now()); auto today_iso = year_weeknum_weekday{ today }; lprintdate(today_iso); // 2016-W44-Mon std::cout << "week " << (unsigned)today_iso.weeknum() << std::endl; //44 1 2 3 4 5 auto today = floor < days > ( system_clock : : now ( ) ) ; auto today_iso = year_weeknum_weekday { today } ; lprintdate ( today_iso ) ; // 2016-W44-Mon std : : cout < < "week " < < ( unsigned ) today_iso . weeknum ( ) < < std : : endl ; //44

We will look at more utilities and examples in another post.

Share this: Facebook

Twitter

Print

More

Email

Reddit



