Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
josuttis_nm_c20_the_complete_guide.pdf
Скачиваний:
44
Добавлен:
27.03.2023
Размер:
5.85 Mб
Скачать

348 Chapter 11: Dates and Timezones for <chrono>

11.1.2 Scheduling a Meeting on the Last Day of Every Month

Let us modify the first example program by iterating over the last days of each month. The way you can do that is as follows:

lib/chrono2.cpp

 

 

 

 

 

#include <chrono>

 

 

 

 

 

 

 

#include <iostream>

 

 

 

 

 

int main()

 

 

 

 

 

{

 

 

 

 

 

namespace chr = std::chrono;

// shortcut for std::chrono

 

 

 

using namespace std::literals;

// for h, min, y suffixes

 

 

 

// for each last of all months of 2021:

 

 

 

 

 

auto first = 2021y / 1 / chr::last;

 

 

 

for (auto d = first; d.year() == first.year(); d += chr::months{1}) {

 

 

 

// print out the date:

 

 

 

 

 

std::cout << d << ":\n";

 

 

 

 

 

// init and print 18:30 UTC of those days:

 

 

 

auto tp{chr::sys_days{d} + 18h + 30min};

 

 

 

std::cout << std::format(" We meet on {:%A %D at %R}\n", tp);

 

 

 

}

 

 

 

 

 

}

 

 

 

 

All we modified was the initialization of first. We declare it with type auto and initialize it with

 

 

 

 

std::chrono::last as day:

 

 

 

 

 

auto first = 2021y / 1 / chr::last;

 

 

 

 

The type std::chrono::last not only represents the last day of a month, it also has the effect that first has a different type: std::chrono::year_month_day_last. The effect is that by adding one month, the day of the date gets adjusted. In fact, the type just always holds the last day. The conversion to the numerical day happens when we output the date and specify a corresponding output format.

As a result, the output changes to the following:

2021/Jan/last:

We meet on Sunday 01/31/21 at 18:30 2021/Feb/last:

We meet on Sunday 02/28/21 at 18:30 2021/Mar/last:

We meet on Wednesday 03/31/21 at 18:30 2021/Apr/last:

We meet on Friday 04/30/21 at 18:30 2021/May/last:

We meet on Monday 05/31/21 at 18:30

...

2021/Nov/last:

11.1 Overview by Example

349

We meet on Tuesday 11/30/21 at 18:30 2021/Dec/last:

We meet on Friday 12/31/21 at 18:30

As you can see, the default output format of year_month_day_last uses last and slashes instead of dashes as a separator (only year_month_day uses hyphens in its default output format). For example:

2021/Jan/last

You could still declare first as std::chrono::year_month_day:

// for each last days of all months of 2021: std::chrono::year_month_day first = 2021y / 1 / chr::last;

for (auto d = first; d.year() == first.year(); d += chr::months{1}) {

//print out the date: std::cout << d << ":\n";

//init and print 18:30 UTC of those days:

auto tp{chr::sys_days{d} + 18h + 30min};

std::cout << std::format(" We meet on {:%D at %R}\n", tp);

}

However, this would cause the following output:

2021-01-31:

We meet on Sunday 01/31/21 at 18:30 2021-02-31 is not a valid date:

We meet on Wednesday 03/03/21 at 18:30 2021-03-31:

We meet on Wednesday 03/31/21 at 18:30 2021-04-31 is not a valid date:

We meet on Saturday 05/01/21 at 18:30 2021-05-31:

We meet on Monday 05/31/21 at 18:30

...

Because the type of first stores the numeric value of the day, initialized with the last day of January, we iterate over the 31st day of each month. If such a day does not exist, the default output format prints that this is an invalid date, while std::format() even performs a bad computation.

A way to deal with such situations is to check whether a date is valid and implement what to do then. For example:

lib/chrono3.cpp

#include <chrono> #include <iostream>

int main()

 

{

 

namespace chr = std::chrono;

// shortcut for std::chrono

using namespace std::literals;

// for h, min, y suffixes

350

Chapter 11: Dates and Timezones for <chrono>

 

 

 

 

// for each last of all months of 2021:

 

 

 

 

 

 

 

 

chr::year_month_day first = 2021y / 1 / 31;

 

 

 

 

for (auto d = first; d.year() == first.year(); d += chr::months{1}) {

 

 

 

 

// print out the date:

 

 

 

 

if (d.ok()) {

 

 

 

 

std::cout << d << ":\n";

 

 

 

 

}

 

 

 

 

else {

 

 

 

 

// for months not having the 31st use the 1st of the next month:

 

 

 

 

auto d1 = d.year() / d.month() / 1 + chr::months{1};

 

 

 

 

std::cout << d << ":\n";

 

 

 

 

}

 

 

 

 

// init and print 18:30 UTC of those days:

 

 

 

 

auto tp{chr::sys_days{d} + 18h + 30min};

 

 

 

 

std::cout << std::format(" We meet on {:%A %D at %R}\n", tp);

 

 

 

}

}

 

 

 

 

 

By using the member function ok(), we adjust an invalid date to take the first day of the next month. We get the following output:

2021-01-31:

 

 

We meet on

Sunday 01/31/21 at

18:30

2021-02-31 is not a valid date:

 

We meet on

Wednesday 03/03/21

at 18:30

2021-03-31:

 

 

We meet on

Wednesday 03/31/21

at 18:30

2021-04-31 is not a valid date:

 

We meet on

Saturday 05/01/21 at 18:30

2021-05-31:

 

 

We meet on

Monday 05/31/21 at

18:30

...

 

 

2021-11-31 is not a valid date:

 

We meet on

Wednesday 12/01/21

at 18:30

2021-12-31:

 

 

We meet on

Friday 12/31/21 at

18:30

11.1.3 Scheduling a Meeting Every First Monday

In a similar way, we can schedule a meeting on each first Monday of a month:

lib/chrono4.cpp

#include <chrono> #include <iostream>

int main()

11.1 Overview by Example

351

{

 

namespace chr = std::chrono;

// shortcut for std::chrono

using namespace std::literals;

// for min, h, y suffixes

// for each first Monday of all months of 2021:

auto first = 2021y / 1 / chr::Monday[1];

for (auto d = first; d.year() == first.year(); d += chr::months{1}) {

//print out the date: std::cout << d << '\n';

//init and print 18:30 UTC of those days:

 

auto tp{chr::sys_days{d} + 18h + 30min};

 

std::cout << std::format(" We meet on {:%A %D at %R}\n", tp);

 

}

 

 

}

 

 

Again, first has a special type, std::chrono::year_month_weekday, which represents a weekday in a month of a year:

The default output format signals that with a specific format. However, the formatted output works fine:

2021/Jan/Mon[1]

We meet on Monday 01/04/21 at 18:30 2021/Feb/Mon[1]

We meet on Monday 02/01/21 at 18:30 2021/Mar/Mon[1]

We meet on Monday 03/01/21 at 18:30 2021/Apr/Mon[1]

We meet on Monday 04/05/21 at 18:30 2021/May/Mon[1]

We meet on Monday 05/03/21 at 18:30

...

2021/Nov/Mon[1]

We meet on Monday 11/01/21 at 18:30 2021/Dec/Mon[1]

We meet on Monday 12/06/21 at 18:30

Calendrical Types for Weekdays

This time, we initialize first as an object of the calendrical type std::chrono::year_month_weekday and initialize it with the first Monday of January of 2021:

auto first = 2021y / 1 / chr::Monday[1];

Again, we use operator/ to combine different date fields. However, this time, types for weekdays come into play:

First, we call 2021y / 1 to combine a std::chrono::year with an integral value to create a std::chrono::year_month.