forked from HowardHinnant/HowardHinnant.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdate_v2.html
6634 lines (5456 loc) · 177 KB
/
date_v2.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>date redirect</title>
<META http-equiv="refresh" content="5;URL=http://howardhinnant.github.io/date/date.html">
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
background-color:#E0E0E0;
padding-left: 15px;
padding-right: 15px;
padding-top: 1px;
padding-bottom: 1px;
}
ins {color:#00A000}
del {color:#A00000}
code {white-space:pre;}
</style>
</head>
<body>
<center>
The contents you are looking for have moved. You will be redirected to the new
location automatically in 5 seconds. Please bookmark the correct page at
<a href="http://howardhinnant.github.io/date/date.html">http://howardhinnant.github.io/date/date.html</a>
</center>
<!--
<address align=right>
<br/>
<br/>
<a href="mailto:howard.hinnant@gmail.com">Howard E. Hinnant</a><br/>
2015-09-19<br/>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"> <img alt="Creative
Commons License" style="border-width:0"
src="http://i.creativecommons.org/l/by/4.0/80x15.png" /></a><br /> This work is licensed
under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative
Commons Attribution 4.0 International License</a>.
</address>
<hr/>
<h1 align=center><code>date</code></h1>
<h2>Contents</h2>
<ul>
<li><a href="#Introduction">Introduction</a></li>
<li><a href="#Implementation">Implementation</a></li>
<li><a href="#Overview">Overview</a></li>
<li><a href="#Reference">Reference</a></li>
</ul>
<a name="Introduction"></a><h2>Introduction</h2>
<p>
This paper fully documents a date and time library for use with C++11 and C++14.
</p>
<a name="Implementation"></a><h2>Implementation</h2>
<p>
This entire library is implemented in a single header:
<a href="https://github.com/HowardHinnant/date/blob/master/date.h">date.h</a> and is
open source (with generous open source terms — not generous enough? Contact me, I'm
flexible).
</p>
<p>
It uses the algorithms from
<a href="http://howardhinnant.github.io/date_algorithms.html"><code>chrono</code>-Compatible Low-Level Date Algorithms</a>.
If you want detailed explanations of the algorithms, go there.
</p>
<p>
It performs best with C++14, which has vastly improved <code>constexpr</code> rules.
However, the library will auto-adopt to C++11, sacrificing several <code>constexpr</code>
declarations. In C++11, this will effectively transfer some computations that should be
done at compile-time to run-time. Porting to C++98/03 has not been attempted.
</p>
<a name="Overview"></a><h2>Overview</h2>
<p>
This library builds date and date/time support on top of the <code><chrono></code>
library. However it does not support timezones nor leap seconds. A
<a href="tz.html">separate library is provided</a>, built on top of this one, for timezone
and leap second support. Thus you only pay for such support if you need it.
</p>
<h3>Major Concepts</h3>
<p>
A date on a calendar is a time point with a resolution of one day. This is not
conceptually different from <code>std::chrono::system_clock::time_point</code> which is a
time point with a resolution of <code>std::chrono::system_clock::period</code> (typically
on the order of a microsecond or nanosecond). Time points are divided into two basic
types:
</p>
<ol>
<li>serial-based</li>
<li>field-based</li>
</ol>
<p>
This terminology is gratefully borrowed from
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf">N3344</a>. In
short, a <i>serial-based</i> time point stores a single count of time durations from some epoch.
<code>std::chrono::system_clock::time_point</code> is an example of a <i>serial-based</i>
time point. A count of days from some epoch is also a <i>serial-based</i> time point.
A <i>field-based</i> time point represents the same concept, but with several fields that
are typically used for human consumption. For example one might represent the time of day
with the number of seconds since midnight (<i>serial-based</i>), or with a structure such
as <code>{hours, minutes, seconds}</code> since midnight (<i>field-based</i>). Similarly
one can represent a date with a count of days, or with a <code>{year, month, day}</code>
structure. Both representations are useful, and each has its strengths and weaknesses.
</p>
<h3>Major Types</h3>
<p>
This library is composed of many types. But here are the most important ones:
</p>
<ol>
<li><code>day_point</code>: A count of days since <code>system_clock</code>'s epoch. This
is a serial-based time point with a resolution of one day.</li>
<li><code>year_month_day</code>: A type that holds a year (e.g. 2015), a month
(encoded as 1 thru 12), and a day (encoded as 1 thru 31). This is a field-based time
point with a resolution of one day.</li>
<li><code>year_month_weekday</code>: A type that holds a year (e.g. 2015), a month
(encoded as 1 thru 12), a day of the week (encoded as 0 thru 6), and an index in the range
[1, 5] indicating if this is the first, second, etc. weekday of the indicated month. This
is a field-based time point with a resolution of one day.</li>
<li>
<code>year_month</code>: A type that holds a year and a month. This is a field-based
time point with a resolution of one month. This time point implements month-based
arithmetic, which other field-based time points can reuse.
</li>
</ol>
<h3>Examples</h3>
<p>
The entire library is in namespace <code>date</code>. The examples in this
overview assume:
</p>
<blockquote><pre>
using namespace date;
using namespace std::chrono;
</pre></blockquote>
<p>
in order to cut down on the verbosity.
</p>
<h3>Example: Constructing dates</h3>
<b><code>year_month_day</code></b>
<p>
<code>constexpr</code> dates can be constructed from literals in any one of 3 orders:
</p>
<blockquote><pre>
constexpr auto x1 = 2015_y/mar/22;
constexpr auto x2 = mar/22/2015;
constexpr auto x3 = 22_d/mar/2015;
</pre></blockquote>
<p>
<code>x1</code>, <code>x2</code> and <code>x3</code> all have the type:
<code>year_month_day</code>, and are all equal to one another. Any other order,
or any ambiguity is caught at compile time. These three orders were chosen
because these are the
<a href="http://en.wikipedia.org/wiki/Date_format_by_country">three orders that people actually use</a>.
</p>
<p>
Integral types can be converted to <code>year</code>, <code>month</code>, or
<code>day</code> to create run time values:
</p>
<blockquote><pre>
int y = 2015;
int m = 3;
int d = 22;
auto x1 = year(y)/m/d;
auto x2 = month(m)/d/y;
auto x3 = day(d)/m/y;
</pre></blockquote>
<p>
As long as the type of the first date component is known, the following components become
unambiguous and can be formed either with the proper type, or with an <code>int</code>
expression. And since there is only one order with <code>day</code> in the middle, that
order need only properly type the <code>day</code> to remain unambiguous:
</p>
<blockquote><pre>
auto x = m/day(d)/y;
</pre></blockquote>
<p>
No matter the order of the <code>year</code>, <code>month</code> and
<code>day</code> specifiers, and no matter whether some of the fields implicitly
convert from <code>int</code>, the type of these expressions is
<code>year_month_day</code>. However because of <code>auto</code>, it is very
often unimportant how to spell the somewhat verbose type name
<code>year_month_day</code>. The compiler knows how to spell the type, and the
meaning is clear to the human reader without an explicit type.
</p>
<p>
If there is <i>any</i> ambiguity, the code <b>will not compile</b>. If the code
does compile, it will be unambiguous and quite readable.
</p>
<b><code>year_month_day_last</code></b>
<p>
Anywhere you can specify a <code>day</code> you can instead specify <code>last</code>
to indicate the last day of the month for that year:
</p>
<blockquote><pre>
constexpr auto x1 = 2015_y/feb/last;
constexpr auto x2 = feb/last/2015;
constexpr auto x3 = last/feb/2015;
</pre></blockquote>
<p>
Instead of constructing a <code>year_month_day</code>, these expressions construct a
<code>year_month_day_last</code>. This type always represents the last day of a
<code>year</code> and <code>month</code>. <code>year_month_day_last</code> will
implicitly convert to <code>year_month_day</code>. Note though that because of
<code>auto</code> both the reader and the writer of the code can very often remain
blissfully ignorant of the spelling of <code>year_month_day_last</code>. The API of
<code>year_month_day</code> and <code>year_month_day_last</code> are virtually identical
so that the learning curve is shallow, and generic code usually does not need to know
which type it is operating on.
</p>
<b><code>year_month_weekday</code></b>
<p>
Anywhere you can specify a <code>day</code> you can instead specify an <i>indexed</i>
<code>weekday</code> to indicate the nth weekday of the month for that year:
</p>
<blockquote><pre>
constexpr auto x1 = 2015_y/mar/sun[4];
constexpr auto x2 = mar/sun[4]/2015;
constexpr auto x3 = sun[4]/mar/2015;
</pre></blockquote>
<p>
The type constructed is <code>year_month_weekday</code> which will implicitly convert to
and from a <code>day_point</code>. If you want to convert to a
<code>year_month_day</code> you can do so explicitly, which will implicitly convert to
<code>day_point</code> and back:
</p>
<blockquote><pre>
constexpr auto x4 = year_month_day(x3);
</pre></blockquote>
<b><code>year_month_weekday_last</code></b>
<p>
<code>weekday</code>'s can be indexed with <code>last</code> and used as above:
</p>
<blockquote><pre>
constexpr auto x1 = 2015_y/mar/sun[last];
constexpr auto x2 = mar/sun[last]/2015;
constexpr auto x3 = sun[last]/mar/2015;
constexpr auto x4 = year_month_day(x3);
cout << x3 << '\n';
cout << x4 << '\n';
</pre></blockquote>
<p>
This creates an object of type <code>year_month_weekday_last</code>. The above code
outputs:
</p>
<blockquote><pre>
2015/Mar/Sun[last]
2015-03-29
</pre></blockquote>
<b>Escape hatch from the cute syntax</b>
<p>
If you hate the cute syntax, don't use it. Every type has a descriptive name,
and public type-safe constructors to do the same job. The "cute syntax" is a
non-friended and <i>zero-abstraction-penalty</i> layer on top of a complete lower-level
API.
</p>
<blockquote><pre>
constexpr auto x1 = 2015_y/mar/sun[last];
constexpr auto x2 = year_month_weekday_last(year(2015), month(3), weekday_last(weekday(0)));
static_assert(x1 == x2, "No matter the API, x1 and x2 have the same value ...");
static_assert(is_same<decltype(x1), decltype(x2)>::value, "... and are the same type");
cout << x1 << '\n';
cout << x2 << '\n';
2015/Mar/Sun[last]
2015/Mar/Sun[last]
</pre></blockquote>
<h3>Example: Today</h3>
<p>
To get today as a <code>day_point</code>, use <code>system_clock::now()</code> and
<code>floor</code> to convert the <code>time_point</code> to a
<code>day_point</code>:
</p>
<blockquote><pre>
auto today = floor<days>(system_clock::now());
cout << today << '\n';
</pre></blockquote>
<p>
Currently this outputs for me:
</p>
<blockquote><pre>
2015-03-22
</pre></blockquote>
<p>
To get today as a <code>year_month_day</code>, get a <code>day_point</code> as above and
convert it to a <code>year_month_day</code>:
</p>
<blockquote><pre>
auto today = year_month_day{floor<days>(system_clock::now())};
cout << today << '\n';
</pre></blockquote>
<p>
Which again currently outputs for me:
</p>
<blockquote><pre>
2015-03-22
</pre></blockquote>
<p>
To get today as a <code>year_month_weekday</code>, get a <code>day_point</code> as above and
convert it to a <code>year_month_weekday</code>:
</p>
<blockquote><pre>
auto today = year_month_weekday{floor<days>(system_clock::now())};
cout << today << '\n';
</pre></blockquote>
<p>
Currently this outputs for me:
</p>
<blockquote><pre>
2015/Mar/Sun[4]
</pre></blockquote>
<p>
This indicates that today (2015-03-22) is the fourth Sunday of Mar., 2015.
</p>
<h3>Example: Contrast with C</h3>
<p>
Just about everything C++ has for date handling, it inherits from C. I thought it
would be fun to contrast an example that comes from the C standard with this library.
</p>
<p>
From the C standard: 7.27.2.3 The <code>mktime</code> function, paragraph 4:
</p>
<blockquote>
<p>
EXAMPLE What day of the week is July 4, 2001?
</p>
<blockquote><pre>
#include <stdio.h>
#include <time.h>
static const char *const wday[] =
{
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", "-unknown-"
};
int
main()
{
struct tm time_str;
time_str.tm_year = 2001 - 1900;
time_str.tm_mon = 7 - 1;
time_str.tm_mday = 4;
time_str.tm_hour = 0;
time_str.tm_min = 0;
time_str.tm_sec = 0;
time_str.tm_isdst = -1;
if (mktime(&time_str) == (time_t)(-1))
time_str.tm_wday = 7;
printf("%s\n", wday[time_str.tm_wday]);
}
</pre></blockquote>
</blockquote>
<p>
This program outputs:
</p>
<blockquote><pre>
Wednesday
</pre></blockquote>
<p>
Coding the same problem up in this library looks like:
</p>
<blockquote><pre>
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
std::cout << weekday(jul/4/2001) << '\n';
}
</pre></blockquote>
<p>
which outputs:
</p>
<blockquote><pre>
Wed
</pre></blockquote>
<p>
And if we really want to show off, this can all be done at compile time:
</p>
<blockquote><pre>
#include "date.h"
int
main()
{
using namespace date;
static_assert(weekday(2001_y/jul/4) == wed, "");
}
</pre></blockquote>
<p>
(Date ordering was switched simply to assure the gentle reader that we're not hung up on
m/d/y ordering.)
</p>
<h3>Errors</h3>
<p>
No exceptions are thrown in the entire library, except those that might be thrown from
<code>std::ostream</code> when streaming values to a <code>std::ostream</code>. Most of
the types have a <code>constexpr const</code> member function named <code>ok()</code>
which returns <code>true</code> if the object represents a valid date, or date component,
and otherwise returns <code>false</code>. However it is perfectly fine (and sometimes
actually useful) for these objects to contain invalid dates or date components. For
example, here is a very simple and remarkably efficient program to output the odd Fridays
of every month in 2015:
</p>
<blockquote><pre>
int
main()
{
using namespace std;
using namespace date;
for (auto m = 1; m <= 12; ++m)
{
auto meet = year_month_day(m/fri[1]/2015);
cout << meet << '\n';
meet = meet.year()/meet.month()/(meet.day()+weeks(2));
cout << meet << '\n';
meet = meet.year()/meet.month()/(meet.day()+weeks(2));
if (meet.ok())
cout << meet << '\n';
}
}
</pre></blockquote>
<p>
There is a relatively expensive (expense is relative here — maybe as much as 100ns)
conversion from <code>year_month_weekday</code> to <code>year_month_day</code> at the top
of the loop to find the first Friday of the month. This computation can never fail. And
after that it is dirt cheap to find the 3rd Friday — you just have to add 2 weeks to
the day field. This computation also can never fail. And it is similarly cheap to find
the 5th Friday of each month. However, not every month has a fifth Friday. But
nevertheless it is ok to form such a <code>year_month_day</code>. The computation can
never fail, though it may render an invalid date. Afterwards one can simply ask: Did I
create a valid date? If so, print it out, otherwise just continue on.
</p>
<p>
This program is easy to read, easy to write, will fail to compile if any careless errors
are made, and extremely high performance. The date computations are dwarfed by the run
time costs of the I/O.
</p>
<p>
Because practically nothing throws exceptions, this entire library is liberally sprinkled
with <code>noexcept</code>.
</p>
<p>
A few of the operations have a precondition that <code>ok() == true</code>. These are
generally conversions to <code>day_point</code>, and month-oriented and weekday-oriented
arithmetic. Anywhere there is a precondition, and those places are few, the precondition
is checkable with <code>ok()</code>.
</p>
<p>
This library catches many errors (especially ambiguity errors) at compile time. What's
left over is left up to <code>ok()</code>. Sometimes <code>!ok()</code> will represent an
error, and other times it will simply represent something innocuous that can be ignored
(such as in the example above). If <code>!ok()</code> actually represents an error that
must be dealt with, the choice of whether to assert or throw is made by the client of
this library.
</p>
<h3>Efficiency</h3>
<p>
In <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf">N3344</a>
Pacifico, Meredith and Lakos present a thorough survey of date types and their performance.
This library has been strongly influenced by this excellent paper.
<code>year_month_day</code> is equivalent to what <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf">N3344</a> terms <code>YMD_4</code>. And
<code>day_point</code> is equivalent to what <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf">N3344</a> terms <code>HH_SERIAL_RAW_4</code>.
</p>
<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3344.pdf">N3344</a>
aptly demonstrates that field-based date structures are good at some operations and poor
at others. And serial-based implementations are generally good at what the field-based
data structures are poor at, and poor at what the field-based data structures are good at.
Indeed, this is the genesis of the design of this library: Provide both data structures
and let the conversions among the data structures be provided by algorithms as shown in
<a href="http://howardhinnant.github.io/date_algorithms.html"><code>chrono</code>-Compatible Low-Level Date Algorithms</a>.
And additionally, just provide the API for each data structure that it can do efficiently.
</p>
<ul>
<li><p>
Field types are good at returning the values of the fields. Serial types aren't (except
for weekdays). So <code>year_month_day</code> has accessors for <code>year</code>,
<code>month</code> and <code>day</code>. And <code>day_point</code> does not.
</p></li>
<li><p>
Field types are good at month and year-oriented arithmetic. Serial types aren't.
So <code>year_month_day</code> has month and year-oriented arithmetic. And
<code>day_point</code> does not.
</p></li>
<li><p>
Serial types are good at day-oriented arithmetic. Field types aren't.
So <code>day_point</code> has day-oriented arithmetic. And <code>year_month_day</code>
does not. Though one can perform day-oriented arithmetic on the day field of a
<code>year_month_day</code>, with no impact on the other fields.
</p></li>
<li><p>
To efficiently compute a day of the week, one first needs to compute a serial date. So
<code>weekday</code> is constructible from <code>day_point</code>.
</p></li>
</ul>
<p>
To demonstrate the efficiency of constructing a <code>year_month_day</code>, a hypothetical
factory function has been created in the table below. And this is compared with a
simplistic <code>struct YMD_4</code> and an obvious factory function for that. Each is
compiled using clang at an optimization of -O2 or higher.
</p>
<blockquote>
<table border="1" cellpadding="10">
<caption><code>year_month_day</code> constructor assembly</caption>
<tr>
<td>
<pre>
date::year_month_day
make_year_month_day(int y, int m, int d)
{
using namespace date;
return year(y)/m/d;
}
</pre>
</td>
<td>
<pre>
struct YMD_4
{
std::int16_t year;
std::uint8_t month;
std::uint8_t day;
};
YMD_4
make_YMD_4(int y, int m, int d)
{
return {static_cast<std::int16_t>(y),
static_cast<std::uint8_t>(m),
static_cast<std::uint8_t>(d)};
}
</pre>
</td>
</tr>
<tr>
<td>
<pre>
.globl __Z19make_year_month_dayiii
.align 4, 0x90
__Z19make_year_month_dayiii:
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
shll $24, %edx
shll $16, %esi
andl $16711680, %esi
movzwl %di, %eax
orl %edx, %eax
orl %esi, %eax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
<td>
<pre>
.globl __Z10make_YMD_4iii
.align 4, 0x90
__Z10make_YMD_4iii:
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
shll $24, %edx
shll $16, %esi
andl $16711680, %esi
movzwl %di, %eax
orl %esi, %eax
orl %edx, %eax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
</tr>
</table>
</blockquote>
<p>
One can see that the generated assembler is virtually identical for these two factory
functions. I.e. the code size and run time overhead of the "cute syntax" for constructing
a <code>year_month_day</code> is zero, at least in optimized builds.
</p>
<p>
A similar experiment is made for constructing a <code>day_point</code> from a count of
days held in an <code>int</code>. To do this one must first create a <code>days</code>
duration, and then construct the <code>day_point</code> from the <code>days</code>
duration. This is contrasted with the very simplistic <code>struct SERIAL_4</code>.
</p>
<blockquote>
<table border="1" cellpadding="10">
<caption><code>day_point</code> constructor assembly</caption>
<tr>
<td>
<pre>
date::day_point
make_day_point(int z)
{
using namespace date;
return day_point{days{z}};
}
</pre>
</td>
<td>
<pre>
struct SERIAL_4
{
std::int32_t count;
};
SERIAL_4
make_SERIAL_4(int z)
{
return {z};
}
</pre>
</td>
</tr>
<tr>
<td>
<pre>
.globl __Z14make_day_pointi
.align 4, 0x90
__Z14make_day_pointi:
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl %edi, %eax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
<td>
<pre>
.globl __Z13make_SERIAL_4i
.align 4, 0x90
__Z13make_SERIAL_4i:
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl %edi, %eax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
</tr>
</table>
</blockquote>
<p>
It is easy to see that the generated code is identical, and thus there is no overhead
associated with the <code>day_point</code> type. It is also noteworthy that the code for
this construction does not actually come from this <code>date</code> library, but instead
comes from your std::lib header <code><chrono></code>. <code>days</code> is nothing
but a <i>type-alias</i> for a <code>std::chrono::duration</code>, and
<code>day_point</code> is nothing but a <i>type-alias</i> for a
<code>std::chrono::time_point</code> (thus the inspiration for the name
<code>day_point</code>). So this is also evidence that there is zero overhead for the
type-safe system of the <code><chrono></code> library.
</p>
<a name="shift_epoch"></a>
<p>
One final example taken from real-world code. Below are two ways of implementing a system
which counts seconds since Jan. 1, 2000: One that uses this library and another that
simply stores the count of seconds in a <code>long</code>. A utility is needed to convert
that count to <a href="http://en.wikipedia.org/wiki/Unix_time">Unix Time</a>, which simply
involves shifting the epoch to Jan. 1, 1970.
</p>
<blockquote>
<table border="1" cellpadding="10">
<caption>Shift epoch from <code>jan/1/2000</code> to <code>jan/1/1970</code></caption>
<tr>
<td>
<pre>
using time_point = std::chrono::time_point<std::chrono::system_clock,
std::chrono::seconds>;
time_point
shift_epoch(time_point t)
{
using namespace date;
return t + (day_point(jan/1/2000) - day_point(jan/1/1970));
}
</pre>
</td>
<td>
<pre>
long
shift_epoch(long t)
{
return t + 946684800;
}
</pre>
</td>
</tr>
<tr>
<td>
<pre>
.globl __Z11shift_epochNSt3__16chrono10time_pointINS0...
.align 4, 0x90
__Z11shift_epochNSt3__16chrono10time_pointINS0...
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
leaq 946684800(%rdi), %rax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
<td>
<pre>
.globl __Z11shift_epochl
.align 4, 0x90
__Z11shift_epochl:
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
leaq 946684800(%rdi), %rax
popq %rbp
retq
.cfi_endproc
</pre>
</td>
</tr>
</table>
</blockquote>
<p>
On the left we have a strongly typed solution which makes it explicit that the code is
adding a time duration equal to the difference between the two epochs. Though verbose,
the code is easy to read. On the right we have the maximally efficient, and yet relatively
cryptic implementation with <code>long</code>. As it turns out, there are 946,684,800
seconds between these two epochs ... who knew?
</p>
<p>
clang generates <i>identical</i> assembly for these two functions at -O2 and higher. That
is, the sub-expression <code>(day_point(jan/1/2000) - day_point(jan/1/1970))</code> is
reduced down to a number of days (10,957) <i>at compile time</i>, and then this
sub-expression, which has type <code>days</code> is added to a <code>time_point</code>
with a resolution of <code>seconds</code>, which causes the compiler to convert
<code>days{10957}</code> to <code>seconds{946684800}</code>, again <i>at compile time</i>.
</p>
<p>
And in the strongly typed case, if in the future one decides that one wants to count
milliseconds instead of seconds, that can be changed in <b>one</b> place:
</p>
<blockquote>
<pre>
using time_point = std::chrono::time_point<std::chrono::system_clock,
std::chrono::<ins>milli</ins>seconds>;
</pre>
</blockquote>
<p>
Upon recompile the compiler automatically updates the compile-time constant in
<code>shift_epoch</code> from 946684800 to 946684800000 (and everywhere else such as
where you perform the epoch shift in the reverse direction).
</p>
<h3>What about a date-time type?</h3>
<p>
You already have a good one. It is called
<code>std::chrono::system_clock::time_point</code>. And it is completely interoperable
with this library. <code>std::chrono::system_clock::time_point</code> is a pointer to
a particular instant of time, with high precision (that precision is specified differently
on each platform). As we saw earlier, one can get a high-precision <code>time_point</code>
representing <i>now</i> with:
</p>
<blockquote><pre>
auto tp = system_clock::now();
</pre></blockquote>
<p>
This library provides a stream insertion operator for
<code>system_clock::time_point</code> (in <code>namespace date</code>).
</p>
<blockquote><pre>
std::cout << tp << '\n';
</pre></blockquote>
<p>
This currently outputs for me:
</p>
<blockquote><pre>
2015-04-19 18:24:42.770911
</pre></blockquote>
<p>
One can turn that into a <code>time_point</code> with the precision of a day (which
has a type alias called <code>day_point</code>) with:
</p>
<blockquote><pre>
auto dp = floor<days>(tp);
</pre></blockquote>
<p>
And one can convert that day-oriented <code>time_point</code> into a
<code>{year, month, day}</code> field type with:
</p>
<blockquote><pre>
auto ymd = year_month_day(dp);
</pre></blockquote>
<p>
This section explains how to extract the <i>time of day</i> from the above information.
<code>dp</code> can also be though of as a <code>time_point</code> to the beginning of the
current day (in the UTC timezone). And so one can get the time <code>duration</code>
since midnight by subtracting the day-precision <code>time_point</code> from the high
precision <code>time_point</code>: <code>tp-dp</code>. This results in a high precision
<code>std::chrono::duration</code> representing the time since midnight.
</p>
<p>
This high precision <code>duration</code> can be broken down into hours, minutes, seconds,
and fractions of a second with a <code>time_of_day</code> object, which is most easily
created by using the <code>make_time</code> factory function:
</p>
<blockquote><pre>
auto time = make_time(tp-dp);
</pre></blockquote>
<p>
Now both <code>ymd</code> and <code>time</code> can simply be printed out:
</p>