diff --git a/Examples-and-Recipes.md b/Examples-and-Recipes.md index e8c1fe5..5927fa0 100644 --- a/Examples-and-Recipes.md +++ b/Examples-and-Recipes.md @@ -5,6 +5,7 @@ This page contains examples and recipes contributed by community members. Feel f - [The current time somewhere else](#elsetime) - [Get the current difference between any two arbitrary time zones](#deltatz) - [Set simultaneous meeting in two different time zones](#meeting) +- [Get milliseconds since the local midnight](#since_midnight) - [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) - [Normalizing `y/m/d` when it is `!ok()`](#normalize) @@ -157,6 +158,101 @@ In any event, the output is still: 2016-07-08 09:00:00 EDT 2016-07-08 16:00:00 MSK + +### Get milliseconds since the local midnight +(by [Howard Hinnant](https://github.com/HowardHinnant)) + +After reading this [stack Overflow question/answers](http://stackoverflow.com/q/11128629/576911) I decided it would be good to show how to solve this problem using this library. As the question is not crystal clear what it is asking, I will attempt to create an unambiguous problem statement here: + +> Find the time duration in milliseconds since the last midnight in the local time zone. + +So that I can more easily test the code to do this, I'm going to write this more generally as: + + 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: + + 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(zt.get_local_time()); + return floor(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. + +The next step is to get the local time associated with `t`. That is what `zt.get_local_time()` does. This will have whatever precision `t` has, unless `t` is coarser than seconds, in which case the local time will have a precision of seconds. + +The call to `floor` _truncates_ the local time to a precision of `days`. This effectively creates a `local_time` equal to the local midnight. By assigning this `local_time` back to `zt`, we don't change the time zone of `zt` at all, but we change the `local_time` of `zt` to midnight (and thus change its `sys_time` as well). + +We can get the corresponding `sys_time` out of `zt` with `zt.get_sys_time()`. This is the UTC time which corresponds to the local midnight. It is then an easy process to subtract this from the input `t` and truncate the results to the desired precision. + +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()); + } + +So to output the current time in milliseconds since the local midnight, you would just: + + 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"; + +This 3am in the middle of the Winter. This outputs: + + 2016-01-15 03:00:00 EST is 10800000ms after midnight + +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"; + +This outputs: + + 2016-03-13 03:00:00 EDT is 7200000ms after midnight + +Because the local time from 2am to 3am was skipped, this correctly outputs 2 hours since midnight. + +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"; + + 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"; + + 2016-11-06 03:00:00 EST is 14400000ms after midnight + +Not only does this library make it easy to write the code to do the desired computation, it also makes it easy to write the test code. + ### Obtaining a `time_point` from `y/m/d h:m:s` components (by [ecorm](https://github.com/ecorm))