mirror of
https://github.com/HowardHinnant/date.git
synced 2025-08-05 13:44:26 +02:00
Updated Examples and Recipes (markdown)
@@ -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))
|
||||||
|
Reference in New Issue
Block a user