Updated Examples and Recipes (markdown)

Howard Hinnant
2017-04-17 13:31:19 -04:00
parent 7e7754d287
commit 8fd308e2d7

@@ -89,27 +89,30 @@ All IANA timezone names (or links -- aliases to timezones) are supported.
Would you just like to know how many hours ahead or behind your friend is in another time zone? Here's how you do that with this library.
#include "tz.h"
#include <iostream>
int
main()
{
auto current_time = std::chrono::system_clock::now();
auto la = date::make_zoned("America/Los_Angeles", current_time);
auto sy = date::make_zoned("Australia/Sydney", current_time);
std::cout << date::make_time(sy.get_local_time() - la.get_local_time()) << '\n';
}
```c++
#include "tz.h"
#include <iostream>
int
main()
{
auto current_time = std::chrono::system_clock::now();
auto la = date::make_zoned("America/Los_Angeles", current_time);
auto sy = date::make_zoned("Australia/Sydney", current_time);
std::cout << date::make_time(sy.get_local_time() - la.get_local_time()) << '\n';
}
```
Let's say you want to find out how many hours ahead Sydney is from LA (now). First get the current UTC time. Then create a `zoned_time` for both "America/Los_Angeles" and "Australia/Sydney" using that current UTC time. Then subtract their `local_time`s. `make_time` is a handy formatting tool for printing out that duration:
17:00:00.000000
Because we did not specify otherwise, the default behavior is to give us the full precision of `system_clock::time_point`. If you would prefer other behavior (e.g. minutes precision), that is easily accomplished with just a little more work. `using` directives make the code a little more readable:
```c++
using namespace date;
using namespace std::chrono;
std::cout << make_time(floor<minutes>(sy.get_local_time() - la.get_local_time())) << '\n';
```
And now the output is:
@@ -121,19 +124,21 @@ And now the output is:
Say you want to set up a video conference between New York and Moscow. This can be done in a few simple ways. First you need to decide when the meeting is going to be with respect to _somebody's_ clock. For example, let's say we want to have the meeting on Jul 8, 2016 at 9am in New York. How do we define that time, and then find the same instant in Moscow?
#include "tz.h"
#include <iostream>
```c++
#include "tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
auto ny = make_zoned("America/New_York", local_days{jul/8/2016} + 9h);
auto moscow = make_zoned("Europe/Moscow", ny);
std::cout << ny << '\n';
std::cout << moscow << '\n';
}
int
main()
{
using namespace std::chrono;
using namespace date;
auto ny = make_zoned("America/New_York", local_days{jul/8/2016} + 9h);
auto moscow = make_zoned("Europe/Moscow", ny);
std::cout << ny << '\n';
std::cout << moscow << '\n';
}
```
The use of `local_days` creates a calendar date local to whatever time zone you pair it with (in this case "America/New_York"). To make this some time other than midnight, just add the time duration since midnight (hours, minutes, seconds, whatever) to the `local_days`, in this case `9h` for 09:00:00. This forms a `zoned_time` that corresponds to 2016-07-08 09:00:00 EDT. To find the same time in Moscow, just create a new `zoned_time` with "Europe/Moscow" and the New York `zoned_time`. This creates a `zoned_time` with the equivalent UTC time, but associated with the time zone "Europe/Moscow".
@@ -144,23 +149,29 @@ Then just print it out:
Obviously you could just as easily specify the meeting in Moscow's time zone and then find the equivalent time in New York:
```c++
auto moscow = make_zoned("Europe/Moscow", local_days{8_d/jul/2016} + 16h);
auto ny = make_zoned("America/New_York", moscow);
```
This would result in the exact same output. For those paying attention, I reordered the date from m/d/y to d/m/y just to show that I could. The meaning is the same.
Sometimes it is convenient to specify the time independent of either timezone. For example this might be some celestial event such as an eclipse. Often such events are recorded in UTC so that people in all time zones can more easily know the correct time. It is just as easy to use UTC for this example:
```c++
auto utc = sys_days{2016_y/jul/8} + 13h;
auto ny = make_zoned("America/New_York", utc);
auto moscow = make_zoned("Europe/Moscow", utc);
```
I reordered the date to y/m/d just to show that I could. As long as the first unit is unambiguous (`year`, `month` or `day`), the following two are unambiguous (only `y/m/d`, `d/m/y` and `m/d/y` are accepted; all others are rejected at compile time).
Instead of `local_days`, `sys_days` is used instead. `sys_days` means UTC (technically it means [Unix Time](https://en.wikipedia.org/wiki/Unix_time) which is a very close approximation to UTC). Then you can construct each `zoned_time` with the UTC time (which has type `sys_time<hours>` in this example). You could also construct the second `zoned_time` from the first, just as before:
```c++
auto ny = make_zoned("America/New_York", sys_days{jul/8/2016} + 13h);
auto moscow = make_zoned("Europe/Moscow", ny);
```
In any event, the output is still:
@@ -177,31 +188,37 @@ After reading this [stack Overflow question/answers](http://stackoverflow.com/q/
So that I can more easily test the code to do this, I'm going to write this more generally as:
```c++
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t, const date::time_zone* zone);
```
And then create an overload to pass in the current time and current time zone:
```c++
inline
std::chrono::milliseconds
since_local_midnight()
{
return since_local_midnight(std::chrono::system_clock::now(), date::current_zone());
}
```
That way I can test things like times just after known daylight saving time transitions to make sure that my code is doing what I want it to.
This only takes a few lines of code:
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t, const date::time_zone* zone)
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned(zone, t);
zt = floor<days>(zt.get_local_time());
return floor<milliseconds>(t - zt.get_sys_time());
}
```c++
std::chrono::milliseconds
since_local_midnight(std::chrono::system_clock::time_point t, const date::time_zone* zone)
{
using namespace date;
using namespace std::chrono;
auto zt = make_zoned(zone, t);
zt = floor<days>(zt.get_local_time());
return floor<milliseconds>(t - zt.get_sys_time());
}
```
The first thing to do is create a `zoned_time` which really does nothing at all but pair `zone` and `t`. This pairing is mainly just to make the syntax nicer.
@@ -213,21 +230,27 @@ We can get the corresponding `sys_time` out of `zt` with `zt.get_sys_time()`. T
As a further testing aid, it is convenient to write a `since_local_midnight` that takes a `zoned_seconds` (which is a `zoned_time` with the precision of seconds) that calls into the main overload:
inline
std::chrono::milliseconds
since_local_midnight(const date::zoned_seconds& zt)
{
return since_local_midnight(zt.get_sys_time(), zt.get_time_zone());
}
```c++
inline
std::chrono::milliseconds
since_local_midnight(const date::zoned_seconds& zt)
{
return since_local_midnight(zt.get_sys_time(), zt.get_time_zone());
}
```
So to output the current time in milliseconds since the local midnight, you would just:
std::cout << since_local_midnight().count() << "ms\n";
```c++
std::cout << since_local_midnight().count() << "ms\n";
```
To ensure that our function is working, it is worthwhile to output a few example dates. This is most easily done by specifying a time zone (I'll use "America/New_York"), and some local date/times where I know the right answer:
auto zt = make_zoned(locate_zone("America/New_York"), local_days{jan/15/2016} + 3h);
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```c++
auto zt = make_zoned(locate_zone("America/New_York"), local_days{jan/15/2016} + 3h);
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```
This 3am in the middle of the Winter. This outputs:
@@ -237,8 +260,10 @@ which is correct (10800000ms == 3h).
I can run the test again just by assigning a new local time to `zt`. The following is 3am just after the "spring forward" daylight saving transition (2nd Sunday in March):
zt = local_days{sun[2]/mar/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```c++
zt = local_days{sun[2]/mar/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```
This outputs:
@@ -248,15 +273,18 @@ Because the local time from 2am to 3am was skipped, this correctly outputs 2 hou
An example from the middle of Summer gets us back to 3 hours after midnight:
zt = local_days{jul/15/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```c++
zt = local_days{jul/15/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```
2016-07-15 03:00:00 EDT is 10800000ms after midnight
And finally an example just after the Fall transition from daylight saving back to standard gives us 4 hours:
zt = local_days{sun[1]/nov/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```c++
zt = local_days{sun[1]/nov/2016} + 3h;
std::cout << zt << " is " << since_local_midnight(zt).count() << "ms after midnight\n";
```
2016-11-06 03:00:00 EST is 14400000ms after midnight