mirror of
https://github.com/HowardHinnant/date.git
synced 2025-08-04 21:24:26 +02:00
Updated FAQ (markdown)
82
FAQ.md
82
FAQ.md
@@ -1,5 +1,6 @@
|
|||||||
## Contents
|
## Contents
|
||||||
- [Why can't I do day arithmetic on a `year_month_day`?](#day_arithmetic)
|
- [Why can't I do day arithmetic on a `year_month_day`?](#day_arithmetic)
|
||||||
|
- [Why can't I do day arithmetic on a `year_month_day`, part 2?](#day_arithmetic2)
|
||||||
- [Why is `%A` failing?](#week_day_parse_bug)
|
- [Why is `%A` failing?](#week_day_parse_bug)
|
||||||
- [Why is `local_t` not a proper clock?](#local_t)
|
- [Why is `local_t` not a proper clock?](#local_t)
|
||||||
- [Why can't I compare instances of `zoned_time`?](#zoned_time_comparison)
|
- [Why can't I compare instances of `zoned_time`?](#zoned_time_comparison)
|
||||||
@@ -68,6 +69,87 @@ It would be very easy to add `T& list<T>::operator[](size_t index)`. But that w
|
|||||||
|
|
||||||
This library continues in that tradition: The expensive operations are not hidden.
|
This library continues in that tradition: The expensive operations are not hidden.
|
||||||
|
|
||||||
|
<a name="day_arithmetic2"></a>
|
||||||
|
### Why can't I do day arithmetic on a `year_month_day`, part 2?
|
||||||
|
|
||||||
|
Lately there has been a bit of mass hysteria over the impression that this library makes it between difficult and impossible to do day-oriented arithmetic on dates. Please let me assure you, it is very easy to add/subtract any number of days from a date. For example:
|
||||||
|
|
||||||
|
#include "date/date.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
using namespace date;
|
||||||
|
sys_days date = 2019_y/December/16;
|
||||||
|
date += days{100};
|
||||||
|
std::cout << date << '\n'; // Prints out: 2020-03-25
|
||||||
|
date = date - days{100};
|
||||||
|
std::cout << date << '\n'; // Prints out: 2019-12-16
|
||||||
|
}
|
||||||
|
|
||||||
|
So what's behind all of the excitement?
|
||||||
|
|
||||||
|
Bottom line: There's more than one calendrical ("date") class in this library and they are good at different things. And none of them can do everything. But the one thing that they can all do is easily convert to one another.
|
||||||
|
|
||||||
|
Here is an overview of 3 types in this library that each represent a date. All of these types are a calendar.
|
||||||
|
|
||||||
|
**`sys_days`**
|
||||||
|
|
||||||
|
`sys_days` is the _canonical_ calendrical type in this library. Every calendar can implicitly convert to and from it without loss of information. It is the "hub calendar". Under the hood it is nothing but a count of days since the 1970 epoch. And this data structure is what is used by most other date libraries, because it is very efficient at some important things.
|
||||||
|
|
||||||
|
`sys_days` is _very_ good at adding and subtracting days. It can do this in one assembly instruction and sub-nanosecond speeds, because all that happens is an integral addition/subtraction under the hood. It is also very good at interfacing with the existing `chrono` family of `system_clock` `time_point`s because `sys_days` *is* a `system_clock` `time_point` (of day-precision).
|
||||||
|
|
||||||
|
auto tp = date + 7h + 45min + 15s + 321ms; // tp is a system_clock time_point with millisecond precision
|
||||||
|
|
||||||
|
`sys_days` is _not_ good at extracting the year, month and day fields of a date. Most other libraries deal with this by ignoring the issue. They perform a computation that extracts all three fields (or nearly so) when you ask for the year. Then they perform the same computation when you ask for the month. And then again when you ask for the day. This library says: you can't ask `sys_days` for just one of these fields.
|
||||||
|
|
||||||
|
year y = date.year(); // compile-time error, date has type sys_days
|
||||||
|
|
||||||
|
Instead you can ask for all three fields at once:
|
||||||
|
|
||||||
|
year_month_day ymd = date; // ok, date has type sys_days
|
||||||
|
|
||||||
|
**`year_month_day`**
|
||||||
|
|
||||||
|
`year_month_day` is a simple `{year, month, day}` data structure. It is very good at returning the year, month and day fields. It is _not_ good at day-oriented arithmetic. To do that, the best thing to do is convert to `sys_days`, perform the arithmetic, and convert back. Or better yet, never convert to `year_month_day` in the first place if that makes sense for your application.
|
||||||
|
|
||||||
|
**`year_month_weekday`**
|
||||||
|
|
||||||
|
There's also a 3rd calendar that is a simple `{year, month, weekday, N}`, which represents the N<sup>*th*</sup> weekday of a month and year pair (e.g. 1<sup>*st*</sup> Sunday of May 2020). It also does not do day-oriented arithmetic. But it is very good at getting the year, month, weekday and N fields. And given a `sys_days` `date`, it is very easy to obtain a `year_month_weekday`:
|
||||||
|
|
||||||
|
year_month_weekday ymw = date; // ok, date has type sys_days
|
||||||
|
|
||||||
|
Or go the other way:
|
||||||
|
|
||||||
|
date = ymw;
|
||||||
|
|
||||||
|
One can even *explicitly* convert directly between `year_month_day` and `year_month_weekday`:
|
||||||
|
|
||||||
|
year_month_day ymd{ymw}; // ok
|
||||||
|
|
||||||
|
The compiler simply implicitly bounces off of `sys_days` under the hood.
|
||||||
|
|
||||||
|
Aside: You can even write your own calendar as long as it implicitly converts to and from `sys_days`. Then it interoperates with `year_month_day` and `year_month_weekday` exactly as above.
|
||||||
|
|
||||||
|
**So does this mean I can't add to the day field even if I know it won't overflow into the next month?**
|
||||||
|
|
||||||
|
Nope. You can easily add to the "day field" of a `year_month_day` or `year_month_weekday`. But in this case, it is up to you to do any necessary error checking if applicable.
|
||||||
|
|
||||||
|
year_month_day ymd = 2019_y/December/16; // 2019-12-16
|
||||||
|
ymd = ymd.year()/ymd.month()/(ymd.day() + days{1}); // 2019-12-17
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
year_month_weekday ymw = 2019_y/December/Monday[3]; // 3rd Monday of December 2019
|
||||||
|
ymw = ymw.year()/ymw.month()/ymw.weekday()[ymw.index()+1]; // 4th Monday of December 2019
|
||||||
|
|
||||||
|
Virtually no computation and little code generation takes place for either of the examples above. They just stuff new values into one of the fields.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
So choose whichever calendar is most useful for you. And when you need to, convert among them to get done what you need to get done. Your code will be efficient, readable, and type-safe.
|
||||||
|
|
||||||
<a name="week_day_parse_bug"></a>
|
<a name="week_day_parse_bug"></a>
|
||||||
### Why is `%A` failing?
|
### Why is `%A` failing?
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user