Updated Examples and Recipes (markdown)

Howard Hinnant
2016-05-29 22:34:04 -04:00
parent f580e3e093
commit 4318716ed2

@@ -4,6 +4,7 @@ This page contains examples and recipes contributed by community members. Feel f
- [Obtaining a `time_point` from `y/m/d h:m:s` components](#time_point_to_components) - [Obtaining a `time_point` from `y/m/d h:m:s` components](#time_point_to_components)
- [Obtaining `y/m/d h:m:s` components from a `time_point`](#components_to_time_point) - [Obtaining `y/m/d h:m:s` components from a `time_point`](#components_to_time_point)
- [Normalizing `y/m/d` when it is `!ok()`](#normalize) - [Normalizing `y/m/d` when it is `!ok()`](#normalize)
- [When is it ok to be `!ok()`?](#not_ok_is_ok)
- [Converting from {year, microseconds} to CCSDS](#ccsds) - [Converting from {year, microseconds} to CCSDS](#ccsds)
- [Difference in months between two dates](#deltamonths) - [Difference in months between two dates](#deltamonths)
- [Parsing ISO strings](http://stackoverflow.com/a/33438989/576911) - [Parsing ISO strings](http://stackoverflow.com/a/33438989/576911)
@@ -157,6 +158,79 @@ Outputs:
The specifications for these functions do not yet guarantee this "normalization behavior." But the implementation has been thoroughly tested for this behavior and the specification will be updated soon. The specifications for these functions do not yet guarantee this "normalization behavior." But the implementation has been thoroughly tested for this behavior and the specification will be updated soon.
<a name="not_ok_is_ok"></a>
### When is it ok to be `!ok()`?
(by [Howard Hinnant](https://github.com/HowardHinnant))
This library allows dates to silently fall into a state of `!ok()`. Why does not `!ok()` assert or throw? When is it *ever* ok to be `!ok()`?
Consider this problem:
I want to find all dates for some year `y` which are the 5th Friday of the month (because that is party day or whatever). Here is a **very** efficient function which collects all of the 5th Fridays of a year:
std::pair<std::array<date::year_month_day, 5>, unsigned>
fifth_friday(date::year y)
{
using namespace date;
std::array<year_month_day, 5> dates{0_y/0/0, 0_y/0/0, 0_y/0/0, 0_y/0/0, 0_y/0/0};
unsigned n = 0;
for (auto m = jan; true; ++m)
{
auto d = fri[5]/m/y;
if (d.ok())
{
dates[n] = year_month_day{d};
++n;
}
if (m == dec)
break;
}
return {dates, n};
}
It turns out that it is an invariant that *every* year will have either 4 or 5 months which will have 5 Fridays. So we can efficiently return the results as a `pair<array<year_month_day, 5>, unsigned>`, where the second member of the `pair` will always be either 4 or 5.
The first job is just to initialize the `array` with a bunch of `year_month_day`s. I've arbitrarily chosen `0_y/0/0` as a good initialization value. What do I like about this value? One of the things I like is that it is `!ok()`!. If I accidentally access `.first[4]` when `.second == 4`, an extra bit of safety is that the resultant `year_month_day` is `!ok()`. So being able to construct these `!ok()` values without an assert or exception is important just for that reason (like a `nan`). The cost? Nothing. These are compile-time constants.
Next I iterate over each month for the year `y`. The first thing to do is construct the 5th Friday for this month/year pair:
auto d = fri[5]/m/y;
Now since not every month has a 5th Friday, this may not result in a valid date. But in this function the proper response to constructing an invalid date _is not_ an assert nor an exception. The _proper_ response is to _ignore_ the date and iterate on to the next month. If it is a valid date, then it pushed on to the result.
This function can be exercised like this:
int
main()
{
using namespace std::chrono;
using namespace date;
auto current_year = year_month_day{floor<days>(system_clock::now())}.year();
auto dates = fifth_friday(current_year);
std::cout << "Fifth Friday dates for " << current_year << " are:\n";
for (auto i = 0u; i < dates.second; ++i)
std::cout << dates.first[i] << '\n';
}
The variable `current_year` is initialized with the current year in the UTC time zone (close enough for government work -- use "tz.h" if you need to make it more exact to your locale). Then it is a simple matter to feed `current_year` into `fifth_friday` and iterate over the results. This just output for me:
Fifth Friday dates for 2016 are:
2016-01-29
2016-04-29
2016-07-29
2016-09-30
2016-12-30
Next year it will output:
Fifth Friday dates for 2017 are:
2017-03-31
2017-06-30
2017-09-29
2017-12-29
_Many_ invalid dates were computed during the execution of this program. And _none_ of them represented errors.
<a name="ccsds"></a> <a name="ccsds"></a>
### Converting from {year, microseconds} to CCSDS ### Converting from {year, microseconds} to CCSDS
(by [Howard Hinnant](https://github.com/HowardHinnant)) (by [Howard Hinnant](https://github.com/HowardHinnant))