Xclox
C++11 header-only cross-platform date and time library with an asynchronous NTP client
date.h
1 /*
2  * Copyright (c) 2024 Abdullatif Kalla.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE.txt file in the root directory of this source tree.
6  */
7 
8 #include "xclox/date.hpp"
9 
10 using namespace xclox;
11 using namespace std::chrono;
12 
13 TEST_SUITE("Date")
14 {
15  constexpr seconds NtpDeltaSeconds { 2208988800 };
16  constexpr seconds UnixRolloverSeconds { 2147483647 };
17 
18  TEST_CASE("constructible")
19  {
20  SUBCASE("default")
21  {
22  Date d;
23 
24  CHECK(d.year() == 0);
25  CHECK(d.month() == 0);
26  CHECK(d.day() == 0);
27  }
28  SUBCASE("year, month, day")
29  {
30  Date d1(2012, 3, 27);
31  CHECK(d1.year() == 2012);
32  CHECK(d1.month() == 3);
33  CHECK(d1.day() == 27);
34 
35  Date d2(-4714, 11, 24);
36  CHECK(d2.year() == -4714);
37  CHECK(d2.month() == 11);
38  CHECK(d2.day() == 24);
39  }
40  SUBCASE("number of days since epoch")
41  {
42  Date d1(-duration_cast<Date::Days>(NtpDeltaSeconds));
43  CHECK(d1.year() == 1900);
44  CHECK(d1.month() == 1);
45  CHECK(d1.day() == 1);
46 
47  Date d2(Date::Days(0));
48  CHECK(d2.year() == 1970);
49  CHECK(d2.month() == 1);
50  CHECK(d2.day() == 1);
51 
52  Date d3(duration_cast<Date::Days>(UnixRolloverSeconds));
53  CHECK(d3.year() == 2038);
54  CHECK(d3.month() == 1);
55  CHECK(d3.day() == 19);
56  }
57  }
58 
59  TEST_CASE("validatable")
60  {
61  CHECK(Date().isValid() == false);
62  CHECK(Date(0, 0, 0).isValid() == false);
63  CHECK(Date(0, 1, 1).isValid() == false);
64  CHECK(Date(2017, -1, 1).isValid() == false);
65  CHECK(Date(2018, 1, -1).isValid() == false);
66  CHECK(Date(2018, -1, -1).isValid() == false);
67  CHECK(Date(1, 1, 1).isValid() == true);
68  //
69  // additional tests.
70  //
71  // for (long jd = 0; jd <= 9999999; ++jd) {
72  // Date d = Date::fromJulianDay(jd);
73  // CHECK(d == Date(-4714, 11, 24).addDays(jd));
74  // CHECK(d.isValid());
75  // }
76  // for (int y = -9999; y <= 9999; ++y) {
77  // for (char m = 0; m <= 13; ++m)
78  // for (char d = 0; d <= 32; ++d) {
79  // if (y != 0 && m >= 1 && m <= 12 && d >= 1 && d <= Date::daysInMonthOfYear(y, m))
80  // CHECK(Date(y, m, d).isValid());
81  // else
82  // CHECK_FALSE(Date(y, m, d).isValid());
83  // }
84  // }
85  }
86 
87  TEST_CASE("comparable")
88  {
89  CHECK(Date(2012, 3, 27) == Date(2012, 3, 27));
90  CHECK(Date(2012, 3, 1) != Date(2012, 3, 2));
91  CHECK(Date(2012, 3, 1) < Date(2012, 3, 2));
92  CHECK(Date(2012, 3, 2) <= Date(2012, 3, 2));
93  CHECK(Date(2012, 3, 2) <= Date(2012, 3, 3));
94  CHECK(Date(2012, 3, 3) > Date(2012, 3, 2));
95  CHECK(Date(2012, 3, 3) >= Date(2012, 3, 3));
96  CHECK(Date(2012, 3, 4) >= Date(2012, 3, 3));
97  }
98 
99  TEST_CASE("copyable")
100  {
101  Date d1;
102  Date d2(2001, 2, 3);
103  Date d3(2003, 2, 1);
104 
105  SUBCASE("construction")
106  {
107  Date d4(d1);
108  Date d5(d2);
109  Date d6(std::move(d3));
110 
111  CHECK(d1 == d4);
112  CHECK(d2 == d5);
113  CHECK(d3 == d6);
114  }
115  SUBCASE("assignment")
116  {
117  Date d4 = d1;
118  Date d5 = d2;
119  Date d6 = std::move(d3);
120 
121  CHECK(d1 == d4);
122  CHECK(d2 == d5);
123  CHECK(d3 == d6);
124  }
125  }
126 
127  TEST_CASE("current date")
128  {
129  CHECK(Date::current() == Date(duration_cast<Date::Days>(system_clock::now().time_since_epoch())));
130  }
131 
132  TEST_CASE("epoch")
133  {
134  CHECK(Date::epoch() == Date(1970, 1, 1));
135  }
136 
137  TEST_CASE("addition & subtraction")
138  {
139  SUBCASE("day")
140  {
141  CHECK(Date(2045, 3, 27).addDays(5) == Date(2045, 4, 1));
142  CHECK(Date(2045, 4, 1).subtractDays(5) == Date(2045, 3, 27));
143  //
144  // additional tests.
145  //
146  CHECK(Date(2018, 1, 1).addDays(0) == Date(2018, 1, 1));
147  CHECK(Date(2018, 1, 1).subtractDays(0) == Date(2018, 1, 1));
148  CHECK(Date(2018, 1, 2).addDays(-1) == Date(2018, 1, 1));
149  CHECK(Date(2018, 1, 1).subtractDays(-1) == Date(2018, 1, 2));
150  // long dys = 0;
151  // for (int y = 1970; y <= 9999; ++y) {
152  // for (char m = 1; m <= 12; ++m)
153  // for (char d = 1; d <= Date::daysInMonthOfYear(y, m); ++d) {
154  // CHECK(Date(y, m, d) == Date(1970, 1, 1).addDays(dys++));
155  // }
156  // }
157  // dys = 1;
158  // for (int y = 1969; y >= -9999; --y) {
159  // if (y == 0) {
160  // continue;
161  // }
162  // for (char m = 12; m >= 1; --m)
163  // for (char d = Date::daysInMonthOfYear(y, m); d >= 1; --d)
164  // CHECK(Date(y, m, d) == Date(1970, 1, 1).subtractDays(dys++));
165  // }
166  }
167  SUBCASE("month")
168  {
169  // when the sum of augend and addend is smaller than 12.
170  CHECK(Date(2012, 3, 27).addMonths(5) == Date(2012, 8, 27));
171  // when the sum of augend and addend is bigger than 12.
172  CHECK(Date(2012, 8, 27).addMonths(10) == Date(2013, 6, 27));
173  // when the result of addition is 12. due to the representation of month is 1...12 rather than 0...11.
174  CHECK(Date(2012, 8, 27).addMonths(4) == Date(2012, 12, 27));
175  // when the addend is negative.
176  CHECK(Date(2012, 3, 27).addMonths(-5) == Date(2011, 10, 27));
177  // when the minuend is bigger than the subtrahend.
178  CHECK(Date(2013, 6, 27).subtractMonths(5) == Date(2013, 1, 27));
179  // when the minuend is smaller than the subtrahend.
180  CHECK(Date(2013, 1, 27).subtractMonths(10) == Date(2012, 3, 27));
181  // when the result of subtraction is 12. due to the representation of month is 1...12 rather than 0...11.
182  CHECK(Date(2013, 1, 27).subtractMonths(1) == Date(2012, 12, 27));
183  // when the subtrahend is negative.
184  CHECK(Date(2011, 10, 27).subtractMonths(-5) == Date(2012, 3, 27));
185  // when the ending day/month combination does not exist in the resulting month/year, returns the latest valid date.
186  CHECK(Date(2013, 1, 31).addMonths(1) == Date(2013, 2, 28));
187  CHECK(Date(2013, 2, 28).addMonths(1) == Date(2013, 3, 28));
188  CHECK(Date(2012, 3, 31).subtractMonths(1) == Date(2012, 2, 29));
189  //
190  // additional tests.
191  //
192  CHECK(Date(2018, 1, 1).addMonths(0) == Date(2018, 1, 1));
193  CHECK(Date(2018, 1, 1).subtractMonths(0) == Date(2018, 1, 1));
194  }
195  SUBCASE("year")
196  {
197  CHECK(Date(1966, 11, 2).addYears(40) == Date(2006, 11, 2));
198  CHECK(Date(2006, 11, 2).subtractYears(40) == Date(1966, 11, 2));
199  //
200  // additional tests.
201  //
202  CHECK(Date(2018, 1, 1).addYears(0) == Date(2018, 1, 1));
203  CHECK(Date(2018, 1, 1).subtractYears(0) == Date(2018, 1, 1));
204  CHECK(Date(2018, 1, 1).addYears(-1) == Date(2017, 1, 1));
205  CHECK(Date(2018, 1, 1).subtractYears(-1) == Date(2019, 1, 1));
206  }
207  }
208 
209  TEST_CASE("leap year")
210  {
211  CHECK(Date(2012, 1, 1).isLeapYear());
212  CHECK_FALSE(Date::isLeapYear(2011));
213  CHECK_FALSE(Date::isLeapYear(100));
214  CHECK(Date::isLeapYear(2800));
215  CHECK(Date::isLeapYear(-1));
216  CHECK_FALSE(Date::isLeapYear(0)); // no year 0, should return false.
217  //
218  // additional tests.
219  //
220  CHECK(Date::isLeapYear(-4801));
221  CHECK_FALSE(Date::isLeapYear(-4800));
222  CHECK(Date::isLeapYear(-4445));
223  CHECK_FALSE(Date::isLeapYear(-4444));
224  CHECK_FALSE(Date::isLeapYear(-6));
225  CHECK(Date::isLeapYear(-5));
226  CHECK_FALSE(Date::isLeapYear(-4));
227  CHECK_FALSE(Date::isLeapYear(-3));
228  CHECK_FALSE(Date::isLeapYear(-2));
229  CHECK_FALSE(Date::isLeapYear(1));
230  CHECK_FALSE(Date::isLeapYear(2));
231  CHECK_FALSE(Date::isLeapYear(3));
232  CHECK(Date::isLeapYear(4));
233  CHECK_FALSE(Date::isLeapYear(7));
234  CHECK(Date::isLeapYear(8));
235  CHECK(Date::isLeapYear(400));
236  CHECK_FALSE(Date::isLeapYear(700));
237  CHECK_FALSE(Date::isLeapYear(1500));
238  CHECK(Date::isLeapYear(1600));
239  CHECK_FALSE(Date::isLeapYear(1700));
240  CHECK_FALSE(Date::isLeapYear(1800));
241  CHECK_FALSE(Date::isLeapYear(1900));
242  CHECK(Date::isLeapYear(2000));
243  CHECK_FALSE(Date::isLeapYear(2100));
244  CHECK_FALSE(Date::isLeapYear(2200));
245  CHECK_FALSE(Date::isLeapYear(2300));
246  CHECK(Date::isLeapYear(2400));
247  CHECK_FALSE(Date::isLeapYear(2500));
248  CHECK_FALSE(Date::isLeapYear(2600));
249  CHECK_FALSE(Date::isLeapYear(2700));
250  }
251 
252  TEST_CASE("extraction of individual components")
253  {
254  int year, month, day;
255 
256  Date(1989, 3, 12).getYearMonthDay(&year, &month, &day);
257  Date(1989, 3, 12).getYearMonthDay(&year, &month, nullptr);
258  Date(1989, 3, 12).getYearMonthDay(&year, nullptr, nullptr);
259  Date(1989, 3, 12).getYearMonthDay(nullptr, nullptr, nullptr);
260  Date(1989, 3, 12).getYearMonthDay(0, &month, &day);
261  Date(1989, 3, 12).getYearMonthDay(0, 0, &day);
262  Date(1989, 3, 12).getYearMonthDay(0, 0, 0);
263 
264  CHECK(year == 1989);
265  CHECK(month == 3);
266  CHECK(day == 12);
267  }
268 
269  TEST_CASE("calculation")
270  {
271  SUBCASE("day of week")
272  {
273  CHECK(Date(1970, 1, 1).dayOfWeek() == static_cast<int>(Date::Weekday::Thursday));
274  CHECK(Date(2001, 1, 1).dayOfWeek() == 1);
275  CHECK(Date(2002, 1, 1).dayOfWeek() == 2);
276  CHECK(Date(2003, 1, 1).dayOfWeek() == 3);
277  CHECK(Date(2004, 1, 1).dayOfWeek() == 4);
278  CHECK(Date(2010, 1, 1).dayOfWeek() == 5);
279  CHECK(Date(2005, 1, 1).dayOfWeek() == 6);
280  CHECK(Date(2006, 1, 1).dayOfWeek() == 7);
281  }
282  SUBCASE("day of year")
283  {
284  CHECK(Date(1970, 1, 1).dayOfYear() == 1);
285  CHECK(Date(2017, 12, 2).dayOfYear() == 336);
286  CHECK(Date(2064, 2, 29).dayOfYear() == 60);
287  }
288  SUBCASE("days in month")
289  {
290  CHECK(Date::daysInMonthOfYear(1, 0) == -1);
291  CHECK(Date::daysInMonthOfYear(1, 32) == -1);
292  CHECK(Date::daysInMonthOfYear(1970, 1) == 31);
293  CHECK(Date(1970, 1, 1).daysInMonth() == 31);
294  CHECK(Date(1970, 2, 1).daysInMonth() == 28);
295  CHECK(Date(2012, 2, 1).daysInMonth() == 29);
296  CHECK(Date(2055, 3, 1).daysInMonth() == 31);
297  CHECK(Date(2013, 4, 1).daysInMonth() == 30);
298  CHECK(Date(2025, 5, 1).daysInMonth() == 31);
299  CHECK(Date(2036, 6, 1).daysInMonth() == 30);
300  CHECK(Date(2057, 7, 1).daysInMonth() == 31);
301  CHECK(Date(2088, 8, 1).daysInMonth() == 31);
302  CHECK(Date(2009, 9, 1).daysInMonth() == 30);
303  CHECK(Date(2001, 10, 1).daysInMonth() == 31);
304  CHECK(Date(2023, 11, 1).daysInMonth() == 30);
305  CHECK(Date(2023, 12, 1).daysInMonth() == 31);
306  }
307  SUBCASE("days in year")
308  {
309  CHECK(Date(1970, 1, 1).daysInYear() == 365);
310  CHECK(Date(2012, 2, 2).daysInYear() == 366);
311  }
312  SUBCASE("number of days between two dates")
313  {
314  CHECK(Date::daysBetween(Date(1970, 1, 1), Date(1971, 1, 1)) == 365);
315  CHECK(Date::daysBetween(Date(2012, 1, 1), Date(2016, 1, 1)) == 1461);
316  CHECK(Date::daysBetween(Date(-1, 1, 1), Date(1, 1, 1)) == 366); // year -1 is a leap year.
317  CHECK(Date::weeksBetween(Date(1970, 1, 8), Date(1970, 1, 1)) == -1);
318  CHECK(Date::weeksBetween(Date(1970, 1, 1), Date(1971, 1, 1)) == 52);
319  }
320  SUBCASE("week of year")
321  {
322  int weekYear;
323 
324  // when the week is in the middle of the year
325  CHECK(Date(2017, 12, 3).weekOfYear(&weekYear) == 48);
326  CHECK(weekYear == 2017);
327 
328  // when the week is at the start of year
329  CHECK(Date(2002, 12, 31).weekOfYear(&weekYear) == 1);
330  CHECK(weekYear == 2003);
331 
332  // when the week is at the end of year
333  CHECK(Date(2000, 1, 1).weekOfYear(&weekYear) == 52);
334  CHECK(weekYear == 1999);
335 
336  // when the week is at the end of 53-week-year
337  CHECK(Date(2010, 1, 1).weekOfYear(&weekYear) == 53);
338  CHECK(weekYear == 2009);
339  }
340  }
341 
342  TEST_CASE("conversion")
343  {
344  SUBCASE("to Julian day")
345  {
346  CHECK(Date(-4714, 11, 24).toJulianDay() == 0);
347  CHECK(Date(-4714, 11, 25).toJulianDay() == 1);
348  CHECK(Date(1970, 1, 1).toJulianDay() == 2440588);
349  CHECK(Date(2000, 1, 1).toJulianDay() == 2451545);
350  CHECK(Date(2017, 12, 4).toJulianDay() == 2458092);
351  //
352  // additional tests.
353  //
354  // long jd = 0;
355  // for (char d = 24; d <= Date::daysInMonthOfYear(-4714, 11); ++d)
356  // CHECK(Date(-4714, 11, d).toJulianDay() == jd++);
357  // for (char d = 1; d <= Date::daysInMonthOfYear(-4714, 12); ++d)
358  // CHECK(Date(-4714, 12, d).toJulianDay() == jd++);
359  // for (long y = -4713; y <= 9999; ++y) {
360  // if (y == 0) {
361  // continue;
362  // }
363  // for (char m = 1; m <= 12; ++m)
364  // for (char d = 1; d <= Date::daysInMonthOfYear(y, m); ++d)
365  // CHECK(Date(y, m, d).toJulianDay() == jd++);
366  // }
367  }
368  SUBCASE("from Julian day")
369  {
370  CHECK(Date::fromJulianDay(0) == Date(-4714, 11, 24));
371  CHECK(Date::fromJulianDay(1) == Date(-4714, 11, 25));
372  CHECK(Date::fromJulianDay(2440588) == Date(1970, 1, 1));
373  CHECK(Date::fromJulianDay(2451545) == Date(2000, 1, 1));
374  CHECK(Date::fromJulianDay(2458092) == Date(2017, 12, 4));
375  //
376  // additional tests.
377  //
378  // for (long jd = 0; jd <= 9999999; ++jd) {
379  // Date d = Date::fromJulianDay(jd);
380  // CHECK(d == Date(-4714, 11, 24).addDays(jd));
381  // CHECK(d.isValid());
382  // }
383  }
384  SUBCASE("to days since epoch")
385  {
386  CHECK(Date(1970, 1, 1).toDaysSinceEpoch() == 0);
387  CHECK(Date(1971, 1, 1).toDaysSinceEpoch() == 365);
388  }
389  }
390 
391  TEST_CASE("formatting")
392  {
393  SUBCASE("year")
394  {
395  CHECK(Date(572, 4, 22).toString("y") == "572");
396  CHECK(Date(1999, 4, 13).toString("yy") == "99");
397  CHECK(Date(1901, 6, 11).toString("yy") == "01");
398  CHECK(Date(1999, 7, 4).toString("yyyy") == "1999");
399  CHECK(Date(-795, 7, 23).toString("yyyy") == "0795");
400  CHECK(Date(-1795, 7, 23).toString("#yyyy") == "-1795");
401  CHECK(Date(1795, 7, 23).toString("#yyyy") == "+1795");
402  CHECK(Date(-1795, 7, 23).toString("yyyy E") == "1795 BCE");
403  CHECK(Date(1795, 7, 23).toString("yyyy E") == "1795 CE");
404  CHECK(Date(1795, 7, 23).toString("yy . yy") == "95 . 95");
405  }
406  SUBCASE("month")
407  {
408  CHECK(Date(572, 4, 22).toString("M") == "4");
409  CHECK(Date(1999, 5, 13).toString("MM") == "05");
410  CHECK(Date(1999, 11, 13).toString("MM") == "11");
411  CHECK(Date(1901, 6, 11).toString("MMM") == "Jun");
412  CHECK(Date(1999, 7, 30).toString("MMMM") == "July");
413  }
414  SUBCASE("day")
415  {
416  CHECK(Date(572, 4, 22).toString("d") == "22");
417  CHECK(Date(1999, 4, 3).toString("dd") == "03");
418  CHECK(Date(1901, 6, 11).toString("dd") == "11");
419  CHECK(Date(1999, 7, 4).toString("ddd") == "Sun");
420  CHECK(Date(2017, 12, 15).toString("dddd") == "Friday");
421  }
422  SUBCASE("date")
423  {
424  // unparsable expressions are reserved.
425  CHECK(Date(2017, 12, 19).toString("yyyyMMdd ieee") == "20171219 ieee");
426  // invalid dates return an empty string.
427  CHECK(Date().toString("yyyy-MM-dd E") == "");
428  //
429  // additional tests.
430  //
431  CHECK(Date(0, 0, 0).toString("") == "");
432  CHECK(Date(0, 0, 0).toString("yyyy-MM-dd E") == "");
433  CHECK(Date(0, -1, 1).toString("yyyy-MM-dd E") == "");
434  CHECK(Date(0, 1, -1).toString("yyyy-MM-dd E") == "");
435  CHECK(Date(0, -1, -1).toString("yyyy-MM-dd E") == "");
436  CHECK(Date(572, 4, 22).toString("y.M.d") == "572.4.22");
437  CHECK(Date(2017, 4, 3).toString("yy.MM.dd") == "17.04.03");
438  CHECK(Date(2007, 5, 11).toString("yy.MMM.dd") == "07.May.11");
439  CHECK(Date(2017, 12, 10).toString("ddd dd.MM.yyyy") == "Sun 10.12.2017");
440  CHECK(Date(2017, 12, 15).toString("dddd dd MMMM yyyy") == "Friday 15 December 2017");
441  CHECK(Date(2017, 12, 16).toString("yyyy-MM-dd E") == "2017-12-16 CE");
442  CHECK(Date(-2017, 12, 16).toString("#yyyy.MM.dd") == "-2017.12.16");
443  CHECK(Date(2017, 12, 19).toString("yyyyMMdd") == "20171219");
444  }
445  }
446 
447  TEST_CASE("parsing")
448  {
449  SUBCASE("year")
450  {
451  CHECK(Date::fromString("572", "y") == Date(572, 1, 1));
452  CHECK(Date::fromString("12", "yy") == Date(2012, 1, 1));
453  CHECK(Date::fromString("1999", "yyyy") == Date(1999, 1, 1));
454  CHECK(Date::fromString("-572", "#y") == Date(-572, 1, 1));
455  CHECK(Date::fromString("+572", "#y") == Date(572, 1, 1));
456  CHECK(Date::fromString("-1999", "#yyyy") == Date(-1999, 1, 1));
457  CHECK(Date::fromString("+1999", "#yyyy") == Date(1999, 1, 1));
458  CHECK(Date::fromString("572 CE", "y E") == Date(572, 1, 1));
459  CHECK(Date::fromString("572 BCE", "y E") == Date(-572, 1, 1));
460  CHECK(Date::fromString("1999 CE", "yyyy E") == Date(1999, 1, 1));
461  CHECK(Date::fromString("1999 BCE", "yyyy E") == Date(-1999, 1, 1));
462  }
463  SUBCASE("month")
464  {
465  CHECK(Date::fromString("1", "M") == Date(1, 1, 1));
466  CHECK(Date::fromString("02", "MM") == Date(1, 2, 1));
467  CHECK(Date::fromString("Aug", "MMM") == Date(1, 8, 1));
468  CHECK(Date::fromString("September", "MMMM") == Date(1, 9, 1));
469  CHECK(Date::fromString("January, 2009", "MMMM, yyyy") == Date(2009, 1, 1));
470  CHECK(Date::fromString("December, 2011", "MMMM, yyyy") == Date(2011, 12, 1));
471  }
472  SUBCASE("day")
473  {
474  CHECK(Date::fromString("1", "d") == Date(1, 1, 1));
475  CHECK(Date::fromString("02", "dd") == Date(1, 1, 2));
476  CHECK(Date::fromString("Thu, 22.05.17", "ddd, dd.MM.yy") == Date(2017, 5, 22));
477  CHECK(Date::fromString("Thursday, 01.12.1989", "dddd, dd.MM.yyyy") == Date(1989, 12, 1));
478  }
479  SUBCASE("date")
480  {
481  CHECK(Date::fromString("572.4.22", "y.M.d") == Date(572, 4, 22));
482  CHECK(Date::fromString("17.04.03", "yy.MM.dd") == Date(2017, 4, 3));
483  CHECK(Date::fromString("07.May.11", "yy.MMM.dd") == Date(2007, 5, 11));
484  CHECK(Date::fromString("Sun 10.12.2017", "ddd dd.MM.yyyy") == Date(2017, 12, 10));
485  CHECK(Date::fromString("Friday 15 December 2017", "dddd dd MMMM yyyy") == Date(2017, 12, 15));
486  CHECK(Date::fromString("2017-12-16 CE", "yyyy-MM-dd E") == Date(2017, 12, 16));
487  CHECK(Date::fromString("-2017.12.16", "#yyyy.MM.dd") == Date(-2017, 12, 16));
488  CHECK(Date::fromString("20171219", "yyyyMMdd") == Date(2017, 12, 19));
489  CHECK(Date::fromString("ieee 20171219", "ieee yyyyMMdd") == Date(2017, 12, 19));
490  }
491  }
492 
493  TEST_CASE("serialization & deserialization")
494  {
495  Date d;
496  std::stringstream ss;
497  ss << Date(2014, 11, 9);
498  ss >> d;
499  CHECK(d == Date(2014, 11, 9));
500  }
501 } // TEST_SUITE
Date is an immutable class representing a date without a time zone in the ISO-8601 calendar system,...
Definition: date.hpp:84
internal::Days Days
Day duration.
Definition: date.hpp:91
void getYearMonthDay(int *year, int *month, int *day) const
Set the year, month, and day of this date in the parameters year, month, and day, respectively.
Definition: date.hpp:254
int year() const
Returns the year of this date as a number.
Definition: date.hpp:280
static int daysInMonthOfYear(int year, int month)
Returns the number of days in month of year. It ranges between 28 and 31.
Definition: date.hpp:744
static Date fromJulianDay(long julianDay)
Returns a Date object corresponding to the Julian day julianDay.
Definition: date.hpp:688
static Date current()
Returns a Date object set to the current date obtained from the system clock.
Definition: date.hpp:597
int month() const
Returns the month of the year of this date as a number between 1 and 12, which corresponds to the enu...
Definition: date.hpp:271
static Date epoch()
Returns a Date object set to the epoch "1970-01-01".
Definition: date.hpp:603
int day() const
Returns the day of the month of this date as a number between 1 and 31.
Definition: date.hpp:265
static long weeksBetween(const Date &from, const Date &to)
Returns the number of weeks between from and to.
Definition: date.hpp:719
static long daysBetween(const Date &from, const Date &to)
Returns the number of days between from and to.
Definition: date.hpp:707
static Date fromString(const std::string &date, const std::string &format)
Returns a Date object from the date string date according to the format string format.
Definition: date.hpp:612
bool isLeapYear() const
Returns whether the year of this date is a leap year.
Definition: date.hpp:310