]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/src/std/datetime/date.d
Add D front-end, libphobos library, and D2 testsuite.
[thirdparty/gcc.git] / libphobos / src / std / datetime / date.d
1 // Written in the D programming language
2
3 /++
4 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5 Authors: Jonathan M Davis
6 Source: $(PHOBOSSRC std/datetime/_date.d)
7 +/
8 module std.datetime.date;
9
10 import core.time;
11 import std.traits : isSomeString, Unqual;
12 import std.typecons : Flag;
13
14 version (unittest) import std.exception : assertThrown;
15
16
17 @safe unittest
18 {
19 initializeTests();
20 }
21
22
23 /++
24 Exception type used by std.datetime. It's an alias to
25 $(REF TimeException,core,time). Either can be caught without concern about
26 which module it came from.
27 +/
28 alias DateTimeException = TimeException;
29
30
31 /++
32 Represents the 12 months of the Gregorian year (January is 1).
33 +/
34 enum Month : ubyte
35 {
36 jan = 1, ///
37 feb, ///
38 mar, ///
39 apr, ///
40 may, ///
41 jun, ///
42 jul, ///
43 aug, ///
44 sep, ///
45 oct, ///
46 nov, ///
47 dec ///
48 }
49
50
51 /++
52 Represents the 7 days of the Gregorian week (Sunday is 0).
53 +/
54 enum DayOfWeek : ubyte
55 {
56 sun = 0, ///
57 mon, ///
58 tue, ///
59 wed, ///
60 thu, ///
61 fri, ///
62 sat ///
63 }
64
65
66 /++
67 In some date calculations, adding months or years can cause the date to fall
68 on a day of the month which is not valid (e.g. February 29th 2001 or
69 June 31st 2000). If overflow is allowed (as is the default), then the month
70 will be incremented accordingly (so, February 29th 2001 would become
71 March 1st 2001, and June 31st 2000 would become July 1st 2000). If overflow
72 is not allowed, then the day will be adjusted to the last valid day in that
73 month (so, February 29th 2001 would become February 28th 2001 and
74 June 31st 2000 would become June 30th 2000).
75
76 AllowDayOverflow only applies to calculations involving months or years.
77
78 If set to $(D AllowDayOverflow.no), then day overflow is not allowed.
79
80 Otherwise, if set to $(D AllowDayOverflow.yes), then day overflow is
81 allowed.
82 +/
83 alias AllowDayOverflow = Flag!"allowDayOverflow";
84
85
86 /++
87 Array of the strings representing time units, starting with the smallest
88 unit and going to the largest. It does not include $(D "nsecs").
89
90 Includes $(D "hnsecs") (hecto-nanoseconds (100 ns)),
91 $(D "usecs") (microseconds), $(D "msecs") (milliseconds), $(D "seconds"),
92 $(D "minutes"), $(D "hours"), $(D "days"), $(D "weeks"), $(D "months"), and
93 $(D "years")
94 +/
95 immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes",
96 "hours", "days", "weeks", "months", "years"];
97
98
99 /++
100 Combines the $(REF Date,std,datetime,date) and
101 $(REF TimeOfDay,std,datetime,date) structs to give an object which holds
102 both the date and the time. It is optimized for calendar-based operations and
103 has no concept of time zone. For an object which is optimized for time
104 operations based on the system time, use $(REF SysTime,std,datetime,systime).
105 $(REF SysTime,std,datetime,systime) has a concept of time zone and has much
106 higher precision (hnsecs). $(D DateTime) is intended primarily for
107 calendar-based uses rather than precise time operations.
108 +/
109 struct DateTime
110 {
111 public:
112
113 /++
114 Params:
115 date = The date portion of $(LREF DateTime).
116 tod = The time portion of $(LREF DateTime).
117 +/
118 this(in Date date, in TimeOfDay tod = TimeOfDay.init) @safe pure nothrow @nogc
119 {
120 _date = date;
121 _tod = tod;
122 }
123
124 @safe unittest
125 {
126 {
127 auto dt = DateTime.init;
128 assert(dt._date == Date.init);
129 assert(dt._tod == TimeOfDay.init);
130 }
131
132 {
133 auto dt = DateTime(Date(1999, 7 ,6));
134 assert(dt._date == Date(1999, 7, 6));
135 assert(dt._tod == TimeOfDay.init);
136 }
137
138 {
139 auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33));
140 assert(dt._date == Date(1999, 7, 6));
141 assert(dt._tod == TimeOfDay(12, 30, 33));
142 }
143 }
144
145
146 /++
147 Params:
148 year = The year portion of the date.
149 month = The month portion of the date (January is 1).
150 day = The day portion of the date.
151 hour = The hour portion of the time;
152 minute = The minute portion of the time;
153 second = The second portion of the time;
154 +/
155 this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0) @safe pure
156 {
157 _date = Date(year, month, day);
158 _tod = TimeOfDay(hour, minute, second);
159 }
160
161 @safe unittest
162 {
163 {
164 auto dt = DateTime(1999, 7 ,6);
165 assert(dt._date == Date(1999, 7, 6));
166 assert(dt._tod == TimeOfDay.init);
167 }
168
169 {
170 auto dt = DateTime(1999, 7 ,6, 12, 30, 33);
171 assert(dt._date == Date(1999, 7, 6));
172 assert(dt._tod == TimeOfDay(12, 30, 33));
173 }
174 }
175
176
177 /++
178 Compares this $(LREF DateTime) with the given $(D DateTime.).
179
180 Returns:
181 $(BOOKTABLE,
182 $(TR $(TD this < rhs) $(TD < 0))
183 $(TR $(TD this == rhs) $(TD 0))
184 $(TR $(TD this > rhs) $(TD > 0))
185 )
186 +/
187 int opCmp(in DateTime rhs) const @safe pure nothrow @nogc
188 {
189 immutable dateResult = _date.opCmp(rhs._date);
190
191 if (dateResult != 0)
192 return dateResult;
193
194 return _tod.opCmp(rhs._tod);
195 }
196
197 @safe unittest
198 {
199 // Test A.D.
200 assert(DateTime(Date.init, TimeOfDay.init).opCmp(DateTime.init) == 0);
201
202 assert(DateTime(Date(1999, 1, 1)).opCmp(DateTime(Date(1999, 1, 1))) == 0);
203 assert(DateTime(Date(1, 7, 1)).opCmp(DateTime(Date(1, 7, 1))) == 0);
204 assert(DateTime(Date(1, 1, 6)).opCmp(DateTime(Date(1, 1, 6))) == 0);
205
206 assert(DateTime(Date(1999, 7, 1)).opCmp(DateTime(Date(1999, 7, 1))) == 0);
207 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) == 0);
208
209 assert(DateTime(Date(1, 7, 6)).opCmp(DateTime(Date(1, 7, 6))) == 0);
210
211 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
212 assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
213 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 8, 6))) < 0);
214 assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
215 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) < 0);
216 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 7, 6))) > 0);
217
218 assert(DateTime(Date(1999, 8, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
219 assert(DateTime(Date(2000, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
220 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0);
221 assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
222 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 8, 6))) < 0);
223 assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0);
224
225
226 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).opCmp(
227 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))) == 0);
228 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)).opCmp(
229 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))) == 0);
230 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)).opCmp(
231 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))) == 0);
232 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp(
233 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0);
234
235 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)).opCmp(
236 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))) == 0);
237 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
238 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) == 0);
239
240 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)).opCmp(
241 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))) == 0);
242 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp(
243 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0);
244
245 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
246 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
247 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
248 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
249 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
250 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0);
251 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
252 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
253 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
254 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) < 0);
255 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
256 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
257
258 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
259 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
260 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
261 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
262 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
263 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
264 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
265 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0);
266
267 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
268 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
269 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
270 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0);
271
272 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
273 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
274 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
275 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
276 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
277 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
278 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
279 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
280 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
281 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0);
282 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
283 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
284
285 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
286 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
287 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
288 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
289 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
290 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
291 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
292 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0);
293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
294 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
295 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
296 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
297
298 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp(
299 DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
300 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
301 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0);
302 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp(
303 DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))) < 0);
304 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
305 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
306 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp(
307 DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
308 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
309 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0);
310
311 // Test B.C.
312 assert(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)).opCmp(
313 DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))) == 0);
314 assert(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)).opCmp(
315 DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))) == 0);
316 assert(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)).opCmp(
317 DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))) == 0);
318
319 assert(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)).opCmp(
320 DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))) == 0);
321 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
322 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) == 0);
323
324 assert(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
325 DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))) == 0);
326
327 assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
328 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
329 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
330 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
331 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
332 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
333 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
334 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
335 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
336 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
337 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
338 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
339
340 assert(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
341 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
342 assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp(
343 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
344 assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
345 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0);
346 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
347 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0);
348 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
349 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0);
350 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
351 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0);
352
353 // Test Both
354 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
355 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
356 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
357 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
358
359 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
360 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
361 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
362 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) > 0);
363
364 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp(
365 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
366 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
367 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0);
368
369 assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp(
370 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0);
371 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp(
372 DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))) > 0);
373
374 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp(
375 DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))) < 0);
376 assert(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)).opCmp(
377 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0);
378
379 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
380 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
381 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30));
382 assert(dt.opCmp(dt) == 0);
383 assert(dt.opCmp(cdt) == 0);
384 assert(dt.opCmp(idt) == 0);
385 assert(cdt.opCmp(dt) == 0);
386 assert(cdt.opCmp(cdt) == 0);
387 assert(cdt.opCmp(idt) == 0);
388 assert(idt.opCmp(dt) == 0);
389 assert(idt.opCmp(cdt) == 0);
390 assert(idt.opCmp(idt) == 0);
391 }
392
393
394 /++
395 The date portion of $(LREF DateTime).
396 +/
397 @property Date date() const @safe pure nothrow @nogc
398 {
399 return _date;
400 }
401
402 @safe unittest
403 {
404 {
405 auto dt = DateTime.init;
406 assert(dt.date == Date.init);
407 }
408
409 {
410 auto dt = DateTime(Date(1999, 7, 6));
411 assert(dt.date == Date(1999, 7, 6));
412 }
413
414 const cdt = DateTime(1999, 7, 6);
415 immutable idt = DateTime(1999, 7, 6);
416 assert(cdt.date == Date(1999, 7, 6));
417 assert(idt.date == Date(1999, 7, 6));
418 }
419
420
421 /++
422 The date portion of $(LREF DateTime).
423
424 Params:
425 date = The Date to set this $(LREF DateTime)'s date portion to.
426 +/
427 @property void date(in Date date) @safe pure nothrow @nogc
428 {
429 _date = date;
430 }
431
432 @safe unittest
433 {
434 auto dt = DateTime.init;
435 dt.date = Date(1999, 7, 6);
436 assert(dt._date == Date(1999, 7, 6));
437 assert(dt._tod == TimeOfDay.init);
438
439 const cdt = DateTime(1999, 7, 6);
440 immutable idt = DateTime(1999, 7, 6);
441 static assert(!__traits(compiles, cdt.date = Date(2010, 1, 1)));
442 static assert(!__traits(compiles, idt.date = Date(2010, 1, 1)));
443 }
444
445
446 /++
447 The time portion of $(LREF DateTime).
448 +/
449 @property TimeOfDay timeOfDay() const @safe pure nothrow @nogc
450 {
451 return _tod;
452 }
453
454 @safe unittest
455 {
456 {
457 auto dt = DateTime.init;
458 assert(dt.timeOfDay == TimeOfDay.init);
459 }
460
461 {
462 auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33));
463 assert(dt.timeOfDay == TimeOfDay(12, 30, 33));
464 }
465
466 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
467 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
468 assert(cdt.timeOfDay == TimeOfDay(12, 30, 33));
469 assert(idt.timeOfDay == TimeOfDay(12, 30, 33));
470 }
471
472
473 /++
474 The time portion of $(LREF DateTime).
475
476 Params:
477 tod = The $(REF TimeOfDay,std,datetime,date) to set this
478 $(LREF DateTime)'s time portion to.
479 +/
480 @property void timeOfDay(in TimeOfDay tod) @safe pure nothrow @nogc
481 {
482 _tod = tod;
483 }
484
485 @safe unittest
486 {
487 auto dt = DateTime.init;
488 dt.timeOfDay = TimeOfDay(12, 30, 33);
489 assert(dt._date == Date.init);
490 assert(dt._tod == TimeOfDay(12, 30, 33));
491
492 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
493 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
494 static assert(!__traits(compiles, cdt.timeOfDay = TimeOfDay(12, 30, 33)));
495 static assert(!__traits(compiles, idt.timeOfDay = TimeOfDay(12, 30, 33)));
496 }
497
498
499 /++
500 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
501 are B.C.
502 +/
503 @property short year() const @safe pure nothrow @nogc
504 {
505 return _date.year;
506 }
507
508 @safe unittest
509 {
510 assert(Date.init.year == 1);
511 assert(Date(1999, 7, 6).year == 1999);
512 assert(Date(-1999, 7, 6).year == -1999);
513
514 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
515 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
516 assert(idt.year == 1999);
517 assert(idt.year == 1999);
518 }
519
520
521 /++
522 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
523 are B.C.
524
525 Params:
526 year = The year to set this $(LREF DateTime)'s year to.
527
528 Throws:
529 $(REF DateTimeException,std,datetime,date) if the new year is not
530 a leap year and if the resulting date would be on February 29th.
531 +/
532 @property void year(int year) @safe pure
533 {
534 _date.year = year;
535 }
536
537 ///
538 @safe unittest
539 {
540 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999);
541 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010);
542 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7);
543 }
544
545 @safe unittest
546 {
547 static void testDT(DateTime dt, int year, in DateTime expected, size_t line = __LINE__)
548 {
549 dt.year = year;
550 assert(dt == expected);
551 }
552
553 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)),
554 1999,
555 DateTime(Date(1999, 1, 1), TimeOfDay(12, 30, 33)));
556 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)),
557 0,
558 DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)));
559 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)),
560 -1999,
561 DateTime(Date(-1999, 1, 1), TimeOfDay(12, 30, 33)));
562
563 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
564 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
565 static assert(!__traits(compiles, cdt.year = 7));
566 static assert(!__traits(compiles, idt.year = 7));
567 }
568
569
570 /++
571 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
572
573 Throws:
574 $(REF DateTimeException,std,datetime,date) if $(D isAD) is true.
575 +/
576 @property short yearBC() const @safe pure
577 {
578 return _date.yearBC;
579 }
580
581 ///
582 @safe unittest
583 {
584 assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1);
585 assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2);
586 assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101);
587 }
588
589 @safe unittest
590 {
591 assertThrown!DateTimeException((in DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1))));
592
593 auto dt = DateTime(1999, 7, 6, 12, 30, 33);
594 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
595 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
596 dt.yearBC = 12;
597 assert(dt.yearBC == 12);
598 static assert(!__traits(compiles, cdt.yearBC = 12));
599 static assert(!__traits(compiles, idt.yearBC = 12));
600 }
601
602
603 /++
604 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
605
606 Params:
607 year = The year B.C. to set this $(LREF DateTime)'s year to.
608
609 Throws:
610 $(REF DateTimeException,std,datetime,date) if a non-positive value
611 is given.
612 +/
613 @property void yearBC(int year) @safe pure
614 {
615 _date.yearBC = year;
616 }
617
618 ///
619 @safe unittest
620 {
621 auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0));
622 dt.yearBC = 1;
623 assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0)));
624
625 dt.yearBC = 10;
626 assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0)));
627 }
628
629 @safe unittest
630 {
631 assertThrown!DateTimeException((DateTime dt){dt.yearBC = -1;}(DateTime(Date(1, 1, 1))));
632
633 auto dt = DateTime(1999, 7, 6, 12, 30, 33);
634 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
635 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
636 dt.yearBC = 12;
637 assert(dt.yearBC == 12);
638 static assert(!__traits(compiles, cdt.yearBC = 12));
639 static assert(!__traits(compiles, idt.yearBC = 12));
640 }
641
642
643 /++
644 Month of a Gregorian Year.
645 +/
646 @property Month month() const @safe pure nothrow @nogc
647 {
648 return _date.month;
649 }
650
651 ///
652 @safe unittest
653 {
654 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7);
655 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10);
656 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4);
657 }
658
659 @safe unittest
660 {
661 assert(DateTime.init.month == 1);
662 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7);
663 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7);
664
665 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
666 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
667 assert(cdt.month == 7);
668 assert(idt.month == 7);
669 }
670
671
672 /++
673 Month of a Gregorian Year.
674
675 Params:
676 month = The month to set this $(LREF DateTime)'s month to.
677
678 Throws:
679 $(REF DateTimeException,std,datetime,date) if the given month is
680 not a valid month.
681 +/
682 @property void month(Month month) @safe pure
683 {
684 _date.month = month;
685 }
686
687 @safe unittest
688 {
689 static void testDT(DateTime dt, Month month, in DateTime expected = DateTime.init, size_t line = __LINE__)
690 {
691 dt.month = month;
692 assert(expected != DateTime.init);
693 assert(dt == expected);
694 }
695
696 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 0));
697 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 13));
698
699 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)),
700 cast(Month) 7,
701 DateTime(Date(1, 7, 1), TimeOfDay(12, 30, 33)));
702 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)),
703 cast(Month) 7,
704 DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)));
705
706 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
707 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
708 static assert(!__traits(compiles, cdt.month = 12));
709 static assert(!__traits(compiles, idt.month = 12));
710 }
711
712
713 /++
714 Day of a Gregorian Month.
715 +/
716 @property ubyte day() const @safe pure nothrow @nogc
717 {
718 return _date.day;
719 }
720
721 ///
722 @safe unittest
723 {
724 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6);
725 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4);
726 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5);
727 }
728
729 @safe unittest
730 {
731 import std.format : format;
732 import std.range : chain;
733
734 static void test(DateTime dateTime, int expected)
735 {
736 assert(dateTime.day == expected, format("Value given: %s", dateTime));
737 }
738
739 foreach (year; chain(testYearsBC, testYearsAD))
740 {
741 foreach (md; testMonthDays)
742 {
743 foreach (tod; testTODs)
744 test(DateTime(Date(year, md.month, md.day), tod), md.day);
745 }
746 }
747
748 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
749 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
750 assert(cdt.day == 6);
751 assert(idt.day == 6);
752 }
753
754
755 /++
756 Day of a Gregorian Month.
757
758 Params:
759 day = The day of the month to set this $(LREF DateTime)'s day to.
760
761 Throws:
762 $(REF DateTimeException,std,datetime,date) if the given day is not
763 a valid day of the current month.
764 +/
765 @property void day(int day) @safe pure
766 {
767 _date.day = day;
768 }
769
770 @safe unittest
771 {
772 import std.exception : assertNotThrown;
773
774 static void testDT(DateTime dt, int day)
775 {
776 dt.day = day;
777 }
778
779 // Test A.D.
780 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 0));
781 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 32));
782 assertThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 29));
783 assertThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 30));
784 assertThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 32));
785 assertThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 31));
786 assertThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 32));
787 assertThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 31));
788 assertThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 32));
789 assertThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 32));
790 assertThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 31));
791 assertThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 32));
792 assertThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 31));
793 assertThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 32));
794
795 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 31));
796 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 28));
797 assertNotThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 29));
798 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 31));
799 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 30));
800 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 31));
801 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 30));
802 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 31));
803 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 31));
804 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 30));
805 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 31));
806 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 30));
807 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 31));
808
809 {
810 auto dt = DateTime(Date(1, 1, 1), TimeOfDay(7, 12, 22));
811 dt.day = 6;
812 assert(dt == DateTime(Date(1, 1, 6), TimeOfDay(7, 12, 22)));
813 }
814
815 // Test B.C.
816 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 0));
817 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 32));
818 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 29));
819 assertThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 30));
820 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 32));
821 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 31));
822 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 32));
823 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 31));
824 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 32));
825 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 32));
826 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 31));
827 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 32));
828 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 31));
829 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 32));
830
831 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 31));
832 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 28));
833 assertNotThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 29));
834 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 31));
835 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 30));
836 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 31));
837 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 30));
838 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 31));
839 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 31));
840 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 30));
841 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 31));
842 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 30));
843 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 31));
844
845 auto dt = DateTime(Date(-1, 1, 1), TimeOfDay(7, 12, 22));
846 dt.day = 6;
847 assert(dt == DateTime(Date(-1, 1, 6), TimeOfDay(7, 12, 22)));
848
849 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
850 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
851 static assert(!__traits(compiles, cdt.day = 27));
852 static assert(!__traits(compiles, idt.day = 27));
853 }
854
855
856 /++
857 Hours past midnight.
858 +/
859 @property ubyte hour() const @safe pure nothrow @nogc
860 {
861 return _tod.hour;
862 }
863
864 @safe unittest
865 {
866 assert(DateTime.init.hour == 0);
867 assert(DateTime(Date.init, TimeOfDay(12, 0, 0)).hour == 12);
868
869 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
870 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
871 assert(cdt.hour == 12);
872 assert(idt.hour == 12);
873 }
874
875
876 /++
877 Hours past midnight.
878
879 Params:
880 hour = The hour of the day to set this $(LREF DateTime)'s hour to.
881
882 Throws:
883 $(REF DateTimeException,std,datetime,date) if the given hour would
884 result in an invalid $(LREF DateTime).
885 +/
886 @property void hour(int hour) @safe pure
887 {
888 _tod.hour = hour;
889 }
890
891 @safe unittest
892 {
893 assertThrown!DateTimeException((){DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).hour = 24;}());
894
895 auto dt = DateTime.init;
896 dt.hour = 12;
897 assert(dt == DateTime(1, 1, 1, 12, 0, 0));
898
899 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
900 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
901 static assert(!__traits(compiles, cdt.hour = 27));
902 static assert(!__traits(compiles, idt.hour = 27));
903 }
904
905
906 /++
907 Minutes past the hour.
908 +/
909 @property ubyte minute() const @safe pure nothrow @nogc
910 {
911 return _tod.minute;
912 }
913
914 @safe unittest
915 {
916 assert(DateTime.init.minute == 0);
917 assert(DateTime(1, 1, 1, 0, 30, 0).minute == 30);
918
919 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
920 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
921 assert(cdt.minute == 30);
922 assert(idt.minute == 30);
923 }
924
925
926 /++
927 Minutes past the hour.
928
929 Params:
930 minute = The minute to set this $(LREF DateTime)'s minute to.
931
932 Throws:
933 $(REF DateTimeException,std,datetime,date) if the given minute
934 would result in an invalid $(LREF DateTime).
935 +/
936 @property void minute(int minute) @safe pure
937 {
938 _tod.minute = minute;
939 }
940
941 @safe unittest
942 {
943 assertThrown!DateTimeException((){DateTime.init.minute = 60;}());
944
945 auto dt = DateTime.init;
946 dt.minute = 30;
947 assert(dt == DateTime(1, 1, 1, 0, 30, 0));
948
949 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
950 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
951 static assert(!__traits(compiles, cdt.minute = 27));
952 static assert(!__traits(compiles, idt.minute = 27));
953 }
954
955
956 /++
957 Seconds past the minute.
958 +/
959 @property ubyte second() const @safe pure nothrow @nogc
960 {
961 return _tod.second;
962 }
963
964 @safe unittest
965 {
966 assert(DateTime.init.second == 0);
967 assert(DateTime(1, 1, 1, 0, 0, 33).second == 33);
968
969 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
970 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
971 assert(cdt.second == 33);
972 assert(idt.second == 33);
973 }
974
975
976 /++
977 Seconds past the minute.
978
979 Params:
980 second = The second to set this $(LREF DateTime)'s second to.
981
982 Throws:
983 $(REF DateTimeException,std,datetime,date) if the given seconds
984 would result in an invalid $(LREF DateTime).
985 +/
986 @property void second(int second) @safe pure
987 {
988 _tod.second = second;
989 }
990
991 @safe unittest
992 {
993 assertThrown!DateTimeException((){DateTime.init.second = 60;}());
994
995 auto dt = DateTime.init;
996 dt.second = 33;
997 assert(dt == DateTime(1, 1, 1, 0, 0, 33));
998
999 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1000 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1001 static assert(!__traits(compiles, cdt.second = 27));
1002 static assert(!__traits(compiles, idt.second = 27));
1003 }
1004
1005
1006 /++
1007 Adds the given number of years or months to this $(LREF DateTime). A
1008 negative number will subtract.
1009
1010 Note that if day overflow is allowed, and the date with the adjusted
1011 year/month overflows the number of days in the new month, then the month
1012 will be incremented by one, and the day set to the number of days
1013 overflowed. (e.g. if the day were 31 and the new month were June, then
1014 the month would be incremented to July, and the new day would be 1). If
1015 day overflow is not allowed, then the day will be set to the last valid
1016 day in the month (e.g. June 31st would become June 30th).
1017
1018 Params:
1019 units = The type of units to add ("years" or "months").
1020 value = The number of months or years to add to this
1021 $(LREF DateTime).
1022 allowOverflow = Whether the days should be allowed to overflow,
1023 causing the month to increment.
1024 +/
1025 ref DateTime add(string units)
1026 (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
1027 if (units == "years" || units == "months")
1028 {
1029 _date.add!units(value, allowOverflow);
1030 return this;
1031 }
1032
1033 ///
1034 @safe unittest
1035 {
1036 auto dt1 = DateTime(2010, 1, 1, 12, 30, 33);
1037 dt1.add!"months"(11);
1038 assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33));
1039
1040 auto dt2 = DateTime(2010, 1, 1, 12, 30, 33);
1041 dt2.add!"months"(-11);
1042 assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33));
1043
1044 auto dt3 = DateTime(2000, 2, 29, 12, 30, 33);
1045 dt3.add!"years"(1);
1046 assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33));
1047
1048 auto dt4 = DateTime(2000, 2, 29, 12, 30, 33);
1049 dt4.add!"years"(1, AllowDayOverflow.no);
1050 assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33));
1051 }
1052
1053 @safe unittest
1054 {
1055 auto dt = DateTime(2000, 1, 31);
1056 dt.add!"years"(7).add!"months"(-4);
1057 assert(dt == DateTime(2006, 10, 1));
1058
1059 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1060 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1061 static assert(!__traits(compiles, cdt.add!"years"(4)));
1062 static assert(!__traits(compiles, idt.add!"years"(4)));
1063 static assert(!__traits(compiles, cdt.add!"months"(4)));
1064 static assert(!__traits(compiles, idt.add!"months"(4)));
1065 }
1066
1067
1068 /++
1069 Adds the given number of years or months to this $(LREF DateTime). A
1070 negative number will subtract.
1071
1072 The difference between rolling and adding is that rolling does not
1073 affect larger units. Rolling a $(LREF DateTime) 12 months
1074 gets the exact same $(LREF DateTime). However, the days can still be
1075 affected due to the differing number of days in each month.
1076
1077 Because there are no units larger than years, there is no difference
1078 between adding and rolling years.
1079
1080 Params:
1081 units = The type of units to add ("years" or "months").
1082 value = The number of months or years to add to this
1083 $(LREF DateTime).
1084 allowOverflow = Whether the days should be allowed to overflow,
1085 causing the month to increment.
1086 +/
1087 ref DateTime roll(string units)
1088 (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
1089 if (units == "years" || units == "months")
1090 {
1091 _date.roll!units(value, allowOverflow);
1092 return this;
1093 }
1094
1095 ///
1096 @safe unittest
1097 {
1098 auto dt1 = DateTime(2010, 1, 1, 12, 33, 33);
1099 dt1.roll!"months"(1);
1100 assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33));
1101
1102 auto dt2 = DateTime(2010, 1, 1, 12, 33, 33);
1103 dt2.roll!"months"(-1);
1104 assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33));
1105
1106 auto dt3 = DateTime(1999, 1, 29, 12, 33, 33);
1107 dt3.roll!"months"(1);
1108 assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33));
1109
1110 auto dt4 = DateTime(1999, 1, 29, 12, 33, 33);
1111 dt4.roll!"months"(1, AllowDayOverflow.no);
1112 assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33));
1113
1114 auto dt5 = DateTime(2000, 2, 29, 12, 30, 33);
1115 dt5.roll!"years"(1);
1116 assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33));
1117
1118 auto dt6 = DateTime(2000, 2, 29, 12, 30, 33);
1119 dt6.roll!"years"(1, AllowDayOverflow.no);
1120 assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33));
1121 }
1122
1123 @safe unittest
1124 {
1125 auto dt = DateTime(2000, 1, 31);
1126 dt.roll!"years"(7).roll!"months"(-4);
1127 assert(dt == DateTime(2007, 10, 1));
1128
1129 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1130 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1131 static assert(!__traits(compiles, cdt.roll!"years"(4)));
1132 static assert(!__traits(compiles, idt.roll!"years"(4)));
1133 static assert(!__traits(compiles, cdt.roll!"months"(4)));
1134 static assert(!__traits(compiles, idt.roll!"months"(4)));
1135 }
1136
1137
1138 /++
1139 Adds the given number of units to this $(LREF DateTime). A negative
1140 number will subtract.
1141
1142 The difference between rolling and adding is that rolling does not
1143 affect larger units. For instance, rolling a $(LREF DateTime) one
1144 year's worth of days gets the exact same $(LREF DateTime).
1145
1146 Accepted units are $(D "days"), $(D "minutes"), $(D "hours"),
1147 $(D "minutes"), and $(D "seconds").
1148
1149 Params:
1150 units = The units to add.
1151 value = The number of $(D_PARAM units) to add to this
1152 $(LREF DateTime).
1153 +/
1154 ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
1155 if (units == "days")
1156 {
1157 _date.roll!"days"(value);
1158 return this;
1159 }
1160
1161 ///
1162 @safe unittest
1163 {
1164 auto dt1 = DateTime(2010, 1, 1, 11, 23, 12);
1165 dt1.roll!"days"(1);
1166 assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12));
1167 dt1.roll!"days"(365);
1168 assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12));
1169 dt1.roll!"days"(-32);
1170 assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12));
1171
1172 auto dt2 = DateTime(2010, 7, 4, 12, 0, 0);
1173 dt2.roll!"hours"(1);
1174 assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0));
1175
1176 auto dt3 = DateTime(2010, 1, 1, 0, 0, 0);
1177 dt3.roll!"seconds"(-1);
1178 assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59));
1179 }
1180
1181 @safe unittest
1182 {
1183 auto dt = DateTime(2000, 1, 31);
1184 dt.roll!"days"(7).roll!"days"(-4);
1185 assert(dt == DateTime(2000, 1, 3));
1186
1187 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1188 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1189 static assert(!__traits(compiles, cdt.roll!"days"(4)));
1190 static assert(!__traits(compiles, idt.roll!"days"(4)));
1191 }
1192
1193
1194 // Shares documentation with "days" version.
1195 ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
1196 if (units == "hours" ||
1197 units == "minutes" ||
1198 units == "seconds")
1199 {
1200 _tod.roll!units(value);
1201 return this;
1202 }
1203
1204 // Test roll!"hours"().
1205 @safe unittest
1206 {
1207 static void testDT(DateTime orig, int hours, in DateTime expected, size_t line = __LINE__)
1208 {
1209 orig.roll!"hours"(hours);
1210 assert(orig == expected);
1211 }
1212
1213 // Test A.D.
1214 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1215 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1216 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1217 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
1218 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1219 DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33)));
1220 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1221 DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33)));
1222 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1223 DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33)));
1224 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1225 DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33)));
1226 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 6,
1227 DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33)));
1228 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7,
1229 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
1230 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 8,
1231 DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33)));
1232 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 9,
1233 DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33)));
1234 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1235 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
1236 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 11,
1237 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
1238 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 12,
1239 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
1240 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 13,
1241 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
1242 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 14,
1243 DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33)));
1244 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1245 DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33)));
1246 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 16,
1247 DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33)));
1248 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 17,
1249 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
1250 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 18,
1251 DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33)));
1252 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 19,
1253 DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33)));
1254 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 20,
1255 DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33)));
1256 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 21,
1257 DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33)));
1258 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 22,
1259 DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33)));
1260 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 23,
1261 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
1262 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 24,
1263 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1264 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 25,
1265 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
1266
1267 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1268 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
1269 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1270 DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33)));
1271 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1272 DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33)));
1273 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1274 DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33)));
1275 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1276 DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33)));
1277 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -6,
1278 DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33)));
1279 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -7,
1280 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
1281 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -8,
1282 DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33)));
1283 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -9,
1284 DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33)));
1285 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1286 DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33)));
1287 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -11,
1288 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
1289 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -12,
1290 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
1291 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -13,
1292 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
1293 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -14,
1294 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
1295 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1296 DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33)));
1297 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -16,
1298 DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33)));
1299 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -17,
1300 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
1301 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -18,
1302 DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33)));
1303 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -19,
1304 DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33)));
1305 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -20,
1306 DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33)));
1307 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -21,
1308 DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33)));
1309 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -22,
1310 DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33)));
1311 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -23,
1312 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)));
1313 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -24,
1314 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1315 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -25,
1316 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)));
1317
1318 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 1,
1319 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33)));
1320 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 0,
1321 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
1322 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), -1,
1323 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
1324
1325 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 1,
1326 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)));
1327 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 0,
1328 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)));
1329 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), -1,
1330 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33)));
1331
1332 testDT(DateTime(Date(1999, 7, 31), TimeOfDay(23, 30, 33)), 1,
1333 DateTime(Date(1999, 7, 31), TimeOfDay(0, 30, 33)));
1334 testDT(DateTime(Date(1999, 8, 1), TimeOfDay(0, 30, 33)), -1,
1335 DateTime(Date(1999, 8, 1), TimeOfDay(23, 30, 33)));
1336
1337 testDT(DateTime(Date(1999, 12, 31), TimeOfDay(23, 30, 33)), 1,
1338 DateTime(Date(1999, 12, 31), TimeOfDay(0, 30, 33)));
1339 testDT(DateTime(Date(2000, 1, 1), TimeOfDay(0, 30, 33)), -1,
1340 DateTime(Date(2000, 1, 1), TimeOfDay(23, 30, 33)));
1341
1342 testDT(DateTime(Date(1999, 2, 28), TimeOfDay(23, 30, 33)), 25,
1343 DateTime(Date(1999, 2, 28), TimeOfDay(0, 30, 33)));
1344 testDT(DateTime(Date(1999, 3, 2), TimeOfDay(0, 30, 33)), -25,
1345 DateTime(Date(1999, 3, 2), TimeOfDay(23, 30, 33)));
1346
1347 testDT(DateTime(Date(2000, 2, 28), TimeOfDay(23, 30, 33)), 25,
1348 DateTime(Date(2000, 2, 28), TimeOfDay(0, 30, 33)));
1349 testDT(DateTime(Date(2000, 3, 1), TimeOfDay(0, 30, 33)), -25,
1350 DateTime(Date(2000, 3, 1), TimeOfDay(23, 30, 33)));
1351
1352 // Test B.C.
1353 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1354 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1355 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1356 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
1357 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1358 DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33)));
1359 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1360 DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33)));
1361 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1362 DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33)));
1363 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1364 DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33)));
1365 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 6,
1366 DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33)));
1367 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7,
1368 DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33)));
1369 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 8,
1370 DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33)));
1371 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 9,
1372 DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33)));
1373 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1374 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
1375 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 11,
1376 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
1377 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 12,
1378 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
1379 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 13,
1380 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
1381 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 14,
1382 DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33)));
1383 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1384 DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33)));
1385 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 16,
1386 DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33)));
1387 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 17,
1388 DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33)));
1389 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 18,
1390 DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33)));
1391 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 19,
1392 DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33)));
1393 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 20,
1394 DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33)));
1395 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 21,
1396 DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33)));
1397 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 22,
1398 DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33)));
1399 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 23,
1400 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
1401 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 24,
1402 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1403 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 25,
1404 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
1405
1406 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1407 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
1408 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1409 DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33)));
1410 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1411 DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33)));
1412 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1413 DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33)));
1414 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1415 DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33)));
1416 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -6,
1417 DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33)));
1418 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -7,
1419 DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33)));
1420 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -8,
1421 DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33)));
1422 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -9,
1423 DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33)));
1424 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1425 DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33)));
1426 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -11,
1427 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
1428 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -12,
1429 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
1430 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -13,
1431 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
1432 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -14,
1433 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
1434 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1435 DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33)));
1436 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -16,
1437 DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33)));
1438 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -17,
1439 DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33)));
1440 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -18,
1441 DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33)));
1442 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -19,
1443 DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33)));
1444 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -20,
1445 DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33)));
1446 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -21,
1447 DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33)));
1448 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -22,
1449 DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33)));
1450 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -23,
1451 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33)));
1452 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -24,
1453 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1454 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -25,
1455 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33)));
1456
1457 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 1,
1458 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33)));
1459 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 0,
1460 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
1461 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), -1,
1462 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
1463
1464 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 1,
1465 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)));
1466 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 0,
1467 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)));
1468 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), -1,
1469 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33)));
1470
1471 testDT(DateTime(Date(-1999, 7, 31), TimeOfDay(23, 30, 33)), 1,
1472 DateTime(Date(-1999, 7, 31), TimeOfDay(0, 30, 33)));
1473 testDT(DateTime(Date(-1999, 8, 1), TimeOfDay(0, 30, 33)), -1,
1474 DateTime(Date(-1999, 8, 1), TimeOfDay(23, 30, 33)));
1475
1476 testDT(DateTime(Date(-2001, 12, 31), TimeOfDay(23, 30, 33)), 1,
1477 DateTime(Date(-2001, 12, 31), TimeOfDay(0, 30, 33)));
1478 testDT(DateTime(Date(-2000, 1, 1), TimeOfDay(0, 30, 33)), -1,
1479 DateTime(Date(-2000, 1, 1), TimeOfDay(23, 30, 33)));
1480
1481 testDT(DateTime(Date(-2001, 2, 28), TimeOfDay(23, 30, 33)), 25,
1482 DateTime(Date(-2001, 2, 28), TimeOfDay(0, 30, 33)));
1483 testDT(DateTime(Date(-2001, 3, 2), TimeOfDay(0, 30, 33)), -25,
1484 DateTime(Date(-2001, 3, 2), TimeOfDay(23, 30, 33)));
1485
1486 testDT(DateTime(Date(-2000, 2, 28), TimeOfDay(23, 30, 33)), 25,
1487 DateTime(Date(-2000, 2, 28), TimeOfDay(0, 30, 33)));
1488 testDT(DateTime(Date(-2000, 3, 1), TimeOfDay(0, 30, 33)), -25,
1489 DateTime(Date(-2000, 3, 1), TimeOfDay(23, 30, 33)));
1490
1491 // Test Both
1492 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 17_546,
1493 DateTime(Date(-1, 1, 1), TimeOfDay(13, 30, 33)));
1494 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -17_546,
1495 DateTime(Date(1, 1, 1), TimeOfDay(11, 30, 33)));
1496
1497 auto dt = DateTime(2000, 1, 31, 9, 7, 6);
1498 dt.roll!"hours"(27).roll!"hours"(-9);
1499 assert(dt == DateTime(2000, 1, 31, 3, 7, 6));
1500
1501 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1502 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1503 static assert(!__traits(compiles, cdt.roll!"hours"(4)));
1504 static assert(!__traits(compiles, idt.roll!"hours"(4)));
1505 }
1506
1507 // Test roll!"minutes"().
1508 @safe unittest
1509 {
1510 static void testDT(DateTime orig, int minutes, in DateTime expected, size_t line = __LINE__)
1511 {
1512 orig.roll!"minutes"(minutes);
1513 assert(orig == expected);
1514 }
1515
1516 // Test A.D.
1517 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1518 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1519 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1520 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
1521 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1522 DateTime(Date(1999, 7, 6), TimeOfDay(12, 32, 33)));
1523 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1524 DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 33)));
1525 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1526 DateTime(Date(1999, 7, 6), TimeOfDay(12, 34, 33)));
1527 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1528 DateTime(Date(1999, 7, 6), TimeOfDay(12, 35, 33)));
1529 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1530 DateTime(Date(1999, 7, 6), TimeOfDay(12, 40, 33)));
1531 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1532 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
1533 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 29,
1534 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
1535 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30,
1536 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1537 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 45,
1538 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
1539 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60,
1540 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1541 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 75,
1542 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
1543 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 90,
1544 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1545 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 100,
1546 DateTime(Date(1999, 7, 6), TimeOfDay(12, 10, 33)));
1547
1548 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 689,
1549 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
1550 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 690,
1551 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1552 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 691,
1553 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
1554 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 960,
1555 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1556 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1439,
1557 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
1558 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1440,
1559 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1560 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1441,
1561 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
1562 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2880,
1563 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1564
1565 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1566 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
1567 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1568 DateTime(Date(1999, 7, 6), TimeOfDay(12, 28, 33)));
1569 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1570 DateTime(Date(1999, 7, 6), TimeOfDay(12, 27, 33)));
1571 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1572 DateTime(Date(1999, 7, 6), TimeOfDay(12, 26, 33)));
1573 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1574 DateTime(Date(1999, 7, 6), TimeOfDay(12, 25, 33)));
1575 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1576 DateTime(Date(1999, 7, 6), TimeOfDay(12, 20, 33)));
1577 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1578 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
1579 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -29,
1580 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
1581 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -30,
1582 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1583 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -45,
1584 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33)));
1585 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60,
1586 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1587 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -75,
1588 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33)));
1589 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -90,
1590 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1591 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -100,
1592 DateTime(Date(1999, 7, 6), TimeOfDay(12, 50, 33)));
1593
1594 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -749,
1595 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
1596 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -750,
1597 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1598 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -751,
1599 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
1600 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -960,
1601 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1602 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1439,
1603 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)));
1604 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1440,
1605 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1606 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1441,
1607 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33)));
1608 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2880,
1609 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1610
1611 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 1,
1612 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33)));
1613 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 0,
1614 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)));
1615 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), -1,
1616 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33)));
1617
1618 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 1,
1619 DateTime(Date(1999, 7, 6), TimeOfDay(11, 0, 33)));
1620 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 0,
1621 DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)));
1622 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), -1,
1623 DateTime(Date(1999, 7, 6), TimeOfDay(11, 58, 33)));
1624
1625 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 1,
1626 DateTime(Date(1999, 7, 6), TimeOfDay(0, 1, 33)));
1627 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 0,
1628 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)));
1629 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), -1,
1630 DateTime(Date(1999, 7, 6), TimeOfDay(0, 59, 33)));
1631
1632 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 1,
1633 DateTime(Date(1999, 7, 5), TimeOfDay(23, 0, 33)));
1634 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 0,
1635 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)));
1636 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), -1,
1637 DateTime(Date(1999, 7, 5), TimeOfDay(23, 58, 33)));
1638
1639 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 1,
1640 DateTime(Date(1998, 12, 31), TimeOfDay(23, 0, 33)));
1641 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 0,
1642 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)));
1643 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), -1,
1644 DateTime(Date(1998, 12, 31), TimeOfDay(23, 58, 33)));
1645
1646 // Test B.C.
1647 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1648 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1649 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1650 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
1651 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1652 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 32, 33)));
1653 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1654 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 33, 33)));
1655 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1656 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 34, 33)));
1657 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1658 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 35, 33)));
1659 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1660 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 40, 33)));
1661 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1662 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
1663 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 29,
1664 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
1665 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30,
1666 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1667 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 45,
1668 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
1669 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60,
1670 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1671 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 75,
1672 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
1673 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 90,
1674 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1675 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 100,
1676 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 10, 33)));
1677
1678 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 689,
1679 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
1680 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 690,
1681 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1682 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 691,
1683 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
1684 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 960,
1685 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1686 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1439,
1687 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
1688 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1440,
1689 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1690 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1441,
1691 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
1692 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2880,
1693 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1694
1695 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1696 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
1697 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1698 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 28, 33)));
1699 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1700 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 27, 33)));
1701 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1702 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 26, 33)));
1703 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1704 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 25, 33)));
1705 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1706 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 20, 33)));
1707 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1708 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
1709 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -29,
1710 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
1711 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -30,
1712 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1713 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -45,
1714 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33)));
1715 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60,
1716 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1717 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -75,
1718 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33)));
1719 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -90,
1720 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1721 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -100,
1722 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 50, 33)));
1723
1724 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -749,
1725 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
1726 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -750,
1727 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1728 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -751,
1729 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
1730 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -960,
1731 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1732 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1439,
1733 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33)));
1734 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1440,
1735 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1736 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1441,
1737 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33)));
1738 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2880,
1739 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1740
1741 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 1,
1742 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33)));
1743 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 0,
1744 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)));
1745 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), -1,
1746 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33)));
1747
1748 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 1,
1749 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 0, 33)));
1750 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 0,
1751 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)));
1752 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), -1,
1753 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 58, 33)));
1754
1755 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 1,
1756 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 1, 33)));
1757 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 0,
1758 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)));
1759 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), -1,
1760 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 59, 33)));
1761
1762 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 1,
1763 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 0, 33)));
1764 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 0,
1765 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)));
1766 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), -1,
1767 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 58, 33)));
1768
1769 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 1,
1770 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 0, 33)));
1771 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 0,
1772 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)));
1773 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), -1,
1774 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 58, 33)));
1775
1776 // Test Both
1777 testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1,
1778 DateTime(Date(1, 1, 1), TimeOfDay(0, 59, 0)));
1779 testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)), 1,
1780 DateTime(Date(0, 12, 31), TimeOfDay(23, 0, 0)));
1781
1782 testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1,
1783 DateTime(Date(0, 1, 1), TimeOfDay(0, 59, 0)));
1784 testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)), 1,
1785 DateTime(Date(-1, 12, 31), TimeOfDay(23, 0, 0)));
1786
1787 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_760,
1788 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)));
1789 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -1_052_760,
1790 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
1791
1792 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_782,
1793 DateTime(Date(-1, 1, 1), TimeOfDay(11, 52, 33)));
1794 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 52, 33)), -1_052_782,
1795 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
1796
1797 auto dt = DateTime(2000, 1, 31, 9, 7, 6);
1798 dt.roll!"minutes"(92).roll!"minutes"(-292);
1799 assert(dt == DateTime(2000, 1, 31, 9, 47, 6));
1800
1801 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
1802 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
1803 static assert(!__traits(compiles, cdt.roll!"minutes"(4)));
1804 static assert(!__traits(compiles, idt.roll!"minutes"(4)));
1805 }
1806
1807 // Test roll!"seconds"().
1808 @safe unittest
1809 {
1810 static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__)
1811 {
1812 orig.roll!"seconds"(seconds);
1813 assert(orig == expected);
1814 }
1815
1816 // Test A.D.
1817 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1818 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1819 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1820 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
1821 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1822 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 35)));
1823 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1824 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 36)));
1825 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1826 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 37)));
1827 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1828 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 38)));
1829 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1830 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 43)));
1831 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1832 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 48)));
1833 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 26,
1834 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
1835 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 27,
1836 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
1837 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30,
1838 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 3)));
1839 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 59,
1840 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
1841 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60,
1842 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1843 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 61,
1844 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
1845
1846 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1766,
1847 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
1848 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1767,
1849 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
1850 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1768,
1851 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1)));
1852 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2007,
1853 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
1854 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3599,
1855 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
1856 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3600,
1857 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1858 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3601,
1859 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
1860 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7200,
1861 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1862
1863 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1864 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
1865 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1866 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 31)));
1867 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1868 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 30)));
1869 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1870 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 29)));
1871 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1872 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 28)));
1873 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1874 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 23)));
1875 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1876 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 18)));
1877 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -33,
1878 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
1879 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -34,
1880 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
1881 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -35,
1882 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 58)));
1883 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -59,
1884 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)));
1885 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60,
1886 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
1887 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -61,
1888 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32)));
1889
1890 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 1,
1891 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1)));
1892 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 0,
1893 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)));
1894 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), -1,
1895 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59)));
1896
1897 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 1,
1898 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 1)));
1899 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 0,
1900 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)));
1901 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), -1,
1902 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 59)));
1903
1904 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 1,
1905 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 1)));
1906 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 0,
1907 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)));
1908 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), -1,
1909 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 59)));
1910
1911 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 1,
1912 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 0)));
1913 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 0,
1914 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)));
1915 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), -1,
1916 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 58)));
1917
1918 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 1,
1919 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 0)));
1920 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 0,
1921 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)));
1922 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), -1,
1923 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 58)));
1924
1925 // Test B.C.
1926 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0,
1927 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1928 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1,
1929 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
1930 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2,
1931 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 35)));
1932 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3,
1933 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 36)));
1934 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4,
1935 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 37)));
1936 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5,
1937 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 38)));
1938 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10,
1939 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 43)));
1940 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15,
1941 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 48)));
1942 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 26,
1943 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
1944 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 27,
1945 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
1946 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30,
1947 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 3)));
1948 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 59,
1949 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
1950 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60,
1951 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1952 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 61,
1953 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
1954
1955 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1766,
1956 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
1957 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1767,
1958 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
1959 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1768,
1960 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1)));
1961 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2007,
1962 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
1963 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3599,
1964 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
1965 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3600,
1966 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1967 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3601,
1968 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
1969 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7200,
1970 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1971
1972 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1,
1973 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
1974 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2,
1975 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 31)));
1976 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3,
1977 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 30)));
1978 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4,
1979 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 29)));
1980 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5,
1981 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 28)));
1982 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10,
1983 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 23)));
1984 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15,
1985 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 18)));
1986 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -33,
1987 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
1988 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -34,
1989 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
1990 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -35,
1991 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 58)));
1992 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -59,
1993 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34)));
1994 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60,
1995 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
1996 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -61,
1997 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32)));
1998
1999 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 1,
2000 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1)));
2001 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 0,
2002 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)));
2003 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), -1,
2004 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59)));
2005
2006 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 1,
2007 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 1)));
2008 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 0,
2009 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)));
2010 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), -1,
2011 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 59)));
2012
2013 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 1,
2014 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 1)));
2015 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 0,
2016 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)));
2017 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), -1,
2018 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 59)));
2019
2020 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 1,
2021 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 0)));
2022 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 0,
2023 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)));
2024 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), -1,
2025 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 58)));
2026
2027 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 1,
2028 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 0)));
2029 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 0,
2030 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)));
2031 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), -1,
2032 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 58)));
2033
2034 // Test Both
2035 testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1,
2036 DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 59)));
2037 testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)), 1,
2038 DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)));
2039
2040 testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1,
2041 DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 59)));
2042 testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 59)), 1,
2043 DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)));
2044
2045 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_600L,
2046 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)));
2047 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -63_165_600L,
2048 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
2049
2050 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_617L,
2051 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 50)));
2052 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 50)), -63_165_617L,
2053 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)));
2054
2055 auto dt = DateTime(2000, 1, 31, 9, 7, 6);
2056 dt.roll!"seconds"(92).roll!"seconds"(-292);
2057 assert(dt == DateTime(2000, 1, 31, 9, 7, 46));
2058
2059 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2060 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2061 static assert(!__traits(compiles, cdt.roll!"seconds"(4)));
2062 static assert(!__traits(compiles, idt.roll!"seconds"(4)));
2063 }
2064
2065
2066 /++
2067 Gives the result of adding or subtracting a $(REF Duration, core,time)
2068 from this $(LREF DateTime).
2069
2070 The legal types of arithmetic for $(LREF DateTime) using this operator
2071 are
2072
2073 $(BOOKTABLE,
2074 $(TR $(TD DateTime) $(TD +) $(TD Duration) $(TD -->) $(TD DateTime))
2075 $(TR $(TD DateTime) $(TD -) $(TD Duration) $(TD -->) $(TD DateTime))
2076 )
2077
2078 Params:
2079 duration = The $(REF Duration, core,time) to add to or subtract from
2080 this $(LREF DateTime).
2081 +/
2082 DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
2083 if (op == "+" || op == "-")
2084 {
2085 DateTime retval = this;
2086 immutable seconds = duration.total!"seconds";
2087 mixin("return retval._addSeconds(" ~ op ~ "seconds);");
2088 }
2089
2090 ///
2091 @safe unittest
2092 {
2093 import core.time : hours, seconds;
2094
2095 assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) ==
2096 DateTime(2016, 1, 1, 0, 0, 0));
2097
2098 assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) ==
2099 DateTime(2016, 1, 1, 0, 59, 59));
2100
2101 assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) ==
2102 DateTime(2015, 12, 31, 23, 59, 59));
2103
2104 assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) ==
2105 DateTime(2015, 12, 31, 23, 59, 59));
2106 }
2107
2108 @safe unittest
2109 {
2110 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2111
2112 assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2113 assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2114 assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2115 assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2116
2117 assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2118 assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2119 assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2120 assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2121 assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2122 assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2123 assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2124 assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2125 assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2126 assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2127 assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2128 assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2129
2130 assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2131 assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2132 assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2133 assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2134
2135 assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2136 assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2137 assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2138 assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2139 assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2140 assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2141 assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2142 assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2143 assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2144 assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2145 assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2146 assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2147
2148 auto duration = dur!"seconds"(12);
2149 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2150 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2151 assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45));
2152 assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45));
2153 assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21));
2154 assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21));
2155 }
2156
2157 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
2158 deprecated("Use Duration instead of TickDuration.")
2159 DateTime opBinary(string op)(in TickDuration td) const @safe pure nothrow @nogc
2160 if (op == "+" || op == "-")
2161 {
2162 DateTime retval = this;
2163 immutable seconds = td.seconds;
2164 mixin("return retval._addSeconds(" ~ op ~ "seconds);");
2165 }
2166
2167 deprecated @safe unittest
2168 {
2169 // This probably only runs in cases where gettimeofday() is used, but it's
2170 // hard to do this test correctly with variable ticksPerSec.
2171 if (TickDuration.ticksPerSec == 1_000_000)
2172 {
2173 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2174
2175 assert(dt + TickDuration.from!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2176 assert(dt + TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2177
2178 assert(dt - TickDuration.from!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2179 assert(dt - TickDuration.from!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2180 }
2181 }
2182
2183
2184 /++
2185 Gives the result of adding or subtracting a duration from this
2186 $(LREF DateTime), as well as assigning the result to this
2187 $(LREF DateTime).
2188
2189 The legal types of arithmetic for $(LREF DateTime) using this operator
2190 are
2191
2192 $(BOOKTABLE,
2193 $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime))
2194 $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime))
2195 )
2196
2197 Params:
2198 duration = The duration to add to or subtract from this
2199 $(LREF DateTime).
2200 +/
2201 ref DateTime opOpAssign(string op, D)(in D duration) @safe pure nothrow @nogc
2202 if ((op == "+" || op == "-") &&
2203 (is(Unqual!D == Duration) ||
2204 is(Unqual!D == TickDuration)))
2205 {
2206 import std.format : format;
2207
2208 DateTime retval = this;
2209
2210 static if (is(Unqual!D == Duration))
2211 immutable hnsecs = duration.total!"hnsecs";
2212 else static if (is(Unqual!D == TickDuration))
2213 immutable hnsecs = duration.hnsecs;
2214
2215 mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
2216 }
2217
2218 @safe unittest
2219 {
2220 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) ==
2221 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2222 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) ==
2223 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2224 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) ==
2225 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2226 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) ==
2227 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2228
2229 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) ==
2230 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2231 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) ==
2232 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2233 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) ==
2234 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2235 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) ==
2236 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2237 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) ==
2238 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2239 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) ==
2240 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2241 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) ==
2242 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2243 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) ==
2244 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2245 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) ==
2246 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2247 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) ==
2248 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2249 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) ==
2250 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2251 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) ==
2252 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2253
2254 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) ==
2255 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2256 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) ==
2257 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2258 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) ==
2259 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2260 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) ==
2261 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2262
2263 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) ==
2264 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2265 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) ==
2266 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2267 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) ==
2268 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2269 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) ==
2270 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2271 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) ==
2272 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2273 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) ==
2274 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2275 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) ==
2276 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2277 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) ==
2278 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2279 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) ==
2280 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2281 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) ==
2282 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2283 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) ==
2284 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2285 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) ==
2286 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2287
2288 auto dt = DateTime(2000, 1, 31, 9, 7, 6);
2289 (dt += dur!"seconds"(92)) -= dur!"days"(-500);
2290 assert(dt == DateTime(2001, 6, 14, 9, 8, 38));
2291
2292 auto duration = dur!"seconds"(12);
2293 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2294 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2295 static assert(!__traits(compiles, cdt += duration));
2296 static assert(!__traits(compiles, idt += duration));
2297 static assert(!__traits(compiles, cdt -= duration));
2298 static assert(!__traits(compiles, idt -= duration));
2299 }
2300
2301 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
2302 deprecated("Use Duration instead of TickDuration.")
2303 ref DateTime opOpAssign(string op)(TickDuration td) @safe pure nothrow @nogc
2304 if (op == "+" || op == "-")
2305 {
2306 DateTime retval = this;
2307 immutable seconds = td.seconds;
2308 mixin("return _addSeconds(" ~ op ~ "seconds);");
2309 }
2310
2311 deprecated @safe unittest
2312 {
2313 // This probably only runs in cases where gettimeofday() is used, but it's
2314 // hard to do this test correctly with variable ticksPerSec.
2315 if (TickDuration.ticksPerSec == 1_000_000)
2316 {
2317 {
2318 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2319 dt += TickDuration.from!"usecs"(7_000_000);
2320 assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2321 }
2322
2323 {
2324 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2325 dt += TickDuration.from!"usecs"(-7_000_000);
2326 assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2327 }
2328
2329 {
2330 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2331 dt -= TickDuration.from!"usecs"(-7_000_000);
2332 assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2333 }
2334
2335 {
2336 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2337 dt -= TickDuration.from!"usecs"(7_000_000);
2338 assert(dt == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2339 }
2340 }
2341 }
2342
2343
2344 /++
2345 Gives the difference between two $(LREF DateTime)s.
2346
2347 The legal types of arithmetic for $(LREF DateTime) using this operator are
2348
2349 $(BOOKTABLE,
2350 $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration))
2351 )
2352 +/
2353 Duration opBinary(string op)(in DateTime rhs) const @safe pure nothrow @nogc
2354 if (op == "-")
2355 {
2356 immutable dateResult = _date - rhs.date;
2357 immutable todResult = _tod - rhs._tod;
2358
2359 return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs");
2360 }
2361
2362 @safe unittest
2363 {
2364 auto dt = DateTime(1999, 7, 6, 12, 30, 33);
2365
2366 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) ==
2367 dur!"seconds"(31_536_000));
2368 assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2369 dur!"seconds"(-31_536_000));
2370
2371 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2372 dur!"seconds"(26_78_400));
2373 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) ==
2374 dur!"seconds"(-26_78_400));
2375
2376 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) ==
2377 dur!"seconds"(86_400));
2378 assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2379 dur!"seconds"(-86_400));
2380
2381 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) ==
2382 dur!"seconds"(3600));
2383 assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2384 dur!"seconds"(-3600));
2385
2386 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2387 dur!"seconds"(60));
2388 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) ==
2389 dur!"seconds"(-60));
2390
2391 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2392 dur!"seconds"(1));
2393 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) ==
2394 dur!"seconds"(-1));
2395
2396 assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033));
2397 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033));
2398 assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367));
2399 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367));
2400
2401 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2402 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2403 assert(dt - dt == Duration.zero);
2404 assert(cdt - dt == Duration.zero);
2405 assert(idt - dt == Duration.zero);
2406
2407 assert(dt - cdt == Duration.zero);
2408 assert(cdt - cdt == Duration.zero);
2409 assert(idt - cdt == Duration.zero);
2410
2411 assert(dt - idt == Duration.zero);
2412 assert(cdt - idt == Duration.zero);
2413 assert(idt - idt == Duration.zero);
2414 }
2415
2416
2417 /++
2418 Returns the difference between the two $(LREF DateTime)s in months.
2419
2420 To get the difference in years, subtract the year property
2421 of two $(LREF DateTime)s. To get the difference in days or weeks,
2422 subtract the $(LREF DateTime)s themselves and use the
2423 $(REF Duration, core,time) that results. Because converting between
2424 months and smaller units requires a specific date (which
2425 $(REF Duration, core,time)s don't have), getting the difference in
2426 months requires some math using both the year and month properties, so
2427 this is a convenience function for getting the difference in months.
2428
2429 Note that the number of days in the months or how far into the month
2430 either date is is irrelevant. It is the difference in the month property
2431 combined with the difference in years * 12. So, for instance,
2432 December 31st and January 1st are one month apart just as December 1st
2433 and January 31st are one month apart.
2434
2435 Params:
2436 rhs = The $(LREF DateTime) to subtract from this one.
2437 +/
2438 int diffMonths(in DateTime rhs) const @safe pure nothrow @nogc
2439 {
2440 return _date.diffMonths(rhs._date);
2441 }
2442
2443 ///
2444 @safe unittest
2445 {
2446 assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths(
2447 DateTime(1999, 1, 31, 23, 59, 59)) == 1);
2448
2449 assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths(
2450 DateTime(1999, 2, 1, 12, 3, 42)) == -1);
2451
2452 assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths(
2453 DateTime(1999, 1, 1, 2, 4, 7)) == 2);
2454
2455 assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths(
2456 DateTime(1999, 3, 31, 0, 30, 58)) == -2);
2457 }
2458
2459 @safe unittest
2460 {
2461 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2462 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2463 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2464 assert(dt.diffMonths(dt) == 0);
2465 assert(cdt.diffMonths(dt) == 0);
2466 assert(idt.diffMonths(dt) == 0);
2467
2468 assert(dt.diffMonths(cdt) == 0);
2469 assert(cdt.diffMonths(cdt) == 0);
2470 assert(idt.diffMonths(cdt) == 0);
2471
2472 assert(dt.diffMonths(idt) == 0);
2473 assert(cdt.diffMonths(idt) == 0);
2474 assert(idt.diffMonths(idt) == 0);
2475 }
2476
2477
2478 /++
2479 Whether this $(LREF DateTime) is in a leap year.
2480 +/
2481 @property bool isLeapYear() const @safe pure nothrow @nogc
2482 {
2483 return _date.isLeapYear;
2484 }
2485
2486 @safe unittest
2487 {
2488 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2489 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2490 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2491 assert(!dt.isLeapYear);
2492 assert(!cdt.isLeapYear);
2493 assert(!idt.isLeapYear);
2494 }
2495
2496
2497 /++
2498 Day of the week this $(LREF DateTime) is on.
2499 +/
2500 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc
2501 {
2502 return _date.dayOfWeek;
2503 }
2504
2505 @safe unittest
2506 {
2507 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2508 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2509 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2510 assert(dt.dayOfWeek == DayOfWeek.tue);
2511 assert(cdt.dayOfWeek == DayOfWeek.tue);
2512 assert(idt.dayOfWeek == DayOfWeek.tue);
2513 }
2514
2515
2516 /++
2517 Day of the year this $(LREF DateTime) is on.
2518 +/
2519 @property ushort dayOfYear() const @safe pure nothrow @nogc
2520 {
2521 return _date.dayOfYear;
2522 }
2523
2524 ///
2525 @safe unittest
2526 {
2527 assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1);
2528 assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365);
2529 assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366);
2530 }
2531
2532 @safe unittest
2533 {
2534 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2535 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2536 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2537 assert(dt.dayOfYear == 187);
2538 assert(cdt.dayOfYear == 187);
2539 assert(idt.dayOfYear == 187);
2540 }
2541
2542
2543 /++
2544 Day of the year.
2545
2546 Params:
2547 day = The day of the year to set which day of the year this
2548 $(LREF DateTime) is on.
2549 +/
2550 @property void dayOfYear(int day) @safe pure
2551 {
2552 _date.dayOfYear = day;
2553 }
2554
2555 @safe unittest
2556 {
2557 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2558 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2559 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2560 dt.dayOfYear = 12;
2561 assert(dt.dayOfYear == 12);
2562 static assert(!__traits(compiles, cdt.dayOfYear = 12));
2563 static assert(!__traits(compiles, idt.dayOfYear = 12));
2564 }
2565
2566
2567 /++
2568 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on.
2569 +/
2570 @property int dayOfGregorianCal() const @safe pure nothrow @nogc
2571 {
2572 return _date.dayOfGregorianCal;
2573 }
2574
2575 ///
2576 @safe unittest
2577 {
2578 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1);
2579 assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365);
2580 assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366);
2581
2582 assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0);
2583 assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365);
2584 assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366);
2585
2586 assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120);
2587 assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137);
2588 }
2589
2590 @safe unittest
2591 {
2592 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2593 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2594 assert(cdt.dayOfGregorianCal == 729_941);
2595 assert(idt.dayOfGregorianCal == 729_941);
2596 }
2597
2598
2599 /++
2600 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on.
2601 Setting this property does not affect the time portion of
2602 $(LREF DateTime).
2603
2604 Params:
2605 days = The day of the Gregorian Calendar to set this $(LREF DateTime)
2606 to.
2607 +/
2608 @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc
2609 {
2610 _date.dayOfGregorianCal = days;
2611 }
2612
2613 ///
2614 @safe unittest
2615 {
2616 auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0));
2617 dt.dayOfGregorianCal = 1;
2618 assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)));
2619
2620 dt.dayOfGregorianCal = 365;
2621 assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0)));
2622
2623 dt.dayOfGregorianCal = 366;
2624 assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0)));
2625
2626 dt.dayOfGregorianCal = 0;
2627 assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)));
2628
2629 dt.dayOfGregorianCal = -365;
2630 assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0)));
2631
2632 dt.dayOfGregorianCal = -366;
2633 assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0)));
2634
2635 dt.dayOfGregorianCal = 730_120;
2636 assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0)));
2637
2638 dt.dayOfGregorianCal = 734_137;
2639 assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0)));
2640 }
2641
2642 @safe unittest
2643 {
2644 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2645 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2646 static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7));
2647 static assert(!__traits(compiles, idt.dayOfGregorianCal = 7));
2648 }
2649
2650
2651 /++
2652 The ISO 8601 week of the year that this $(LREF DateTime) is in.
2653
2654 See_Also:
2655 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
2656 +/
2657 @property ubyte isoWeek() const @safe pure nothrow
2658 {
2659 return _date.isoWeek;
2660 }
2661
2662 @safe unittest
2663 {
2664 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2665 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2666 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2667 assert(dt.isoWeek == 27);
2668 assert(cdt.isoWeek == 27);
2669 assert(idt.isoWeek == 27);
2670 }
2671
2672
2673 /++
2674 $(LREF DateTime) for the last day in the month that this
2675 $(LREF DateTime) is in. The time portion of endOfMonth is always
2676 23:59:59.
2677 +/
2678 @property DateTime endOfMonth() const @safe pure nothrow
2679 {
2680 try
2681 return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59));
2682 catch (Exception e)
2683 assert(0, "DateTime constructor threw.");
2684 }
2685
2686 ///
2687 @safe unittest
2688 {
2689 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth ==
2690 DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59)));
2691
2692 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth ==
2693 DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59)));
2694
2695 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth ==
2696 DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59)));
2697
2698 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth ==
2699 DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59)));
2700 }
2701
2702 @safe unittest
2703 {
2704 // Test A.D.
2705 assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59));
2706 assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59));
2707 assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59));
2708 assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59));
2709 assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59));
2710 assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59));
2711 assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59));
2712 assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2713 assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59));
2714 assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59));
2715 assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59));
2716 assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59));
2717 assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59));
2718
2719 // Test B.C.
2720 assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59));
2721 assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59));
2722 assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59));
2723 assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59));
2724 assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59));
2725 assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59));
2726 assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59));
2727 assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59));
2728 assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59));
2729 assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59));
2730 assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59));
2731 assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59));
2732 assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59));
2733
2734 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2735 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2736 assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2737 assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2738 }
2739
2740
2741 /++
2742 The last day in the month that this $(LREF DateTime) is in.
2743 +/
2744 @property ubyte daysInMonth() const @safe pure nothrow @nogc
2745 {
2746 return _date.daysInMonth;
2747 }
2748
2749 ///
2750 @safe unittest
2751 {
2752 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31);
2753 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28);
2754 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29);
2755 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30);
2756 }
2757
2758 @safe unittest
2759 {
2760 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2761 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2762 assert(cdt.daysInMonth == 31);
2763 assert(idt.daysInMonth == 31);
2764 }
2765
2766
2767 /++
2768 Whether the current year is a date in A.D.
2769 +/
2770 @property bool isAD() const @safe pure nothrow @nogc
2771 {
2772 return _date.isAD;
2773 }
2774
2775 ///
2776 @safe unittest
2777 {
2778 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD);
2779 assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD);
2780 assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD);
2781 assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD);
2782 }
2783
2784 @safe unittest
2785 {
2786 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2787 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2788 assert(cdt.isAD);
2789 assert(idt.isAD);
2790 }
2791
2792
2793 /++
2794 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this
2795 $(LREF DateTime) at the given time. For example, prior to noon,
2796 1996-03-31 would be the Julian day number 2_450_173, so this function
2797 returns 2_450_173, while from noon onward, the julian day number would
2798 be 2_450_174, so this function returns 2_450_174.
2799 +/
2800 @property long julianDay() const @safe pure nothrow @nogc
2801 {
2802 if (_tod._hour < 12)
2803 return _date.julianDay - 1;
2804 else
2805 return _date.julianDay;
2806 }
2807
2808 @safe unittest
2809 {
2810 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1);
2811 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0);
2812
2813 assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424);
2814 assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425);
2815
2816 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425);
2817 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426);
2818
2819 assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160);
2820 assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161);
2821
2822 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000);
2823 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001);
2824
2825 assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973);
2826 assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974);
2827
2828 assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173);
2829 assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174);
2830
2831 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432);
2832 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433);
2833
2834 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2835 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2836 assert(cdt.julianDay == 2_451_366);
2837 assert(idt.julianDay == 2_451_366);
2838 }
2839
2840
2841 /++
2842 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any
2843 time on this date (since, the modified Julian day changes at midnight).
2844 +/
2845 @property long modJulianDay() const @safe pure nothrow @nogc
2846 {
2847 return _date.modJulianDay;
2848 }
2849
2850 @safe unittest
2851 {
2852 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0);
2853 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0);
2854
2855 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432);
2856 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432);
2857
2858 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2859 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2860 assert(cdt.modJulianDay == 51_365);
2861 assert(idt.modJulianDay == 51_365);
2862 }
2863
2864
2865 /++
2866 Converts this $(LREF DateTime) to a string with the format YYYYMMDDTHHMMSS.
2867 +/
2868 string toISOString() const @safe pure nothrow
2869 {
2870 import std.format : format;
2871 try
2872 {
2873 return format!("%sT%02d%02d%02d")(
2874 _date.toISOString(),
2875 _tod._hour,
2876 _tod._minute,
2877 _tod._second
2878 );
2879 }
2880 catch (Exception e)
2881 {
2882 assert(0, "format() threw.");
2883 }
2884 }
2885
2886 ///
2887 @safe unittest
2888 {
2889 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() ==
2890 "20100704T070612");
2891
2892 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() ==
2893 "19981225T021500");
2894
2895 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() ==
2896 "00000105T230959");
2897
2898 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() ==
2899 "-00040105T000002");
2900 }
2901
2902 @safe unittest
2903 {
2904 // Test A.D.
2905 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000");
2906 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612");
2907 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459");
2908 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959");
2909 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101");
2910
2911 // Test B.C.
2912 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204");
2913 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000");
2914 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612");
2915 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459");
2916 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959");
2917 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101");
2918
2919 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2920 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2921 assert(cdt.toISOString() == "19990706T123033");
2922 assert(idt.toISOString() == "19990706T123033");
2923 }
2924
2925
2926 /++
2927 Converts this $(LREF DateTime) to a string with the format
2928 YYYY-MM-DDTHH:MM:SS.
2929 +/
2930 string toISOExtString() const @safe pure nothrow
2931 {
2932 import std.format : format;
2933 try
2934 {
2935 return format!("%sT%02d:%02d:%02d")(
2936 _date.toISOExtString(),
2937 _tod._hour,
2938 _tod._minute,
2939 _tod._second
2940 );
2941 }
2942 catch (Exception e)
2943 {
2944 assert(0, "format() threw.");
2945 }
2946 }
2947
2948 ///
2949 @safe unittest
2950 {
2951 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() ==
2952 "2010-07-04T07:06:12");
2953
2954 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() ==
2955 "1998-12-25T02:15:00");
2956
2957 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() ==
2958 "0000-01-05T23:09:59");
2959
2960 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() ==
2961 "-0004-01-05T00:00:02");
2962 }
2963
2964 @safe unittest
2965 {
2966 // Test A.D.
2967 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
2968 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
2969 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
2970 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
2971 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
2972
2973 // Test B.C.
2974 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
2975 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
2976 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
2977 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
2978 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
2979 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
2980
2981 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2982 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2983 assert(cdt.toISOExtString() == "1999-07-06T12:30:33");
2984 assert(idt.toISOExtString() == "1999-07-06T12:30:33");
2985 }
2986
2987 /++
2988 Converts this $(LREF DateTime) to a string with the format
2989 YYYY-Mon-DD HH:MM:SS.
2990 +/
2991 string toSimpleString() const @safe pure nothrow
2992 {
2993 import std.format : format;
2994 try
2995 {
2996 return format!("%s %02d:%02d:%02d")(
2997 _date.toSimpleString(),
2998 _tod._hour,
2999 _tod._minute,
3000 _tod._second
3001 );
3002 }
3003 catch (Exception e)
3004 {
3005 assert(0, "format() threw.");
3006 }
3007 }
3008
3009 ///
3010 @safe unittest
3011 {
3012 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() ==
3013 "2010-Jul-04 07:06:12");
3014
3015 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() ==
3016 "1998-Dec-25 02:15:00");
3017
3018 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() ==
3019 "0000-Jan-05 23:09:59");
3020
3021 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() ==
3022 "-0004-Jan-05 00:00:02");
3023 }
3024
3025 @safe unittest
3026 {
3027 // Test A.D.
3028 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
3029 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
3030 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
3031 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
3032 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
3033
3034 // Test B.C.
3035 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
3036 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
3037 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
3038 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
3039 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
3040 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
3041
3042 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
3043 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
3044 assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33");
3045 assert(idt.toSimpleString() == "1999-Jul-06 12:30:33");
3046 }
3047
3048
3049 /++
3050 Converts this $(LREF DateTime) to a string.
3051
3052 This function exists to make it easy to convert a $(LREF DateTime) to a
3053 string for code that does not care what the exact format is - just that
3054 it presents the information in a clear manner. It also makes it easy to
3055 simply convert a $(LREF DateTime) to a string when using functions such
3056 as `to!string`, `format`, or `writeln` which use toString to convert
3057 user-defined types. So, it is unlikely that much code will call
3058 toString directly.
3059
3060 The format of the string is purposefully unspecified, and code that
3061 cares about the format of the string should use `toISOString`,
3062 `toISOExtString`, `toSimpleString`, or some other custom formatting
3063 function that explicitly generates the format that the code needs. The
3064 reason is that the code is then clear about what format it's using,
3065 making it less error-prone to maintain the code and interact with other
3066 software that consumes the generated strings. It's for this same reason
3067 that $(LREF DateTime) has no `fromString` function, whereas it does have
3068 `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
3069
3070 The format returned by toString may or may not change in the future.
3071 +/
3072 string toString() const @safe pure nothrow
3073 {
3074 return toSimpleString();
3075 }
3076
3077 @safe unittest
3078 {
3079 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3080 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3081 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3082 assert(dt.toString());
3083 assert(cdt.toString());
3084 assert(idt.toString());
3085 }
3086
3087
3088
3089 /++
3090 Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS.
3091 Whitespace is stripped from the given string.
3092
3093 Params:
3094 isoString = A string formatted in the ISO format for dates and times.
3095
3096 Throws:
3097 $(REF DateTimeException,std,datetime,date) if the given string is
3098 not in the ISO format or if the resulting $(LREF DateTime) would not
3099 be valid.
3100 +/
3101 static DateTime fromISOString(S)(in S isoString) @safe pure
3102 if (isSomeString!S)
3103 {
3104 import std.algorithm.searching : countUntil;
3105 import std.exception : enforce;
3106 import std.format : format;
3107 import std.string : strip;
3108
3109 auto str = strip(isoString);
3110
3111 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString)));
3112 auto t = str.countUntil('T');
3113
3114 enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString)));
3115
3116 immutable date = Date.fromISOString(str[0 .. t]);
3117 immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]);
3118
3119 return DateTime(date, tod);
3120 }
3121
3122 ///
3123 @safe unittest
3124 {
3125 assert(DateTime.fromISOString("20100704T070612") ==
3126 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3127
3128 assert(DateTime.fromISOString("19981225T021500") ==
3129 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3130
3131 assert(DateTime.fromISOString("00000105T230959") ==
3132 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3133
3134 assert(DateTime.fromISOString("-00040105T000002") ==
3135 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3136
3137 assert(DateTime.fromISOString(" 20100704T070612 ") ==
3138 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3139 }
3140
3141 @safe unittest
3142 {
3143 assertThrown!DateTimeException(DateTime.fromISOString(""));
3144 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
3145 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
3146 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
3147 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
3148 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
3149
3150 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
3151 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
3152 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
3153 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
3154 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
3155
3156 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
3157 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
3158 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
3159 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
3160 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
3161 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
3162
3163 assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201"));
3164 assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01"));
3165
3166 assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3167 assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3168 assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3169 assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3170 assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3171 assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3172 assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3173 }
3174
3175 // bug# 17801
3176 @safe unittest
3177 {
3178 import std.conv : to;
3179 import std.meta : AliasSeq;
3180 foreach (C; AliasSeq!(char, wchar, dchar))
3181 {
3182 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3183 assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16));
3184 }
3185 }
3186
3187
3188 /++
3189 Creates a $(LREF DateTime) from a string with the format
3190 YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string.
3191
3192 Params:
3193 isoExtString = A string formatted in the ISO Extended format for dates
3194 and times.
3195
3196 Throws:
3197 $(REF DateTimeException,std,datetime,date) if the given string is
3198 not in the ISO Extended format or if the resulting $(LREF DateTime)
3199 would not be valid.
3200 +/
3201 static DateTime fromISOExtString(S)(in S isoExtString) @safe pure
3202 if (isSomeString!(S))
3203 {
3204 import std.algorithm.searching : countUntil;
3205 import std.exception : enforce;
3206 import std.format : format;
3207 import std.string : strip;
3208
3209 auto str = strip(isoExtString);
3210
3211 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
3212 auto t = str.countUntil('T');
3213
3214 enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
3215
3216 immutable date = Date.fromISOExtString(str[0 .. t]);
3217 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
3218
3219 return DateTime(date, tod);
3220 }
3221
3222 ///
3223 @safe unittest
3224 {
3225 assert(DateTime.fromISOExtString("2010-07-04T07:06:12") ==
3226 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3227
3228 assert(DateTime.fromISOExtString("1998-12-25T02:15:00") ==
3229 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3230
3231 assert(DateTime.fromISOExtString("0000-01-05T23:09:59") ==
3232 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3233
3234 assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") ==
3235 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3236
3237 assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
3238 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3239 }
3240
3241 @safe unittest
3242 {
3243 assertThrown!DateTimeException(DateTime.fromISOExtString(""));
3244 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000"));
3245 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000"));
3246 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000"));
3247 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000."));
3248 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0"));
3249
3250 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00"));
3251 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
3252 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
3253 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00"));
3254 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00."));
3255 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0"));
3256
3257 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00"));
3258 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00"));
3259 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00."));
3260 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0"));
3261
3262 assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201"));
3263 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01"));
3264
3265 assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3266 assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3267 assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3268 assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3269 assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3270 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3271 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3272 }
3273
3274 // bug# 17801
3275 @safe unittest
3276 {
3277 import std.conv : to;
3278 import std.meta : AliasSeq;
3279 foreach (C; AliasSeq!(char, wchar, dchar))
3280 {
3281 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3282 assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
3283 }
3284 }
3285
3286
3287 /++
3288 Creates a $(LREF DateTime) from a string with the format
3289 YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string.
3290
3291 Params:
3292 simpleString = A string formatted in the way that toSimpleString
3293 formats dates and times.
3294
3295 Throws:
3296 $(REF DateTimeException,std,datetime,date) if the given string is
3297 not in the correct format or if the resulting $(LREF DateTime)
3298 would not be valid.
3299 +/
3300 static DateTime fromSimpleString(S)(in S simpleString) @safe pure
3301 if (isSomeString!(S))
3302 {
3303 import std.algorithm.searching : countUntil;
3304 import std.exception : enforce;
3305 import std.format : format;
3306 import std.string : strip;
3307
3308 auto str = strip(simpleString);
3309
3310 enforce(str.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString)));
3311 auto t = str.countUntil(' ');
3312
3313 enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString)));
3314
3315 immutable date = Date.fromSimpleString(str[0 .. t]);
3316 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
3317
3318 return DateTime(date, tod);
3319 }
3320
3321 ///
3322 @safe unittest
3323 {
3324 assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") ==
3325 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3326 assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") ==
3327 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3328 assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") ==
3329 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3330 assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
3331 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3332 assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
3333 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3334 }
3335
3336 @safe unittest
3337 {
3338 assertThrown!DateTimeException(DateTime.fromISOString(""));
3339 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
3340 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
3341 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
3342 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
3343 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
3344
3345 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
3346 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
3347 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
3348 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
3349 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
3350
3351 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
3352 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
3353 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
3354 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
3355 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
3356 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
3357
3358 assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201"));
3359 assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201"));
3360
3361 assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") ==
3362 DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3363 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") ==
3364 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3365 assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") ==
3366 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3367 assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") ==
3368 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3369 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") ==
3370 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3371 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") ==
3372 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3373 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") ==
3374 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3375 }
3376
3377 // bug# 17801
3378 @safe unittest
3379 {
3380 import std.conv : to;
3381 import std.meta : AliasSeq;
3382 foreach (C; AliasSeq!(char, wchar, dchar))
3383 {
3384 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3385 assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
3386 }
3387 }
3388
3389
3390 /++
3391 Returns the $(LREF DateTime) farthest in the past which is representable
3392 by $(LREF DateTime).
3393 +/
3394 @property static DateTime min() @safe pure nothrow @nogc
3395 out(result)
3396 {
3397 assert(result._date == Date.min);
3398 assert(result._tod == TimeOfDay.min);
3399 }
3400 body
3401 {
3402 auto dt = DateTime.init;
3403 dt._date._year = short.min;
3404 dt._date._month = Month.jan;
3405 dt._date._day = 1;
3406
3407 return dt;
3408 }
3409
3410 @safe unittest
3411 {
3412 assert(DateTime.min.year < 0);
3413 assert(DateTime.min < DateTime.max);
3414 }
3415
3416
3417 /++
3418 Returns the $(LREF DateTime) farthest in the future which is
3419 representable by $(LREF DateTime).
3420 +/
3421 @property static DateTime max() @safe pure nothrow @nogc
3422 out(result)
3423 {
3424 assert(result._date == Date.max);
3425 assert(result._tod == TimeOfDay.max);
3426 }
3427 body
3428 {
3429 auto dt = DateTime.init;
3430 dt._date._year = short.max;
3431 dt._date._month = Month.dec;
3432 dt._date._day = 31;
3433 dt._tod._hour = TimeOfDay.maxHour;
3434 dt._tod._minute = TimeOfDay.maxMinute;
3435 dt._tod._second = TimeOfDay.maxSecond;
3436
3437 return dt;
3438 }
3439
3440 @safe unittest
3441 {
3442 assert(DateTime.max.year > 0);
3443 assert(DateTime.max > DateTime.min);
3444 }
3445
3446
3447 private:
3448
3449 /+
3450 Add seconds to the time of day. Negative values will subtract. If the
3451 number of seconds overflows (or underflows), then the seconds will wrap,
3452 increasing (or decreasing) the number of minutes accordingly. The
3453 same goes for any larger units.
3454
3455 Params:
3456 seconds = The number of seconds to add to this $(LREF DateTime).
3457 +/
3458 ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc
3459 {
3460 long hnsecs = convert!("seconds", "hnsecs")(seconds);
3461 hnsecs += convert!("hours", "hnsecs")(_tod._hour);
3462 hnsecs += convert!("minutes", "hnsecs")(_tod._minute);
3463 hnsecs += convert!("seconds", "hnsecs")(_tod._second);
3464
3465 auto days = splitUnitsFromHNSecs!"days"(hnsecs);
3466
3467 if (hnsecs < 0)
3468 {
3469 hnsecs += convert!("days", "hnsecs")(1);
3470 --days;
3471 }
3472
3473 _date._addDays(days);
3474
3475 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
3476 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
3477 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
3478
3479 _tod._hour = cast(ubyte) newHours;
3480 _tod._minute = cast(ubyte) newMinutes;
3481 _tod._second = cast(ubyte) newSeconds;
3482
3483 return this;
3484 }
3485
3486 @safe unittest
3487 {
3488 static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__)
3489 {
3490 orig._addSeconds(seconds);
3491 assert(orig == expected);
3492 }
3493
3494 // Test A.D.
3495 testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33));
3496 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34));
3497 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35));
3498 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36));
3499 testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37));
3500 testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38));
3501 testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43));
3502 testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48));
3503 testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59));
3504 testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0));
3505 testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3));
3506 testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32));
3507 testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33));
3508 testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34));
3509
3510 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59));
3511 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0));
3512 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1));
3513 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0));
3514 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32));
3515 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33));
3516 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34));
3517 testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33));
3518 testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3));
3519
3520 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32));
3521 testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31));
3522 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30));
3523 testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29));
3524 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28));
3525 testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23));
3526 testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18));
3527 testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0));
3528 testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59));
3529 testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58));
3530 testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34));
3531 testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33));
3532 testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32));
3533
3534 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0));
3535 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59));
3536 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33));
3537 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32));
3538 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59));
3539 testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57));
3540
3541 testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1));
3542 testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0));
3543 testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59));
3544
3545 testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1));
3546 testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0));
3547 testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59));
3548
3549 testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1));
3550 testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0));
3551 testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59));
3552
3553 testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0));
3554 testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59));
3555 testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58));
3556
3557 testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0));
3558 testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59));
3559 testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58));
3560
3561 testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1));
3562 testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0));
3563 testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59));
3564
3565 // Test B.C.
3566 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33));
3567 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34));
3568 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35));
3569 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36));
3570 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37));
3571 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38));
3572 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43));
3573 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48));
3574 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59));
3575 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0));
3576 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3));
3577 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32));
3578 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33));
3579 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34));
3580
3581 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59));
3582 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0));
3583 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1));
3584 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0));
3585 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32));
3586 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33));
3587 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34));
3588 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33));
3589 testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3));
3590
3591 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32));
3592 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31));
3593 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30));
3594 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29));
3595 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28));
3596 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23));
3597 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18));
3598 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0));
3599 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59));
3600 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58));
3601 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34));
3602 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33));
3603 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32));
3604
3605 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0));
3606 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59));
3607 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33));
3608 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32));
3609 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59));
3610 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33));
3611 testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57));
3612
3613 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1));
3614 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0));
3615 testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59));
3616
3617 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1));
3618 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0));
3619 testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59));
3620
3621 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1));
3622 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0));
3623 testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59));
3624
3625 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0));
3626 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59));
3627 testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58));
3628
3629 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0));
3630 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59));
3631 testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58));
3632
3633 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1));
3634 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0));
3635 testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59));
3636
3637 // Test Both
3638 testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59));
3639 testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0));
3640
3641 testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59));
3642 testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0));
3643
3644 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33));
3645 testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33));
3646
3647 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50));
3648 testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33));
3649
3650 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
3651 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
3652 static assert(!__traits(compiles, cdt._addSeconds(4)));
3653 static assert(!__traits(compiles, idt._addSeconds(4)));
3654 }
3655
3656
3657 Date _date;
3658 TimeOfDay _tod;
3659 }
3660
3661
3662 /++
3663 Represents a date in the
3664 $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic
3665 Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years
3666 are A.D. Non-positive years are B.C.
3667
3668 Year, month, and day are kept separately internally so that $(D Date) is
3669 optimized for calendar-based operations.
3670
3671 $(D Date) uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
3672 leap year calculations for its entire length. As per
3673 $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as
3674 year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C.
3675 as a positive integer with 1 B.C. being the year prior to 1 A.D.
3676
3677 Year 0 is a leap year.
3678 +/
3679 struct Date
3680 {
3681 public:
3682
3683 /++
3684 Throws:
3685 $(REF DateTimeException,std,datetime,date) if the resulting
3686 $(LREF Date) would not be valid.
3687
3688 Params:
3689 year = Year of the Gregorian Calendar. Positive values are A.D.
3690 Non-positive values are B.C. with year 0 being the year
3691 prior to 1 A.D.
3692 month = Month of the year (January is 1).
3693 day = Day of the month.
3694 +/
3695 this(int year, int month, int day) @safe pure
3696 {
3697 enforceValid!"months"(cast(Month) month);
3698 enforceValid!"days"(year, cast(Month) month, day);
3699
3700 _year = cast(short) year;
3701 _month = cast(Month) month;
3702 _day = cast(ubyte) day;
3703 }
3704
3705 @safe unittest
3706 {
3707 import std.exception : assertNotThrown;
3708 assert(Date(1, 1, 1) == Date.init);
3709
3710 static void testDate(in Date date, int year, int month, int day)
3711 {
3712 assert(date._year == year);
3713 assert(date._month == month);
3714 assert(date._day == day);
3715 }
3716
3717 testDate(Date(1999, 1 , 1), 1999, Month.jan, 1);
3718 testDate(Date(1999, 7 , 1), 1999, Month.jul, 1);
3719 testDate(Date(1999, 7 , 6), 1999, Month.jul, 6);
3720
3721 // Test A.D.
3722 assertThrown!DateTimeException(Date(1, 0, 1));
3723 assertThrown!DateTimeException(Date(1, 1, 0));
3724 assertThrown!DateTimeException(Date(1999, 13, 1));
3725 assertThrown!DateTimeException(Date(1999, 1, 32));
3726 assertThrown!DateTimeException(Date(1999, 2, 29));
3727 assertThrown!DateTimeException(Date(2000, 2, 30));
3728 assertThrown!DateTimeException(Date(1999, 3, 32));
3729 assertThrown!DateTimeException(Date(1999, 4, 31));
3730 assertThrown!DateTimeException(Date(1999, 5, 32));
3731 assertThrown!DateTimeException(Date(1999, 6, 31));
3732 assertThrown!DateTimeException(Date(1999, 7, 32));
3733 assertThrown!DateTimeException(Date(1999, 8, 32));
3734 assertThrown!DateTimeException(Date(1999, 9, 31));
3735 assertThrown!DateTimeException(Date(1999, 10, 32));
3736 assertThrown!DateTimeException(Date(1999, 11, 31));
3737 assertThrown!DateTimeException(Date(1999, 12, 32));
3738
3739 assertNotThrown!DateTimeException(Date(1999, 1, 31));
3740 assertNotThrown!DateTimeException(Date(1999, 2, 28));
3741 assertNotThrown!DateTimeException(Date(2000, 2, 29));
3742 assertNotThrown!DateTimeException(Date(1999, 3, 31));
3743 assertNotThrown!DateTimeException(Date(1999, 4, 30));
3744 assertNotThrown!DateTimeException(Date(1999, 5, 31));
3745 assertNotThrown!DateTimeException(Date(1999, 6, 30));
3746 assertNotThrown!DateTimeException(Date(1999, 7, 31));
3747 assertNotThrown!DateTimeException(Date(1999, 8, 31));
3748 assertNotThrown!DateTimeException(Date(1999, 9, 30));
3749 assertNotThrown!DateTimeException(Date(1999, 10, 31));
3750 assertNotThrown!DateTimeException(Date(1999, 11, 30));
3751 assertNotThrown!DateTimeException(Date(1999, 12, 31));
3752
3753 // Test B.C.
3754 assertNotThrown!DateTimeException(Date(0, 1, 1));
3755 assertNotThrown!DateTimeException(Date(-1, 1, 1));
3756 assertNotThrown!DateTimeException(Date(-1, 12, 31));
3757 assertNotThrown!DateTimeException(Date(-1, 2, 28));
3758 assertNotThrown!DateTimeException(Date(-4, 2, 29));
3759
3760 assertThrown!DateTimeException(Date(-1, 2, 29));
3761 assertThrown!DateTimeException(Date(-2, 2, 29));
3762 assertThrown!DateTimeException(Date(-3, 2, 29));
3763 }
3764
3765
3766 /++
3767 Params:
3768 day = The Xth day of the Gregorian Calendar that the constructed
3769 $(LREF Date) will be for.
3770 +/
3771 this(int day) @safe pure nothrow @nogc
3772 {
3773 if (day > 0)
3774 {
3775 int years = (day / daysIn400Years) * 400 + 1;
3776 day %= daysIn400Years;
3777
3778 {
3779 immutable tempYears = day / daysIn100Years;
3780
3781 if (tempYears == 4)
3782 {
3783 years += 300;
3784 day -= daysIn100Years * 3;
3785 }
3786 else
3787 {
3788 years += tempYears * 100;
3789 day %= daysIn100Years;
3790 }
3791 }
3792
3793 years += (day / daysIn4Years) * 4;
3794 day %= daysIn4Years;
3795
3796 {
3797 immutable tempYears = day / daysInYear;
3798
3799 if (tempYears == 4)
3800 {
3801 years += 3;
3802 day -= daysInYear * 3;
3803 }
3804 else
3805 {
3806 years += tempYears;
3807 day %= daysInYear;
3808 }
3809 }
3810
3811 if (day == 0)
3812 {
3813 _year = cast(short)(years - 1);
3814 _month = Month.dec;
3815 _day = 31;
3816 }
3817 else
3818 {
3819 _year = cast(short) years;
3820
3821 setDayOfYear(day);
3822 }
3823 }
3824 else if (day <= 0 && -day < daysInLeapYear)
3825 {
3826 _year = 0;
3827
3828 setDayOfYear(daysInLeapYear + day);
3829 }
3830 else
3831 {
3832 day += daysInLeapYear - 1;
3833 int years = (day / daysIn400Years) * 400 - 1;
3834 day %= daysIn400Years;
3835
3836 {
3837 immutable tempYears = day / daysIn100Years;
3838
3839 if (tempYears == -4)
3840 {
3841 years -= 300;
3842 day += daysIn100Years * 3;
3843 }
3844 else
3845 {
3846 years += tempYears * 100;
3847 day %= daysIn100Years;
3848 }
3849 }
3850
3851 years += (day / daysIn4Years) * 4;
3852 day %= daysIn4Years;
3853
3854 {
3855 immutable tempYears = day / daysInYear;
3856
3857 if (tempYears == -4)
3858 {
3859 years -= 3;
3860 day += daysInYear * 3;
3861 }
3862 else
3863 {
3864 years += tempYears;
3865 day %= daysInYear;
3866 }
3867 }
3868
3869 if (day == 0)
3870 {
3871 _year = cast(short)(years + 1);
3872 _month = Month.jan;
3873 _day = 1;
3874 }
3875 else
3876 {
3877 _year = cast(short) years;
3878 immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1;
3879
3880 setDayOfYear(newDoY);
3881 }
3882 }
3883 }
3884
3885 @safe unittest
3886 {
3887 import std.range : chain;
3888
3889 // Test A.D.
3890 foreach (gd; chain(testGregDaysBC, testGregDaysAD))
3891 assert(Date(gd.day) == gd.date);
3892 }
3893
3894
3895 /++
3896 Compares this $(LREF Date) with the given $(LREF Date).
3897
3898 Returns:
3899 $(BOOKTABLE,
3900 $(TR $(TD this &lt; rhs) $(TD &lt; 0))
3901 $(TR $(TD this == rhs) $(TD 0))
3902 $(TR $(TD this &gt; rhs) $(TD &gt; 0))
3903 )
3904 +/
3905 int opCmp(in Date rhs) const @safe pure nothrow @nogc
3906 {
3907 if (_year < rhs._year)
3908 return -1;
3909 if (_year > rhs._year)
3910 return 1;
3911
3912 if (_month < rhs._month)
3913 return -1;
3914 if (_month > rhs._month)
3915 return 1;
3916
3917 if (_day < rhs._day)
3918 return -1;
3919 if (_day > rhs._day)
3920 return 1;
3921
3922 return 0;
3923 }
3924
3925 @safe unittest
3926 {
3927 // Test A.D.
3928 assert(Date(1, 1, 1).opCmp(Date.init) == 0);
3929
3930 assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0);
3931 assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0);
3932 assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0);
3933
3934 assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0);
3935 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0);
3936
3937 assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0);
3938
3939 assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0);
3940 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0);
3941 assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0);
3942 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0);
3943 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0);
3944 assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0);
3945
3946 assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0);
3947 assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
3948 assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0);
3949 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0);
3950 assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0);
3951 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
3952
3953 // Test B.C.
3954 assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0);
3955 assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0);
3956 assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0);
3957 assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0);
3958
3959 assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0);
3960 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0);
3961
3962 assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0);
3963
3964 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0);
3965 assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0);
3966 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0);
3967 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0);
3968 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
3969 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0);
3970
3971 assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0);
3972 assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0);
3973 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
3974 assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0);
3975 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0);
3976 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0);
3977
3978 // Test Both
3979 assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0);
3980 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0);
3981
3982 assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0);
3983 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0);
3984
3985 assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0);
3986 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0);
3987
3988 assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0);
3989 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0);
3990
3991 assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0);
3992 assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0);
3993
3994 auto date = Date(1999, 7, 6);
3995 const cdate = Date(1999, 7, 6);
3996 immutable idate = Date(1999, 7, 6);
3997 assert(date.opCmp(date) == 0);
3998 assert(date.opCmp(cdate) == 0);
3999 assert(date.opCmp(idate) == 0);
4000 assert(cdate.opCmp(date) == 0);
4001 assert(cdate.opCmp(cdate) == 0);
4002 assert(cdate.opCmp(idate) == 0);
4003 assert(idate.opCmp(date) == 0);
4004 assert(idate.opCmp(cdate) == 0);
4005 assert(idate.opCmp(idate) == 0);
4006 }
4007
4008
4009 /++
4010 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
4011 are B.C.
4012 +/
4013 @property short year() const @safe pure nothrow @nogc
4014 {
4015 return _year;
4016 }
4017
4018 ///
4019 @safe unittest
4020 {
4021 assert(Date(1999, 7, 6).year == 1999);
4022 assert(Date(2010, 10, 4).year == 2010);
4023 assert(Date(-7, 4, 5).year == -7);
4024 }
4025
4026 @safe unittest
4027 {
4028 assert(Date.init.year == 1);
4029 assert(Date(1999, 7, 6).year == 1999);
4030 assert(Date(-1999, 7, 6).year == -1999);
4031
4032 const cdate = Date(1999, 7, 6);
4033 immutable idate = Date(1999, 7, 6);
4034 assert(cdate.year == 1999);
4035 assert(idate.year == 1999);
4036 }
4037
4038 /++
4039 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
4040 are B.C.
4041
4042 Params:
4043 year = The year to set this Date's year to.
4044
4045 Throws:
4046 $(REF DateTimeException,std,datetime,date) if the new year is not
4047 a leap year and the resulting date would be on February 29th.
4048 +/
4049 @property void year(int year) @safe pure
4050 {
4051 enforceValid!"days"(year, _month, _day);
4052 _year = cast(short) year;
4053 }
4054
4055 ///
4056 @safe unittest
4057 {
4058 assert(Date(1999, 7, 6).year == 1999);
4059 assert(Date(2010, 10, 4).year == 2010);
4060 assert(Date(-7, 4, 5).year == -7);
4061 }
4062
4063 @safe unittest
4064 {
4065 static void testDateInvalid(Date date, int year)
4066 {
4067 date.year = year;
4068 }
4069
4070 static void testDate(Date date, int year, in Date expected)
4071 {
4072 date.year = year;
4073 assert(date == expected);
4074 }
4075
4076 assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1));
4077
4078 testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1));
4079 testDate(Date(1, 1, 1), 0, Date(0, 1, 1));
4080 testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1));
4081
4082 const cdate = Date(1999, 7, 6);
4083 immutable idate = Date(1999, 7, 6);
4084 static assert(!__traits(compiles, cdate.year = 1999));
4085 static assert(!__traits(compiles, idate.year = 1999));
4086 }
4087
4088
4089 /++
4090 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
4091
4092 Throws:
4093 $(REF DateTimeException,std,datetime,date) if $(D isAD) is true.
4094 +/
4095 @property ushort yearBC() const @safe pure
4096 {
4097 import std.format : format;
4098
4099 if (isAD)
4100 throw new DateTimeException(format("Year %s is A.D.", _year));
4101 return cast(ushort)((_year * -1) + 1);
4102 }
4103
4104 ///
4105 @safe unittest
4106 {
4107 assert(Date(0, 1, 1).yearBC == 1);
4108 assert(Date(-1, 1, 1).yearBC == 2);
4109 assert(Date(-100, 1, 1).yearBC == 101);
4110 }
4111
4112 @safe unittest
4113 {
4114 assertThrown!DateTimeException((in Date date){date.yearBC;}(Date(1, 1, 1)));
4115
4116 auto date = Date(0, 7, 6);
4117 const cdate = Date(0, 7, 6);
4118 immutable idate = Date(0, 7, 6);
4119 assert(date.yearBC == 1);
4120 assert(cdate.yearBC == 1);
4121 assert(idate.yearBC == 1);
4122 }
4123
4124
4125 /++
4126 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
4127
4128 Params:
4129 year = The year B.C. to set this $(LREF Date)'s year to.
4130
4131 Throws:
4132 $(REF DateTimeException,std,datetime,date) if a non-positive value
4133 is given.
4134 +/
4135 @property void yearBC(int year) @safe pure
4136 {
4137 if (year <= 0)
4138 throw new DateTimeException("The given year is not a year B.C.");
4139 _year = cast(short)((year - 1) * -1);
4140 }
4141
4142 ///
4143 @safe unittest
4144 {
4145 auto date = Date(2010, 1, 1);
4146 date.yearBC = 1;
4147 assert(date == Date(0, 1, 1));
4148
4149 date.yearBC = 10;
4150 assert(date == Date(-9, 1, 1));
4151 }
4152
4153 @safe unittest
4154 {
4155 assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1)));
4156
4157 auto date = Date(0, 7, 6);
4158 const cdate = Date(0, 7, 6);
4159 immutable idate = Date(0, 7, 6);
4160 date.yearBC = 7;
4161 assert(date.yearBC == 7);
4162 static assert(!__traits(compiles, cdate.yearBC = 7));
4163 static assert(!__traits(compiles, idate.yearBC = 7));
4164 }
4165
4166
4167 /++
4168 Month of a Gregorian Year.
4169 +/
4170 @property Month month() const @safe pure nothrow @nogc
4171 {
4172 return _month;
4173 }
4174
4175 ///
4176 @safe unittest
4177 {
4178 assert(Date(1999, 7, 6).month == 7);
4179 assert(Date(2010, 10, 4).month == 10);
4180 assert(Date(-7, 4, 5).month == 4);
4181 }
4182
4183 @safe unittest
4184 {
4185 assert(Date.init.month == 1);
4186 assert(Date(1999, 7, 6).month == 7);
4187 assert(Date(-1999, 7, 6).month == 7);
4188
4189 const cdate = Date(1999, 7, 6);
4190 immutable idate = Date(1999, 7, 6);
4191 assert(cdate.month == 7);
4192 assert(idate.month == 7);
4193 }
4194
4195 /++
4196 Month of a Gregorian Year.
4197
4198 Params:
4199 month = The month to set this $(LREF Date)'s month to.
4200
4201 Throws:
4202 $(REF DateTimeException,std,datetime,date) if the given month is
4203 not a valid month or if the current day would not be valid in the
4204 given month.
4205 +/
4206 @property void month(Month month) @safe pure
4207 {
4208 enforceValid!"months"(month);
4209 enforceValid!"days"(_year, month, _day);
4210 _month = cast(Month) month;
4211 }
4212
4213 @safe unittest
4214 {
4215 static void testDate(Date date, Month month, in Date expected = Date.init)
4216 {
4217 date.month = month;
4218 assert(expected != Date.init);
4219 assert(date == expected);
4220 }
4221
4222 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0));
4223 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13));
4224 assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2));
4225 assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2));
4226
4227 testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1));
4228 testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1));
4229
4230 const cdate = Date(1999, 7, 6);
4231 immutable idate = Date(1999, 7, 6);
4232 static assert(!__traits(compiles, cdate.month = 7));
4233 static assert(!__traits(compiles, idate.month = 7));
4234 }
4235
4236
4237 /++
4238 Day of a Gregorian Month.
4239 +/
4240 @property ubyte day() const @safe pure nothrow @nogc
4241 {
4242 return _day;
4243 }
4244
4245 ///
4246 @safe unittest
4247 {
4248 assert(Date(1999, 7, 6).day == 6);
4249 assert(Date(2010, 10, 4).day == 4);
4250 assert(Date(-7, 4, 5).day == 5);
4251 }
4252
4253 @safe unittest
4254 {
4255 import std.format : format;
4256 import std.range : chain;
4257
4258 static void test(Date date, int expected)
4259 {
4260 assert(date.day == expected, format("Value given: %s", date));
4261 }
4262
4263 foreach (year; chain(testYearsBC, testYearsAD))
4264 {
4265 foreach (md; testMonthDays)
4266 test(Date(year, md.month, md.day), md.day);
4267 }
4268
4269 const cdate = Date(1999, 7, 6);
4270 immutable idate = Date(1999, 7, 6);
4271 assert(cdate.day == 6);
4272 assert(idate.day == 6);
4273 }
4274
4275 /++
4276 Day of a Gregorian Month.
4277
4278 Params:
4279 day = The day of the month to set this $(LREF Date)'s day to.
4280
4281 Throws:
4282 $(REF DateTimeException,std,datetime,date) if the given day is not
4283 a valid day of the current month.
4284 +/
4285 @property void day(int day) @safe pure
4286 {
4287 enforceValid!"days"(_year, _month, day);
4288 _day = cast(ubyte) day;
4289 }
4290
4291 @safe unittest
4292 {
4293 import std.exception : assertNotThrown;
4294
4295 static void testDate(Date date, int day)
4296 {
4297 date.day = day;
4298 }
4299
4300 // Test A.D.
4301 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0));
4302 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32));
4303 assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29));
4304 assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30));
4305 assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32));
4306 assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31));
4307 assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32));
4308 assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31));
4309 assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32));
4310 assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32));
4311 assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31));
4312 assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32));
4313 assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31));
4314 assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32));
4315
4316 assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31));
4317 assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28));
4318 assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29));
4319 assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31));
4320 assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30));
4321 assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31));
4322 assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30));
4323 assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31));
4324 assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31));
4325 assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30));
4326 assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31));
4327 assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30));
4328 assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31));
4329
4330 {
4331 auto date = Date(1, 1, 1);
4332 date.day = 6;
4333 assert(date == Date(1, 1, 6));
4334 }
4335
4336 // Test B.C.
4337 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0));
4338 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32));
4339 assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29));
4340 assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30));
4341 assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32));
4342 assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31));
4343 assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32));
4344 assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31));
4345 assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32));
4346 assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32));
4347 assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31));
4348 assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32));
4349 assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31));
4350 assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32));
4351
4352 assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31));
4353 assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28));
4354 assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29));
4355 assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31));
4356 assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30));
4357 assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31));
4358 assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30));
4359 assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31));
4360 assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31));
4361 assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30));
4362 assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31));
4363 assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30));
4364 assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31));
4365
4366 {
4367 auto date = Date(-1, 1, 1);
4368 date.day = 6;
4369 assert(date == Date(-1, 1, 6));
4370 }
4371
4372 const cdate = Date(1999, 7, 6);
4373 immutable idate = Date(1999, 7, 6);
4374 static assert(!__traits(compiles, cdate.day = 6));
4375 static assert(!__traits(compiles, idate.day = 6));
4376 }
4377
4378
4379 /++
4380 Adds the given number of years or months to this $(LREF Date). A
4381 negative number will subtract.
4382
4383 Note that if day overflow is allowed, and the date with the adjusted
4384 year/month overflows the number of days in the new month, then the month
4385 will be incremented by one, and the day set to the number of days
4386 overflowed. (e.g. if the day were 31 and the new month were June, then
4387 the month would be incremented to July, and the new day would be 1). If
4388 day overflow is not allowed, then the day will be set to the last valid
4389 day in the month (e.g. June 31st would become June 30th).
4390
4391 Params:
4392 units = The type of units to add ("years" or "months").
4393 value = The number of months or years to add to this
4394 $(LREF Date).
4395 allowOverflow = Whether the day should be allowed to overflow,
4396 causing the month to increment.
4397 +/
4398 @safe pure nothrow @nogc
4399 ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
4400 if (units == "years")
4401 {
4402 _year += value;
4403
4404 if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year))
4405 {
4406 if (allowOverflow == AllowDayOverflow.yes)
4407 {
4408 _month = Month.mar;
4409 _day = 1;
4410 }
4411 else
4412 _day = 28;
4413 }
4414
4415 return this;
4416 }
4417
4418 ///
4419 @safe unittest
4420 {
4421 auto d1 = Date(2010, 1, 1);
4422 d1.add!"months"(11);
4423 assert(d1 == Date(2010, 12, 1));
4424
4425 auto d2 = Date(2010, 1, 1);
4426 d2.add!"months"(-11);
4427 assert(d2 == Date(2009, 2, 1));
4428
4429 auto d3 = Date(2000, 2, 29);
4430 d3.add!"years"(1);
4431 assert(d3 == Date(2001, 3, 1));
4432
4433 auto d4 = Date(2000, 2, 29);
4434 d4.add!"years"(1, AllowDayOverflow.no);
4435 assert(d4 == Date(2001, 2, 28));
4436 }
4437
4438 // Test add!"years"() with AllowDayOverflow.yes
4439 @safe unittest
4440 {
4441 // Test A.D.
4442 {
4443 auto date = Date(1999, 7, 6);
4444 date.add!"years"(7);
4445 assert(date == Date(2006, 7, 6));
4446 date.add!"years"(-9);
4447 assert(date == Date(1997, 7, 6));
4448 }
4449
4450 {
4451 auto date = Date(1999, 2, 28);
4452 date.add!"years"(1);
4453 assert(date == Date(2000, 2, 28));
4454 }
4455
4456 {
4457 auto date = Date(2000, 2, 29);
4458 date.add!"years"(-1);
4459 assert(date == Date(1999, 3, 1));
4460 }
4461
4462 // Test B.C.
4463 {
4464 auto date = Date(-1999, 7, 6);
4465 date.add!"years"(-7);
4466 assert(date == Date(-2006, 7, 6));
4467 date.add!"years"(9);
4468 assert(date == Date(-1997, 7, 6));
4469 }
4470
4471 {
4472 auto date = Date(-1999, 2, 28);
4473 date.add!"years"(-1);
4474 assert(date == Date(-2000, 2, 28));
4475 }
4476
4477 {
4478 auto date = Date(-2000, 2, 29);
4479 date.add!"years"(1);
4480 assert(date == Date(-1999, 3, 1));
4481 }
4482
4483 // Test Both
4484 {
4485 auto date = Date(4, 7, 6);
4486 date.add!"years"(-5);
4487 assert(date == Date(-1, 7, 6));
4488 date.add!"years"(5);
4489 assert(date == Date(4, 7, 6));
4490 }
4491
4492 {
4493 auto date = Date(-4, 7, 6);
4494 date.add!"years"(5);
4495 assert(date == Date(1, 7, 6));
4496 date.add!"years"(-5);
4497 assert(date == Date(-4, 7, 6));
4498 }
4499
4500 {
4501 auto date = Date(4, 7, 6);
4502 date.add!"years"(-8);
4503 assert(date == Date(-4, 7, 6));
4504 date.add!"years"(8);
4505 assert(date == Date(4, 7, 6));
4506 }
4507
4508 {
4509 auto date = Date(-4, 7, 6);
4510 date.add!"years"(8);
4511 assert(date == Date(4, 7, 6));
4512 date.add!"years"(-8);
4513 assert(date == Date(-4, 7, 6));
4514 }
4515
4516 {
4517 auto date = Date(-4, 2, 29);
4518 date.add!"years"(5);
4519 assert(date == Date(1, 3, 1));
4520 }
4521
4522 {
4523 auto date = Date(4, 2, 29);
4524 date.add!"years"(-5);
4525 assert(date == Date(-1, 3, 1));
4526 }
4527
4528 {
4529 auto date = Date(4, 2, 29);
4530 date.add!"years"(-5).add!"years"(7);
4531 assert(date == Date(6, 3, 1));
4532 }
4533
4534 const cdate = Date(1999, 7, 6);
4535 immutable idate = Date(1999, 7, 6);
4536 static assert(!__traits(compiles, cdate.add!"years"(7)));
4537 static assert(!__traits(compiles, idate.add!"years"(7)));
4538 }
4539
4540 // Test add!"years"() with AllowDayOverflow.no
4541 @safe unittest
4542 {
4543 // Test A.D.
4544 {
4545 auto date = Date(1999, 7, 6);
4546 date.add!"years"(7, AllowDayOverflow.no);
4547 assert(date == Date(2006, 7, 6));
4548 date.add!"years"(-9, AllowDayOverflow.no);
4549 assert(date == Date(1997, 7, 6));
4550 }
4551
4552 {
4553 auto date = Date(1999, 2, 28);
4554 date.add!"years"(1, AllowDayOverflow.no);
4555 assert(date == Date(2000, 2, 28));
4556 }
4557
4558 {
4559 auto date = Date(2000, 2, 29);
4560 date.add!"years"(-1, AllowDayOverflow.no);
4561 assert(date == Date(1999, 2, 28));
4562 }
4563
4564 // Test B.C.
4565 {
4566 auto date = Date(-1999, 7, 6);
4567 date.add!"years"(-7, AllowDayOverflow.no);
4568 assert(date == Date(-2006, 7, 6));
4569 date.add!"years"(9, AllowDayOverflow.no);
4570 assert(date == Date(-1997, 7, 6));
4571 }
4572
4573 {
4574 auto date = Date(-1999, 2, 28);
4575 date.add!"years"(-1, AllowDayOverflow.no);
4576 assert(date == Date(-2000, 2, 28));
4577 }
4578
4579 {
4580 auto date = Date(-2000, 2, 29);
4581 date.add!"years"(1, AllowDayOverflow.no);
4582 assert(date == Date(-1999, 2, 28));
4583 }
4584
4585 // Test Both
4586 {
4587 auto date = Date(4, 7, 6);
4588 date.add!"years"(-5, AllowDayOverflow.no);
4589 assert(date == Date(-1, 7, 6));
4590 date.add!"years"(5, AllowDayOverflow.no);
4591 assert(date == Date(4, 7, 6));
4592 }
4593
4594 {
4595 auto date = Date(-4, 7, 6);
4596 date.add!"years"(5, AllowDayOverflow.no);
4597 assert(date == Date(1, 7, 6));
4598 date.add!"years"(-5, AllowDayOverflow.no);
4599 assert(date == Date(-4, 7, 6));
4600 }
4601
4602 {
4603 auto date = Date(4, 7, 6);
4604 date.add!"years"(-8, AllowDayOverflow.no);
4605 assert(date == Date(-4, 7, 6));
4606 date.add!"years"(8, AllowDayOverflow.no);
4607 assert(date == Date(4, 7, 6));
4608 }
4609
4610 {
4611 auto date = Date(-4, 7, 6);
4612 date.add!"years"(8, AllowDayOverflow.no);
4613 assert(date == Date(4, 7, 6));
4614 date.add!"years"(-8, AllowDayOverflow.no);
4615 assert(date == Date(-4, 7, 6));
4616 }
4617
4618 {
4619 auto date = Date(-4, 2, 29);
4620 date.add!"years"(5, AllowDayOverflow.no);
4621 assert(date == Date(1, 2, 28));
4622 }
4623
4624 {
4625 auto date = Date(4, 2, 29);
4626 date.add!"years"(-5, AllowDayOverflow.no);
4627 assert(date == Date(-1, 2, 28));
4628 }
4629
4630 {
4631 auto date = Date(4, 2, 29);
4632 date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
4633 assert(date == Date(6, 2, 28));
4634 }
4635 }
4636
4637
4638 // Shares documentation with "years" version.
4639 @safe pure nothrow @nogc
4640 ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
4641 if (units == "months")
4642 {
4643 auto years = months / 12;
4644 months %= 12;
4645 auto newMonth = _month + months;
4646
4647 if (months < 0)
4648 {
4649 if (newMonth < 1)
4650 {
4651 newMonth += 12;
4652 --years;
4653 }
4654 }
4655 else if (newMonth > 12)
4656 {
4657 newMonth -= 12;
4658 ++years;
4659 }
4660
4661 _year += years;
4662 _month = cast(Month) newMonth;
4663
4664 immutable currMaxDay = maxDay(_year, _month);
4665 immutable overflow = _day - currMaxDay;
4666
4667 if (overflow > 0)
4668 {
4669 if (allowOverflow == AllowDayOverflow.yes)
4670 {
4671 ++_month;
4672 _day = cast(ubyte) overflow;
4673 }
4674 else
4675 _day = cast(ubyte) currMaxDay;
4676 }
4677
4678 return this;
4679 }
4680
4681 // Test add!"months"() with AllowDayOverflow.yes
4682 @safe unittest
4683 {
4684 // Test A.D.
4685 {
4686 auto date = Date(1999, 7, 6);
4687 date.add!"months"(3);
4688 assert(date == Date(1999, 10, 6));
4689 date.add!"months"(-4);
4690 assert(date == Date(1999, 6, 6));
4691 }
4692
4693 {
4694 auto date = Date(1999, 7, 6);
4695 date.add!"months"(6);
4696 assert(date == Date(2000, 1, 6));
4697 date.add!"months"(-6);
4698 assert(date == Date(1999, 7, 6));
4699 }
4700
4701 {
4702 auto date = Date(1999, 7, 6);
4703 date.add!"months"(27);
4704 assert(date == Date(2001, 10, 6));
4705 date.add!"months"(-28);
4706 assert(date == Date(1999, 6, 6));
4707 }
4708
4709 {
4710 auto date = Date(1999, 5, 31);
4711 date.add!"months"(1);
4712 assert(date == Date(1999, 7, 1));
4713 }
4714
4715 {
4716 auto date = Date(1999, 5, 31);
4717 date.add!"months"(-1);
4718 assert(date == Date(1999, 5, 1));
4719 }
4720
4721 {
4722 auto date = Date(1999, 2, 28);
4723 date.add!"months"(12);
4724 assert(date == Date(2000, 2, 28));
4725 }
4726
4727 {
4728 auto date = Date(2000, 2, 29);
4729 date.add!"months"(12);
4730 assert(date == Date(2001, 3, 1));
4731 }
4732
4733 {
4734 auto date = Date(1999, 7, 31);
4735 date.add!"months"(1);
4736 assert(date == Date(1999, 8, 31));
4737 date.add!"months"(1);
4738 assert(date == Date(1999, 10, 1));
4739 }
4740
4741 {
4742 auto date = Date(1998, 8, 31);
4743 date.add!"months"(13);
4744 assert(date == Date(1999, 10, 1));
4745 date.add!"months"(-13);
4746 assert(date == Date(1998, 9, 1));
4747 }
4748
4749 {
4750 auto date = Date(1997, 12, 31);
4751 date.add!"months"(13);
4752 assert(date == Date(1999, 1, 31));
4753 date.add!"months"(-13);
4754 assert(date == Date(1997, 12, 31));
4755 }
4756
4757 {
4758 auto date = Date(1997, 12, 31);
4759 date.add!"months"(14);
4760 assert(date == Date(1999, 3, 3));
4761 date.add!"months"(-14);
4762 assert(date == Date(1998, 1, 3));
4763 }
4764
4765 {
4766 auto date = Date(1998, 12, 31);
4767 date.add!"months"(14);
4768 assert(date == Date(2000, 3, 2));
4769 date.add!"months"(-14);
4770 assert(date == Date(1999, 1, 2));
4771 }
4772
4773 {
4774 auto date = Date(1999, 12, 31);
4775 date.add!"months"(14);
4776 assert(date == Date(2001, 3, 3));
4777 date.add!"months"(-14);
4778 assert(date == Date(2000, 1, 3));
4779 }
4780
4781 // Test B.C.
4782 {
4783 auto date = Date(-1999, 7, 6);
4784 date.add!"months"(3);
4785 assert(date == Date(-1999, 10, 6));
4786 date.add!"months"(-4);
4787 assert(date == Date(-1999, 6, 6));
4788 }
4789
4790 {
4791 auto date = Date(-1999, 7, 6);
4792 date.add!"months"(6);
4793 assert(date == Date(-1998, 1, 6));
4794 date.add!"months"(-6);
4795 assert(date == Date(-1999, 7, 6));
4796 }
4797
4798 {
4799 auto date = Date(-1999, 7, 6);
4800 date.add!"months"(-27);
4801 assert(date == Date(-2001, 4, 6));
4802 date.add!"months"(28);
4803 assert(date == Date(-1999, 8, 6));
4804 }
4805
4806 {
4807 auto date = Date(-1999, 5, 31);
4808 date.add!"months"(1);
4809 assert(date == Date(-1999, 7, 1));
4810 }
4811
4812 {
4813 auto date = Date(-1999, 5, 31);
4814 date.add!"months"(-1);
4815 assert(date == Date(-1999, 5, 1));
4816 }
4817
4818 {
4819 auto date = Date(-1999, 2, 28);
4820 date.add!"months"(-12);
4821 assert(date == Date(-2000, 2, 28));
4822 }
4823
4824 {
4825 auto date = Date(-2000, 2, 29);
4826 date.add!"months"(-12);
4827 assert(date == Date(-2001, 3, 1));
4828 }
4829
4830 {
4831 auto date = Date(-1999, 7, 31);
4832 date.add!"months"(1);
4833 assert(date == Date(-1999, 8, 31));
4834 date.add!"months"(1);
4835 assert(date == Date(-1999, 10, 1));
4836 }
4837
4838 {
4839 auto date = Date(-1998, 8, 31);
4840 date.add!"months"(13);
4841 assert(date == Date(-1997, 10, 1));
4842 date.add!"months"(-13);
4843 assert(date == Date(-1998, 9, 1));
4844 }
4845
4846 {
4847 auto date = Date(-1997, 12, 31);
4848 date.add!"months"(13);
4849 assert(date == Date(-1995, 1, 31));
4850 date.add!"months"(-13);
4851 assert(date == Date(-1997, 12, 31));
4852 }
4853
4854 {
4855 auto date = Date(-1997, 12, 31);
4856 date.add!"months"(14);
4857 assert(date == Date(-1995, 3, 3));
4858 date.add!"months"(-14);
4859 assert(date == Date(-1996, 1, 3));
4860 }
4861
4862 {
4863 auto date = Date(-2002, 12, 31);
4864 date.add!"months"(14);
4865 assert(date == Date(-2000, 3, 2));
4866 date.add!"months"(-14);
4867 assert(date == Date(-2001, 1, 2));
4868 }
4869
4870 {
4871 auto date = Date(-2001, 12, 31);
4872 date.add!"months"(14);
4873 assert(date == Date(-1999, 3, 3));
4874 date.add!"months"(-14);
4875 assert(date == Date(-2000, 1, 3));
4876 }
4877
4878 // Test Both
4879 {
4880 auto date = Date(1, 1, 1);
4881 date.add!"months"(-1);
4882 assert(date == Date(0, 12, 1));
4883 date.add!"months"(1);
4884 assert(date == Date(1, 1, 1));
4885 }
4886
4887 {
4888 auto date = Date(4, 1, 1);
4889 date.add!"months"(-48);
4890 assert(date == Date(0, 1, 1));
4891 date.add!"months"(48);
4892 assert(date == Date(4, 1, 1));
4893 }
4894
4895 {
4896 auto date = Date(4, 3, 31);
4897 date.add!"months"(-49);
4898 assert(date == Date(0, 3, 2));
4899 date.add!"months"(49);
4900 assert(date == Date(4, 4, 2));
4901 }
4902
4903 {
4904 auto date = Date(4, 3, 31);
4905 date.add!"months"(-85);
4906 assert(date == Date(-3, 3, 3));
4907 date.add!"months"(85);
4908 assert(date == Date(4, 4, 3));
4909 }
4910
4911 {
4912 auto date = Date(-3, 3, 31);
4913 date.add!"months"(85).add!"months"(-83);
4914 assert(date == Date(-3, 6, 1));
4915 }
4916
4917 const cdate = Date(1999, 7, 6);
4918 immutable idate = Date(1999, 7, 6);
4919 static assert(!__traits(compiles, cdate.add!"months"(3)));
4920 static assert(!__traits(compiles, idate.add!"months"(3)));
4921 }
4922
4923 // Test add!"months"() with AllowDayOverflow.no
4924 @safe unittest
4925 {
4926 // Test A.D.
4927 {
4928 auto date = Date(1999, 7, 6);
4929 date.add!"months"(3, AllowDayOverflow.no);
4930 assert(date == Date(1999, 10, 6));
4931 date.add!"months"(-4, AllowDayOverflow.no);
4932 assert(date == Date(1999, 6, 6));
4933 }
4934
4935 {
4936 auto date = Date(1999, 7, 6);
4937 date.add!"months"(6, AllowDayOverflow.no);
4938 assert(date == Date(2000, 1, 6));
4939 date.add!"months"(-6, AllowDayOverflow.no);
4940 assert(date == Date(1999, 7, 6));
4941 }
4942
4943 {
4944 auto date = Date(1999, 7, 6);
4945 date.add!"months"(27, AllowDayOverflow.no);
4946 assert(date == Date(2001, 10, 6));
4947 date.add!"months"(-28, AllowDayOverflow.no);
4948 assert(date == Date(1999, 6, 6));
4949 }
4950
4951 {
4952 auto date = Date(1999, 5, 31);
4953 date.add!"months"(1, AllowDayOverflow.no);
4954 assert(date == Date(1999, 6, 30));
4955 }
4956
4957 {
4958 auto date = Date(1999, 5, 31);
4959 date.add!"months"(-1, AllowDayOverflow.no);
4960 assert(date == Date(1999, 4, 30));
4961 }
4962
4963 {
4964 auto date = Date(1999, 2, 28);
4965 date.add!"months"(12, AllowDayOverflow.no);
4966 assert(date == Date(2000, 2, 28));
4967 }
4968
4969 {
4970 auto date = Date(2000, 2, 29);
4971 date.add!"months"(12, AllowDayOverflow.no);
4972 assert(date == Date(2001, 2, 28));
4973 }
4974
4975 {
4976 auto date = Date(1999, 7, 31);
4977 date.add!"months"(1, AllowDayOverflow.no);
4978 assert(date == Date(1999, 8, 31));
4979 date.add!"months"(1, AllowDayOverflow.no);
4980 assert(date == Date(1999, 9, 30));
4981 }
4982
4983 {
4984 auto date = Date(1998, 8, 31);
4985 date.add!"months"(13, AllowDayOverflow.no);
4986 assert(date == Date(1999, 9, 30));
4987 date.add!"months"(-13, AllowDayOverflow.no);
4988 assert(date == Date(1998, 8, 30));
4989 }
4990
4991 {
4992 auto date = Date(1997, 12, 31);
4993 date.add!"months"(13, AllowDayOverflow.no);
4994 assert(date == Date(1999, 1, 31));
4995 date.add!"months"(-13, AllowDayOverflow.no);
4996 assert(date == Date(1997, 12, 31));
4997 }
4998
4999 {
5000 auto date = Date(1997, 12, 31);
5001 date.add!"months"(14, AllowDayOverflow.no);
5002 assert(date == Date(1999, 2, 28));
5003 date.add!"months"(-14, AllowDayOverflow.no);
5004 assert(date == Date(1997, 12, 28));
5005 }
5006
5007 {
5008 auto date = Date(1998, 12, 31);
5009 date.add!"months"(14, AllowDayOverflow.no);
5010 assert(date == Date(2000, 2, 29));
5011 date.add!"months"(-14, AllowDayOverflow.no);
5012 assert(date == Date(1998, 12, 29));
5013 }
5014
5015 {
5016 auto date = Date(1999, 12, 31);
5017 date.add!"months"(14, AllowDayOverflow.no);
5018 assert(date == Date(2001, 2, 28));
5019 date.add!"months"(-14, AllowDayOverflow.no);
5020 assert(date == Date(1999, 12, 28));
5021 }
5022
5023 // Test B.C.
5024 {
5025 auto date = Date(-1999, 7, 6);
5026 date.add!"months"(3, AllowDayOverflow.no);
5027 assert(date == Date(-1999, 10, 6));
5028 date.add!"months"(-4, AllowDayOverflow.no);
5029 assert(date == Date(-1999, 6, 6));
5030 }
5031
5032 {
5033 auto date = Date(-1999, 7, 6);
5034 date.add!"months"(6, AllowDayOverflow.no);
5035 assert(date == Date(-1998, 1, 6));
5036 date.add!"months"(-6, AllowDayOverflow.no);
5037 assert(date == Date(-1999, 7, 6));
5038 }
5039
5040 {
5041 auto date = Date(-1999, 7, 6);
5042 date.add!"months"(-27, AllowDayOverflow.no);
5043 assert(date == Date(-2001, 4, 6));
5044 date.add!"months"(28, AllowDayOverflow.no);
5045 assert(date == Date(-1999, 8, 6));
5046 }
5047
5048 {
5049 auto date = Date(-1999, 5, 31);
5050 date.add!"months"(1, AllowDayOverflow.no);
5051 assert(date == Date(-1999, 6, 30));
5052 }
5053
5054 {
5055 auto date = Date(-1999, 5, 31);
5056 date.add!"months"(-1, AllowDayOverflow.no);
5057 assert(date == Date(-1999, 4, 30));
5058 }
5059
5060 {
5061 auto date = Date(-1999, 2, 28);
5062 date.add!"months"(-12, AllowDayOverflow.no);
5063 assert(date == Date(-2000, 2, 28));
5064 }
5065
5066 {
5067 auto date = Date(-2000, 2, 29);
5068 date.add!"months"(-12, AllowDayOverflow.no);
5069 assert(date == Date(-2001, 2, 28));
5070 }
5071
5072 {
5073 auto date = Date(-1999, 7, 31);
5074 date.add!"months"(1, AllowDayOverflow.no);
5075 assert(date == Date(-1999, 8, 31));
5076 date.add!"months"(1, AllowDayOverflow.no);
5077 assert(date == Date(-1999, 9, 30));
5078 }
5079
5080 {
5081 auto date = Date(-1998, 8, 31);
5082 date.add!"months"(13, AllowDayOverflow.no);
5083 assert(date == Date(-1997, 9, 30));
5084 date.add!"months"(-13, AllowDayOverflow.no);
5085 assert(date == Date(-1998, 8, 30));
5086 }
5087
5088 {
5089 auto date = Date(-1997, 12, 31);
5090 date.add!"months"(13, AllowDayOverflow.no);
5091 assert(date == Date(-1995, 1, 31));
5092 date.add!"months"(-13, AllowDayOverflow.no);
5093 assert(date == Date(-1997, 12, 31));
5094 }
5095
5096 {
5097 auto date = Date(-1997, 12, 31);
5098 date.add!"months"(14, AllowDayOverflow.no);
5099 assert(date == Date(-1995, 2, 28));
5100 date.add!"months"(-14, AllowDayOverflow.no);
5101 assert(date == Date(-1997, 12, 28));
5102 }
5103
5104 {
5105 auto date = Date(-2002, 12, 31);
5106 date.add!"months"(14, AllowDayOverflow.no);
5107 assert(date == Date(-2000, 2, 29));
5108 date.add!"months"(-14, AllowDayOverflow.no);
5109 assert(date == Date(-2002, 12, 29));
5110 }
5111
5112 {
5113 auto date = Date(-2001, 12, 31);
5114 date.add!"months"(14, AllowDayOverflow.no);
5115 assert(date == Date(-1999, 2, 28));
5116 date.add!"months"(-14, AllowDayOverflow.no);
5117 assert(date == Date(-2001, 12, 28));
5118 }
5119
5120 // Test Both
5121 {
5122 auto date = Date(1, 1, 1);
5123 date.add!"months"(-1, AllowDayOverflow.no);
5124 assert(date == Date(0, 12, 1));
5125 date.add!"months"(1, AllowDayOverflow.no);
5126 assert(date == Date(1, 1, 1));
5127 }
5128
5129 {
5130 auto date = Date(4, 1, 1);
5131 date.add!"months"(-48, AllowDayOverflow.no);
5132 assert(date == Date(0, 1, 1));
5133 date.add!"months"(48, AllowDayOverflow.no);
5134 assert(date == Date(4, 1, 1));
5135 }
5136
5137 {
5138 auto date = Date(4, 3, 31);
5139 date.add!"months"(-49, AllowDayOverflow.no);
5140 assert(date == Date(0, 2, 29));
5141 date.add!"months"(49, AllowDayOverflow.no);
5142 assert(date == Date(4, 3, 29));
5143 }
5144
5145 {
5146 auto date = Date(4, 3, 31);
5147 date.add!"months"(-85, AllowDayOverflow.no);
5148 assert(date == Date(-3, 2, 28));
5149 date.add!"months"(85, AllowDayOverflow.no);
5150 assert(date == Date(4, 3, 28));
5151 }
5152
5153 {
5154 auto date = Date(-3, 3, 31);
5155 date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
5156 assert(date == Date(-3, 5, 30));
5157 }
5158 }
5159
5160
5161 /++
5162 Adds the given number of years or months to this $(LREF Date). A negative
5163 number will subtract.
5164
5165 The difference between rolling and adding is that rolling does not
5166 affect larger units. Rolling a $(LREF Date) 12 months gets
5167 the exact same $(LREF Date). However, the days can still be affected due
5168 to the differing number of days in each month.
5169
5170 Because there are no units larger than years, there is no difference
5171 between adding and rolling years.
5172
5173 Params:
5174 units = The type of units to add ("years" or "months").
5175 value = The number of months or years to add to this
5176 $(LREF Date).
5177 allowOverflow = Whether the day should be allowed to overflow,
5178 causing the month to increment.
5179 +/
5180 @safe pure nothrow @nogc
5181 ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
5182 if (units == "years")
5183 {
5184 return add!"years"(value, allowOverflow);
5185 }
5186
5187 ///
5188 @safe unittest
5189 {
5190 auto d1 = Date(2010, 1, 1);
5191 d1.roll!"months"(1);
5192 assert(d1 == Date(2010, 2, 1));
5193
5194 auto d2 = Date(2010, 1, 1);
5195 d2.roll!"months"(-1);
5196 assert(d2 == Date(2010, 12, 1));
5197
5198 auto d3 = Date(1999, 1, 29);
5199 d3.roll!"months"(1);
5200 assert(d3 == Date(1999, 3, 1));
5201
5202 auto d4 = Date(1999, 1, 29);
5203 d4.roll!"months"(1, AllowDayOverflow.no);
5204 assert(d4 == Date(1999, 2, 28));
5205
5206 auto d5 = Date(2000, 2, 29);
5207 d5.roll!"years"(1);
5208 assert(d5 == Date(2001, 3, 1));
5209
5210 auto d6 = Date(2000, 2, 29);
5211 d6.roll!"years"(1, AllowDayOverflow.no);
5212 assert(d6 == Date(2001, 2, 28));
5213 }
5214
5215 @safe unittest
5216 {
5217 const cdate = Date(1999, 7, 6);
5218 immutable idate = Date(1999, 7, 6);
5219 static assert(!__traits(compiles, cdate.roll!"years"(3)));
5220 static assert(!__traits(compiles, idate.rolYears(3)));
5221 }
5222
5223
5224 // Shares documentation with "years" version.
5225 @safe pure nothrow @nogc
5226 ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
5227 if (units == "months")
5228 {
5229 months %= 12;
5230 auto newMonth = _month + months;
5231
5232 if (months < 0)
5233 {
5234 if (newMonth < 1)
5235 newMonth += 12;
5236 }
5237 else
5238 {
5239 if (newMonth > 12)
5240 newMonth -= 12;
5241 }
5242
5243 _month = cast(Month) newMonth;
5244
5245 immutable currMaxDay = maxDay(_year, _month);
5246 immutable overflow = _day - currMaxDay;
5247
5248 if (overflow > 0)
5249 {
5250 if (allowOverflow == AllowDayOverflow.yes)
5251 {
5252 ++_month;
5253 _day = cast(ubyte) overflow;
5254 }
5255 else
5256 _day = cast(ubyte) currMaxDay;
5257 }
5258
5259 return this;
5260 }
5261
5262 // Test roll!"months"() with AllowDayOverflow.yes
5263 @safe unittest
5264 {
5265 // Test A.D.
5266 {
5267 auto date = Date(1999, 7, 6);
5268 date.roll!"months"(3);
5269 assert(date == Date(1999, 10, 6));
5270 date.roll!"months"(-4);
5271 assert(date == Date(1999, 6, 6));
5272 }
5273
5274 {
5275 auto date = Date(1999, 7, 6);
5276 date.roll!"months"(6);
5277 assert(date == Date(1999, 1, 6));
5278 date.roll!"months"(-6);
5279 assert(date == Date(1999, 7, 6));
5280 }
5281
5282 {
5283 auto date = Date(1999, 7, 6);
5284 date.roll!"months"(27);
5285 assert(date == Date(1999, 10, 6));
5286 date.roll!"months"(-28);
5287 assert(date == Date(1999, 6, 6));
5288 }
5289
5290 {
5291 auto date = Date(1999, 5, 31);
5292 date.roll!"months"(1);
5293 assert(date == Date(1999, 7, 1));
5294 }
5295
5296 {
5297 auto date = Date(1999, 5, 31);
5298 date.roll!"months"(-1);
5299 assert(date == Date(1999, 5, 1));
5300 }
5301
5302 {
5303 auto date = Date(1999, 2, 28);
5304 date.roll!"months"(12);
5305 assert(date == Date(1999, 2, 28));
5306 }
5307
5308 {
5309 auto date = Date(2000, 2, 29);
5310 date.roll!"months"(12);
5311 assert(date == Date(2000, 2, 29));
5312 }
5313
5314 {
5315 auto date = Date(1999, 7, 31);
5316 date.roll!"months"(1);
5317 assert(date == Date(1999, 8, 31));
5318 date.roll!"months"(1);
5319 assert(date == Date(1999, 10, 1));
5320 }
5321
5322 {
5323 auto date = Date(1998, 8, 31);
5324 date.roll!"months"(13);
5325 assert(date == Date(1998, 10, 1));
5326 date.roll!"months"(-13);
5327 assert(date == Date(1998, 9, 1));
5328 }
5329
5330 {
5331 auto date = Date(1997, 12, 31);
5332 date.roll!"months"(13);
5333 assert(date == Date(1997, 1, 31));
5334 date.roll!"months"(-13);
5335 assert(date == Date(1997, 12, 31));
5336 }
5337
5338 {
5339 auto date = Date(1997, 12, 31);
5340 date.roll!"months"(14);
5341 assert(date == Date(1997, 3, 3));
5342 date.roll!"months"(-14);
5343 assert(date == Date(1997, 1, 3));
5344 }
5345
5346 {
5347 auto date = Date(1998, 12, 31);
5348 date.roll!"months"(14);
5349 assert(date == Date(1998, 3, 3));
5350 date.roll!"months"(-14);
5351 assert(date == Date(1998, 1, 3));
5352 }
5353
5354 {
5355 auto date = Date(1999, 12, 31);
5356 date.roll!"months"(14);
5357 assert(date == Date(1999, 3, 3));
5358 date.roll!"months"(-14);
5359 assert(date == Date(1999, 1, 3));
5360 }
5361
5362 // Test B.C.
5363 {
5364 auto date = Date(-1999, 7, 6);
5365 date.roll!"months"(3);
5366 assert(date == Date(-1999, 10, 6));
5367 date.roll!"months"(-4);
5368 assert(date == Date(-1999, 6, 6));
5369 }
5370
5371 {
5372 auto date = Date(-1999, 7, 6);
5373 date.roll!"months"(6);
5374 assert(date == Date(-1999, 1, 6));
5375 date.roll!"months"(-6);
5376 assert(date == Date(-1999, 7, 6));
5377 }
5378
5379 {
5380 auto date = Date(-1999, 7, 6);
5381 date.roll!"months"(-27);
5382 assert(date == Date(-1999, 4, 6));
5383 date.roll!"months"(28);
5384 assert(date == Date(-1999, 8, 6));
5385 }
5386
5387 {
5388 auto date = Date(-1999, 5, 31);
5389 date.roll!"months"(1);
5390 assert(date == Date(-1999, 7, 1));
5391 }
5392
5393 {
5394 auto date = Date(-1999, 5, 31);
5395 date.roll!"months"(-1);
5396 assert(date == Date(-1999, 5, 1));
5397 }
5398
5399 {
5400 auto date = Date(-1999, 2, 28);
5401 date.roll!"months"(-12);
5402 assert(date == Date(-1999, 2, 28));
5403 }
5404
5405 {
5406 auto date = Date(-2000, 2, 29);
5407 date.roll!"months"(-12);
5408 assert(date == Date(-2000, 2, 29));
5409 }
5410
5411 {
5412 auto date = Date(-1999, 7, 31);
5413 date.roll!"months"(1);
5414 assert(date == Date(-1999, 8, 31));
5415 date.roll!"months"(1);
5416 assert(date == Date(-1999, 10, 1));
5417 }
5418
5419 {
5420 auto date = Date(-1998, 8, 31);
5421 date.roll!"months"(13);
5422 assert(date == Date(-1998, 10, 1));
5423 date.roll!"months"(-13);
5424 assert(date == Date(-1998, 9, 1));
5425 }
5426
5427 {
5428 auto date = Date(-1997, 12, 31);
5429 date.roll!"months"(13);
5430 assert(date == Date(-1997, 1, 31));
5431 date.roll!"months"(-13);
5432 assert(date == Date(-1997, 12, 31));
5433 }
5434
5435 {
5436 auto date = Date(-1997, 12, 31);
5437 date.roll!"months"(14);
5438 assert(date == Date(-1997, 3, 3));
5439 date.roll!"months"(-14);
5440 assert(date == Date(-1997, 1, 3));
5441 }
5442
5443 {
5444 auto date = Date(-2002, 12, 31);
5445 date.roll!"months"(14);
5446 assert(date == Date(-2002, 3, 3));
5447 date.roll!"months"(-14);
5448 assert(date == Date(-2002, 1, 3));
5449 }
5450
5451 {
5452 auto date = Date(-2001, 12, 31);
5453 date.roll!"months"(14);
5454 assert(date == Date(-2001, 3, 3));
5455 date.roll!"months"(-14);
5456 assert(date == Date(-2001, 1, 3));
5457 }
5458
5459 // Test Both
5460 {
5461 auto date = Date(1, 1, 1);
5462 date.roll!"months"(-1);
5463 assert(date == Date(1, 12, 1));
5464 date.roll!"months"(1);
5465 assert(date == Date(1, 1, 1));
5466 }
5467
5468 {
5469 auto date = Date(4, 1, 1);
5470 date.roll!"months"(-48);
5471 assert(date == Date(4, 1, 1));
5472 date.roll!"months"(48);
5473 assert(date == Date(4, 1, 1));
5474 }
5475
5476 {
5477 auto date = Date(4, 3, 31);
5478 date.roll!"months"(-49);
5479 assert(date == Date(4, 3, 2));
5480 date.roll!"months"(49);
5481 assert(date == Date(4, 4, 2));
5482 }
5483
5484 {
5485 auto date = Date(4, 3, 31);
5486 date.roll!"months"(-85);
5487 assert(date == Date(4, 3, 2));
5488 date.roll!"months"(85);
5489 assert(date == Date(4, 4, 2));
5490 }
5491
5492 {
5493 auto date = Date(-1, 1, 1);
5494 date.roll!"months"(-1);
5495 assert(date == Date(-1, 12, 1));
5496 date.roll!"months"(1);
5497 assert(date == Date(-1, 1, 1));
5498 }
5499
5500 {
5501 auto date = Date(-4, 1, 1);
5502 date.roll!"months"(-48);
5503 assert(date == Date(-4, 1, 1));
5504 date.roll!"months"(48);
5505 assert(date == Date(-4, 1, 1));
5506 }
5507
5508 {
5509 auto date = Date(-4, 3, 31);
5510 date.roll!"months"(-49);
5511 assert(date == Date(-4, 3, 2));
5512 date.roll!"months"(49);
5513 assert(date == Date(-4, 4, 2));
5514 }
5515
5516 {
5517 auto date = Date(-4, 3, 31);
5518 date.roll!"months"(-85);
5519 assert(date == Date(-4, 3, 2));
5520 date.roll!"months"(85);
5521 assert(date == Date(-4, 4, 2));
5522 }
5523
5524 {
5525 auto date = Date(-3, 3, 31);
5526 date.roll!"months"(85).roll!"months"(-83);
5527 assert(date == Date(-3, 6, 1));
5528 }
5529
5530 const cdate = Date(1999, 7, 6);
5531 immutable idate = Date(1999, 7, 6);
5532 static assert(!__traits(compiles, cdate.roll!"months"(3)));
5533 static assert(!__traits(compiles, idate.roll!"months"(3)));
5534 }
5535
5536 // Test roll!"months"() with AllowDayOverflow.no
5537 @safe unittest
5538 {
5539 // Test A.D.
5540 {
5541 auto date = Date(1999, 7, 6);
5542 date.roll!"months"(3, AllowDayOverflow.no);
5543 assert(date == Date(1999, 10, 6));
5544 date.roll!"months"(-4, AllowDayOverflow.no);
5545 assert(date == Date(1999, 6, 6));
5546 }
5547
5548 {
5549 auto date = Date(1999, 7, 6);
5550 date.roll!"months"(6, AllowDayOverflow.no);
5551 assert(date == Date(1999, 1, 6));
5552 date.roll!"months"(-6, AllowDayOverflow.no);
5553 assert(date == Date(1999, 7, 6));
5554 }
5555
5556 {
5557 auto date = Date(1999, 7, 6);
5558 date.roll!"months"(27, AllowDayOverflow.no);
5559 assert(date == Date(1999, 10, 6));
5560 date.roll!"months"(-28, AllowDayOverflow.no);
5561 assert(date == Date(1999, 6, 6));
5562 }
5563
5564 {
5565 auto date = Date(1999, 5, 31);
5566 date.roll!"months"(1, AllowDayOverflow.no);
5567 assert(date == Date(1999, 6, 30));
5568 }
5569
5570 {
5571 auto date = Date(1999, 5, 31);
5572 date.roll!"months"(-1, AllowDayOverflow.no);
5573 assert(date == Date(1999, 4, 30));
5574 }
5575
5576 {
5577 auto date = Date(1999, 2, 28);
5578 date.roll!"months"(12, AllowDayOverflow.no);
5579 assert(date == Date(1999, 2, 28));
5580 }
5581
5582 {
5583 auto date = Date(2000, 2, 29);
5584 date.roll!"months"(12, AllowDayOverflow.no);
5585 assert(date == Date(2000, 2, 29));
5586 }
5587
5588 {
5589 auto date = Date(1999, 7, 31);
5590 date.roll!"months"(1, AllowDayOverflow.no);
5591 assert(date == Date(1999, 8, 31));
5592 date.roll!"months"(1, AllowDayOverflow.no);
5593 assert(date == Date(1999, 9, 30));
5594 }
5595
5596 {
5597 auto date = Date(1998, 8, 31);
5598 date.roll!"months"(13, AllowDayOverflow.no);
5599 assert(date == Date(1998, 9, 30));
5600 date.roll!"months"(-13, AllowDayOverflow.no);
5601 assert(date == Date(1998, 8, 30));
5602 }
5603
5604 {
5605 auto date = Date(1997, 12, 31);
5606 date.roll!"months"(13, AllowDayOverflow.no);
5607 assert(date == Date(1997, 1, 31));
5608 date.roll!"months"(-13, AllowDayOverflow.no);
5609 assert(date == Date(1997, 12, 31));
5610 }
5611
5612 {
5613 auto date = Date(1997, 12, 31);
5614 date.roll!"months"(14, AllowDayOverflow.no);
5615 assert(date == Date(1997, 2, 28));
5616 date.roll!"months"(-14, AllowDayOverflow.no);
5617 assert(date == Date(1997, 12, 28));
5618 }
5619
5620 {
5621 auto date = Date(1998, 12, 31);
5622 date.roll!"months"(14, AllowDayOverflow.no);
5623 assert(date == Date(1998, 2, 28));
5624 date.roll!"months"(-14, AllowDayOverflow.no);
5625 assert(date == Date(1998, 12, 28));
5626 }
5627
5628 {
5629 auto date = Date(1999, 12, 31);
5630 date.roll!"months"(14, AllowDayOverflow.no);
5631 assert(date == Date(1999, 2, 28));
5632 date.roll!"months"(-14, AllowDayOverflow.no);
5633 assert(date == Date(1999, 12, 28));
5634 }
5635
5636 // Test B.C.
5637 {
5638 auto date = Date(-1999, 7, 6);
5639 date.roll!"months"(3, AllowDayOverflow.no);
5640 assert(date == Date(-1999, 10, 6));
5641 date.roll!"months"(-4, AllowDayOverflow.no);
5642 assert(date == Date(-1999, 6, 6));
5643 }
5644
5645 {
5646 auto date = Date(-1999, 7, 6);
5647 date.roll!"months"(6, AllowDayOverflow.no);
5648 assert(date == Date(-1999, 1, 6));
5649 date.roll!"months"(-6, AllowDayOverflow.no);
5650 assert(date == Date(-1999, 7, 6));
5651 }
5652
5653 {
5654 auto date = Date(-1999, 7, 6);
5655 date.roll!"months"(-27, AllowDayOverflow.no);
5656 assert(date == Date(-1999, 4, 6));
5657 date.roll!"months"(28, AllowDayOverflow.no);
5658 assert(date == Date(-1999, 8, 6));
5659 }
5660
5661 {
5662 auto date = Date(-1999, 5, 31);
5663 date.roll!"months"(1, AllowDayOverflow.no);
5664 assert(date == Date(-1999, 6, 30));
5665 }
5666
5667 {
5668 auto date = Date(-1999, 5, 31);
5669 date.roll!"months"(-1, AllowDayOverflow.no);
5670 assert(date == Date(-1999, 4, 30));
5671 }
5672
5673 {
5674 auto date = Date(-1999, 2, 28);
5675 date.roll!"months"(-12, AllowDayOverflow.no);
5676 assert(date == Date(-1999, 2, 28));
5677 }
5678
5679 {
5680 auto date = Date(-2000, 2, 29);
5681 date.roll!"months"(-12, AllowDayOverflow.no);
5682 assert(date == Date(-2000, 2, 29));
5683 }
5684
5685 {
5686 auto date = Date(-1999, 7, 31);
5687 date.roll!"months"(1, AllowDayOverflow.no);
5688 assert(date == Date(-1999, 8, 31));
5689 date.roll!"months"(1, AllowDayOverflow.no);
5690 assert(date == Date(-1999, 9, 30));
5691 }
5692
5693 {
5694 auto date = Date(-1998, 8, 31);
5695 date.roll!"months"(13, AllowDayOverflow.no);
5696 assert(date == Date(-1998, 9, 30));
5697 date.roll!"months"(-13, AllowDayOverflow.no);
5698 assert(date == Date(-1998, 8, 30));
5699 }
5700
5701 {
5702 auto date = Date(-1997, 12, 31);
5703 date.roll!"months"(13, AllowDayOverflow.no);
5704 assert(date == Date(-1997, 1, 31));
5705 date.roll!"months"(-13, AllowDayOverflow.no);
5706 assert(date == Date(-1997, 12, 31));
5707 }
5708
5709 {
5710 auto date = Date(-1997, 12, 31);
5711 date.roll!"months"(14, AllowDayOverflow.no);
5712 assert(date == Date(-1997, 2, 28));
5713 date.roll!"months"(-14, AllowDayOverflow.no);
5714 assert(date == Date(-1997, 12, 28));
5715 }
5716
5717 {
5718 auto date = Date(-2002, 12, 31);
5719 date.roll!"months"(14, AllowDayOverflow.no);
5720 assert(date == Date(-2002, 2, 28));
5721 date.roll!"months"(-14, AllowDayOverflow.no);
5722 assert(date == Date(-2002, 12, 28));
5723 }
5724
5725 {
5726 auto date = Date(-2001, 12, 31);
5727 date.roll!"months"(14, AllowDayOverflow.no);
5728 assert(date == Date(-2001, 2, 28));
5729 date.roll!"months"(-14, AllowDayOverflow.no);
5730 assert(date == Date(-2001, 12, 28));
5731 }
5732
5733 // Test Both
5734 {
5735 auto date = Date(1, 1, 1);
5736 date.roll!"months"(-1, AllowDayOverflow.no);
5737 assert(date == Date(1, 12, 1));
5738 date.roll!"months"(1, AllowDayOverflow.no);
5739 assert(date == Date(1, 1, 1));
5740 }
5741
5742 {
5743 auto date = Date(4, 1, 1);
5744 date.roll!"months"(-48, AllowDayOverflow.no);
5745 assert(date == Date(4, 1, 1));
5746 date.roll!"months"(48, AllowDayOverflow.no);
5747 assert(date == Date(4, 1, 1));
5748 }
5749
5750 {
5751 auto date = Date(4, 3, 31);
5752 date.roll!"months"(-49, AllowDayOverflow.no);
5753 assert(date == Date(4, 2, 29));
5754 date.roll!"months"(49, AllowDayOverflow.no);
5755 assert(date == Date(4, 3, 29));
5756 }
5757
5758 {
5759 auto date = Date(4, 3, 31);
5760 date.roll!"months"(-85, AllowDayOverflow.no);
5761 assert(date == Date(4, 2, 29));
5762 date.roll!"months"(85, AllowDayOverflow.no);
5763 assert(date == Date(4, 3, 29));
5764 }
5765
5766 {
5767 auto date = Date(-1, 1, 1);
5768 date.roll!"months"(-1, AllowDayOverflow.no);
5769 assert(date == Date(-1, 12, 1));
5770 date.roll!"months"(1, AllowDayOverflow.no);
5771 assert(date == Date(-1, 1, 1));
5772 }
5773
5774 {
5775 auto date = Date(-4, 1, 1);
5776 date.roll!"months"(-48, AllowDayOverflow.no);
5777 assert(date == Date(-4, 1, 1));
5778 date.roll!"months"(48, AllowDayOverflow.no);
5779 assert(date == Date(-4, 1, 1));
5780 }
5781
5782 {
5783 auto date = Date(-4, 3, 31);
5784 date.roll!"months"(-49, AllowDayOverflow.no);
5785 assert(date == Date(-4, 2, 29));
5786 date.roll!"months"(49, AllowDayOverflow.no);
5787 assert(date == Date(-4, 3, 29));
5788 }
5789
5790 {
5791 auto date = Date(-4, 3, 31);
5792 date.roll!"months"(-85, AllowDayOverflow.no);
5793 assert(date == Date(-4, 2, 29));
5794 date.roll!"months"(85, AllowDayOverflow.no);
5795 assert(date == Date(-4, 3, 29));
5796 }
5797
5798 {
5799 auto date = Date(-3, 3, 31);
5800 date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
5801 assert(date == Date(-3, 5, 30));
5802 }
5803 }
5804
5805
5806 /++
5807 Adds the given number of units to this $(LREF Date). A negative number
5808 will subtract.
5809
5810 The difference between rolling and adding is that rolling does not
5811 affect larger units. For instance, rolling a $(LREF Date) one
5812 year's worth of days gets the exact same $(LREF Date).
5813
5814 The only accepted units are $(D "days").
5815
5816 Params:
5817 units = The units to add. Must be $(D "days").
5818 days = The number of days to add to this $(LREF Date).
5819 +/
5820 ref Date roll(string units)(long days) @safe pure nothrow @nogc
5821 if (units == "days")
5822 {
5823 immutable limit = maxDay(_year, _month);
5824 days %= limit;
5825 auto newDay = _day + days;
5826
5827 if (days < 0)
5828 {
5829 if (newDay < 1)
5830 newDay += limit;
5831 }
5832 else if (newDay > limit)
5833 newDay -= limit;
5834
5835 _day = cast(ubyte) newDay;
5836 return this;
5837 }
5838
5839 ///
5840 @safe unittest
5841 {
5842 auto d = Date(2010, 1, 1);
5843 d.roll!"days"(1);
5844 assert(d == Date(2010, 1, 2));
5845 d.roll!"days"(365);
5846 assert(d == Date(2010, 1, 26));
5847 d.roll!"days"(-32);
5848 assert(d == Date(2010, 1, 25));
5849 }
5850
5851 @safe unittest
5852 {
5853 // Test A.D.
5854 {
5855 auto date = Date(1999, 2, 28);
5856 date.roll!"days"(1);
5857 assert(date == Date(1999, 2, 1));
5858 date.roll!"days"(-1);
5859 assert(date == Date(1999, 2, 28));
5860 }
5861
5862 {
5863 auto date = Date(2000, 2, 28);
5864 date.roll!"days"(1);
5865 assert(date == Date(2000, 2, 29));
5866 date.roll!"days"(1);
5867 assert(date == Date(2000, 2, 1));
5868 date.roll!"days"(-1);
5869 assert(date == Date(2000, 2, 29));
5870 }
5871
5872 {
5873 auto date = Date(1999, 6, 30);
5874 date.roll!"days"(1);
5875 assert(date == Date(1999, 6, 1));
5876 date.roll!"days"(-1);
5877 assert(date == Date(1999, 6, 30));
5878 }
5879
5880 {
5881 auto date = Date(1999, 7, 31);
5882 date.roll!"days"(1);
5883 assert(date == Date(1999, 7, 1));
5884 date.roll!"days"(-1);
5885 assert(date == Date(1999, 7, 31));
5886 }
5887
5888 {
5889 auto date = Date(1999, 1, 1);
5890 date.roll!"days"(-1);
5891 assert(date == Date(1999, 1, 31));
5892 date.roll!"days"(1);
5893 assert(date == Date(1999, 1, 1));
5894 }
5895
5896 {
5897 auto date = Date(1999, 7, 6);
5898 date.roll!"days"(9);
5899 assert(date == Date(1999, 7, 15));
5900 date.roll!"days"(-11);
5901 assert(date == Date(1999, 7, 4));
5902 date.roll!"days"(30);
5903 assert(date == Date(1999, 7, 3));
5904 date.roll!"days"(-3);
5905 assert(date == Date(1999, 7, 31));
5906 }
5907
5908 {
5909 auto date = Date(1999, 7, 6);
5910 date.roll!"days"(365);
5911 assert(date == Date(1999, 7, 30));
5912 date.roll!"days"(-365);
5913 assert(date == Date(1999, 7, 6));
5914 date.roll!"days"(366);
5915 assert(date == Date(1999, 7, 31));
5916 date.roll!"days"(730);
5917 assert(date == Date(1999, 7, 17));
5918 date.roll!"days"(-1096);
5919 assert(date == Date(1999, 7, 6));
5920 }
5921
5922 {
5923 auto date = Date(1999, 2, 6);
5924 date.roll!"days"(365);
5925 assert(date == Date(1999, 2, 7));
5926 date.roll!"days"(-365);
5927 assert(date == Date(1999, 2, 6));
5928 date.roll!"days"(366);
5929 assert(date == Date(1999, 2, 8));
5930 date.roll!"days"(730);
5931 assert(date == Date(1999, 2, 10));
5932 date.roll!"days"(-1096);
5933 assert(date == Date(1999, 2, 6));
5934 }
5935
5936 // Test B.C.
5937 {
5938 auto date = Date(-1999, 2, 28);
5939 date.roll!"days"(1);
5940 assert(date == Date(-1999, 2, 1));
5941 date.roll!"days"(-1);
5942 assert(date == Date(-1999, 2, 28));
5943 }
5944
5945 {
5946 auto date = Date(-2000, 2, 28);
5947 date.roll!"days"(1);
5948 assert(date == Date(-2000, 2, 29));
5949 date.roll!"days"(1);
5950 assert(date == Date(-2000, 2, 1));
5951 date.roll!"days"(-1);
5952 assert(date == Date(-2000, 2, 29));
5953 }
5954
5955 {
5956 auto date = Date(-1999, 6, 30);
5957 date.roll!"days"(1);
5958 assert(date == Date(-1999, 6, 1));
5959 date.roll!"days"(-1);
5960 assert(date == Date(-1999, 6, 30));
5961 }
5962
5963 {
5964 auto date = Date(-1999, 7, 31);
5965 date.roll!"days"(1);
5966 assert(date == Date(-1999, 7, 1));
5967 date.roll!"days"(-1);
5968 assert(date == Date(-1999, 7, 31));
5969 }
5970
5971 {
5972 auto date = Date(-1999, 1, 1);
5973 date.roll!"days"(-1);
5974 assert(date == Date(-1999, 1, 31));
5975 date.roll!"days"(1);
5976 assert(date == Date(-1999, 1, 1));
5977 }
5978
5979 {
5980 auto date = Date(-1999, 7, 6);
5981 date.roll!"days"(9);
5982 assert(date == Date(-1999, 7, 15));
5983 date.roll!"days"(-11);
5984 assert(date == Date(-1999, 7, 4));
5985 date.roll!"days"(30);
5986 assert(date == Date(-1999, 7, 3));
5987 date.roll!"days"(-3);
5988 assert(date == Date(-1999, 7, 31));
5989 }
5990
5991 {
5992 auto date = Date(-1999, 7, 6);
5993 date.roll!"days"(365);
5994 assert(date == Date(-1999, 7, 30));
5995 date.roll!"days"(-365);
5996 assert(date == Date(-1999, 7, 6));
5997 date.roll!"days"(366);
5998 assert(date == Date(-1999, 7, 31));
5999 date.roll!"days"(730);
6000 assert(date == Date(-1999, 7, 17));
6001 date.roll!"days"(-1096);
6002 assert(date == Date(-1999, 7, 6));
6003 }
6004
6005 // Test Both
6006 {
6007 auto date = Date(1, 7, 6);
6008 date.roll!"days"(-365);
6009 assert(date == Date(1, 7, 13));
6010 date.roll!"days"(365);
6011 assert(date == Date(1, 7, 6));
6012 date.roll!"days"(-731);
6013 assert(date == Date(1, 7, 19));
6014 date.roll!"days"(730);
6015 assert(date == Date(1, 7, 5));
6016 }
6017
6018 {
6019 auto date = Date(0, 7, 6);
6020 date.roll!"days"(-365);
6021 assert(date == Date(0, 7, 13));
6022 date.roll!"days"(365);
6023 assert(date == Date(0, 7, 6));
6024 date.roll!"days"(-731);
6025 assert(date == Date(0, 7, 19));
6026 date.roll!"days"(730);
6027 assert(date == Date(0, 7, 5));
6028 }
6029
6030 {
6031 auto date = Date(0, 7, 6);
6032 date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
6033 assert(date == Date(0, 7, 8));
6034 }
6035
6036 const cdate = Date(1999, 7, 6);
6037 immutable idate = Date(1999, 7, 6);
6038 static assert(!__traits(compiles, cdate.roll!"days"(12)));
6039 static assert(!__traits(compiles, idate.roll!"days"(12)));
6040 }
6041
6042
6043 /++
6044 Gives the result of adding or subtracting a $(REF Duration, core,time)
6045 from
6046
6047 The legal types of arithmetic for $(LREF Date) using this operator are
6048
6049 $(BOOKTABLE,
6050 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date))
6051 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date))
6052 )
6053
6054 Params:
6055 duration = The $(REF Duration, core,time) to add to or subtract from
6056 this $(LREF Date).
6057 +/
6058 Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
6059 if (op == "+" || op == "-")
6060 {
6061 Date retval = this;
6062 immutable days = duration.total!"days";
6063 mixin("return retval._addDays(" ~ op ~ "days);");
6064 }
6065
6066 ///
6067 @safe unittest
6068 {
6069 import core.time : days;
6070
6071 assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1));
6072 assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1));
6073
6074 assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31));
6075 assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26));
6076 }
6077
6078 @safe unittest
6079 {
6080 auto date = Date(1999, 7, 6);
6081
6082 assert(date + dur!"weeks"(7) == Date(1999, 8, 24));
6083 assert(date + dur!"weeks"(-7) == Date(1999, 5, 18));
6084 assert(date + dur!"days"(7) == Date(1999, 7, 13));
6085 assert(date + dur!"days"(-7) == Date(1999, 6, 29));
6086
6087 assert(date + dur!"hours"(24) == Date(1999, 7, 7));
6088 assert(date + dur!"hours"(-24) == Date(1999, 7, 5));
6089 assert(date + dur!"minutes"(1440) == Date(1999, 7, 7));
6090 assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5));
6091 assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7));
6092 assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5));
6093 assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
6094 assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
6095 assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
6096 assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
6097 assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
6098 assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5));
6099
6100 assert(date - dur!"weeks"(-7) == Date(1999, 8, 24));
6101 assert(date - dur!"weeks"(7) == Date(1999, 5, 18));
6102 assert(date - dur!"days"(-7) == Date(1999, 7, 13));
6103 assert(date - dur!"days"(7) == Date(1999, 6, 29));
6104
6105 assert(date - dur!"hours"(-24) == Date(1999, 7, 7));
6106 assert(date - dur!"hours"(24) == Date(1999, 7, 5));
6107 assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7));
6108 assert(date - dur!"minutes"(1440) == Date(1999, 7, 5));
6109 assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7));
6110 assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5));
6111 assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
6112 assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
6113 assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
6114 assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
6115 assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
6116 assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5));
6117
6118 auto duration = dur!"days"(12);
6119 const cdate = Date(1999, 7, 6);
6120 immutable idate = Date(1999, 7, 6);
6121 assert(date + duration == Date(1999, 7, 18));
6122 assert(cdate + duration == Date(1999, 7, 18));
6123 assert(idate + duration == Date(1999, 7, 18));
6124
6125 assert(date - duration == Date(1999, 6, 24));
6126 assert(cdate - duration == Date(1999, 6, 24));
6127 assert(idate - duration == Date(1999, 6, 24));
6128 }
6129
6130 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
6131 deprecated("Use Duration instead of TickDuration.")
6132 Date opBinary(string op)(TickDuration td) const @safe pure nothrow @nogc
6133 if (op == "+" || op == "-")
6134 {
6135 Date retval = this;
6136 immutable days = convert!("hnsecs", "days")(td.hnsecs);
6137 mixin("return retval._addDays(" ~ op ~ "days);");
6138 }
6139
6140 deprecated @safe unittest
6141 {
6142 // This probably only runs in cases where gettimeofday() is used, but it's
6143 // hard to do this test correctly with variable ticksPerSec.
6144 if (TickDuration.ticksPerSec == 1_000_000)
6145 {
6146 auto date = Date(1999, 7, 6);
6147
6148 assert(date + TickDuration.from!"usecs"(86_400_000_000) == Date(1999, 7, 7));
6149 assert(date + TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
6150
6151 assert(date - TickDuration.from!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
6152 assert(date - TickDuration.from!"usecs"(86_400_000_000) == Date(1999, 7, 5));
6153 }
6154 }
6155
6156
6157 /++
6158 Gives the result of adding or subtracting a $(REF Duration, core,time)
6159 from this $(LREF Date), as well as assigning the result to this
6160 $(LREF Date).
6161
6162 The legal types of arithmetic for $(LREF Date) using this operator are
6163
6164 $(BOOKTABLE,
6165 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date))
6166 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date))
6167 )
6168
6169 Params:
6170 duration = The $(REF Duration, core,time) to add to or subtract from
6171 this $(LREF Date).
6172 +/
6173 ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
6174 if (op == "+" || op == "-")
6175 {
6176 immutable days = duration.total!"days";
6177 mixin("return _addDays(" ~ op ~ "days);");
6178 }
6179
6180 @safe unittest
6181 {
6182 assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24));
6183 assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18));
6184 assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13));
6185 assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29));
6186
6187 assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7));
6188 assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5));
6189 assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7));
6190 assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5));
6191 assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7));
6192 assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5));
6193 assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
6194 assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
6195 assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
6196 assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
6197 assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
6198 assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5));
6199
6200 assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24));
6201 assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18));
6202 assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13));
6203 assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29));
6204
6205 assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7));
6206 assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5));
6207 assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7));
6208 assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5));
6209 assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7));
6210 assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5));
6211 assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
6212 assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
6213 assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
6214 assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
6215 assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
6216 assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5));
6217
6218 {
6219 auto date = Date(0, 1, 31);
6220 (date += dur!"days"(507)) += dur!"days"(-2);
6221 assert(date == Date(1, 6, 19));
6222 }
6223
6224 auto duration = dur!"days"(12);
6225 auto date = Date(1999, 7, 6);
6226 const cdate = Date(1999, 7, 6);
6227 immutable idate = Date(1999, 7, 6);
6228 date += duration;
6229 static assert(!__traits(compiles, cdate += duration));
6230 static assert(!__traits(compiles, idate += duration));
6231
6232 date -= duration;
6233 static assert(!__traits(compiles, cdate -= duration));
6234 static assert(!__traits(compiles, idate -= duration));
6235 }
6236
6237 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
6238 deprecated("Use Duration instead of TickDuration.")
6239 ref Date opOpAssign(string op)(TickDuration td) @safe pure nothrow @nogc
6240 if (op == "+" || op == "-")
6241 {
6242 immutable days = convert!("seconds", "days")(td.seconds);
6243 mixin("return _addDays(" ~ op ~ "days);");
6244 }
6245
6246 deprecated @safe unittest
6247 {
6248 // This probably only runs in cases where gettimeofday() is used, but it's
6249 // hard to do this test correctly with variable ticksPerSec.
6250 if (TickDuration.ticksPerSec == 1_000_000)
6251 {
6252 {
6253 auto date = Date(1999, 7, 6);
6254 date += TickDuration.from!"usecs"(86_400_000_000);
6255 assert(date == Date(1999, 7, 7));
6256 }
6257
6258 {
6259 auto date = Date(1999, 7, 6);
6260 date += TickDuration.from!"usecs"(-86_400_000_000);
6261 assert(date == Date(1999, 7, 5));
6262 }
6263
6264 {
6265 auto date = Date(1999, 7, 6);
6266 date -= TickDuration.from!"usecs"(-86_400_000_000);
6267 assert(date == Date(1999, 7, 7));
6268 }
6269
6270 {
6271 auto date = Date(1999, 7, 6);
6272 date -= TickDuration.from!"usecs"(86_400_000_000);
6273 assert(date == Date(1999, 7, 5));
6274 }
6275 }
6276 }
6277
6278
6279 /++
6280 Gives the difference between two $(LREF Date)s.
6281
6282 The legal types of arithmetic for $(LREF Date) using this operator are
6283
6284 $(BOOKTABLE,
6285 $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration))
6286 )
6287 +/
6288 Duration opBinary(string op)(in Date rhs) const @safe pure nothrow @nogc
6289 if (op == "-")
6290 {
6291 return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
6292 }
6293
6294 @safe unittest
6295 {
6296 auto date = Date(1999, 7, 6);
6297
6298 assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365));
6299 assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365));
6300 assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31));
6301 assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31));
6302 assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1));
6303 assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1));
6304
6305 const cdate = Date(1999, 7, 6);
6306 immutable idate = Date(1999, 7, 6);
6307 assert(date - date == Duration.zero);
6308 assert(cdate - date == Duration.zero);
6309 assert(idate - date == Duration.zero);
6310
6311 assert(date - cdate == Duration.zero);
6312 assert(cdate - cdate == Duration.zero);
6313 assert(idate - cdate == Duration.zero);
6314
6315 assert(date - idate == Duration.zero);
6316 assert(cdate - idate == Duration.zero);
6317 assert(idate - idate == Duration.zero);
6318 }
6319
6320
6321 /++
6322 Returns the difference between the two $(LREF Date)s in months.
6323
6324 To get the difference in years, subtract the year property
6325 of two $(LREF Date)s. To get the difference in days or weeks,
6326 subtract the $(LREF Date)s themselves and use the
6327 $(REF Duration, core,time) that results. Because converting between
6328 months and smaller units requires a specific date (which
6329 $(REF Duration, core,time)s don't have), getting the difference in
6330 months requires some math using both the year and month properties, so
6331 this is a convenience function for getting the difference in months.
6332
6333 Note that the number of days in the months or how far into the month
6334 either $(LREF Date) is is irrelevant. It is the difference in the month
6335 property combined with the difference in years * 12. So, for instance,
6336 December 31st and January 1st are one month apart just as December 1st
6337 and January 31st are one month apart.
6338
6339 Params:
6340 rhs = The $(LREF Date) to subtract from this one.
6341 +/
6342 int diffMonths(in Date rhs) const @safe pure nothrow @nogc
6343 {
6344 immutable yearDiff = _year - rhs._year;
6345 immutable monthDiff = _month - rhs._month;
6346
6347 return yearDiff * 12 + monthDiff;
6348 }
6349
6350 ///
6351 @safe unittest
6352 {
6353 assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1);
6354 assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1);
6355 assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2);
6356 assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2);
6357 }
6358
6359 @safe unittest
6360 {
6361 auto date = Date(1999, 7, 6);
6362
6363 // Test A.D.
6364 assert(date.diffMonths(Date(1998, 6, 5)) == 13);
6365 assert(date.diffMonths(Date(1998, 7, 5)) == 12);
6366 assert(date.diffMonths(Date(1998, 8, 5)) == 11);
6367 assert(date.diffMonths(Date(1998, 9, 5)) == 10);
6368 assert(date.diffMonths(Date(1998, 10, 5)) == 9);
6369 assert(date.diffMonths(Date(1998, 11, 5)) == 8);
6370 assert(date.diffMonths(Date(1998, 12, 5)) == 7);
6371 assert(date.diffMonths(Date(1999, 1, 5)) == 6);
6372 assert(date.diffMonths(Date(1999, 2, 6)) == 5);
6373 assert(date.diffMonths(Date(1999, 3, 6)) == 4);
6374 assert(date.diffMonths(Date(1999, 4, 6)) == 3);
6375 assert(date.diffMonths(Date(1999, 5, 6)) == 2);
6376 assert(date.diffMonths(Date(1999, 6, 6)) == 1);
6377 assert(date.diffMonths(date) == 0);
6378 assert(date.diffMonths(Date(1999, 8, 6)) == -1);
6379 assert(date.diffMonths(Date(1999, 9, 6)) == -2);
6380 assert(date.diffMonths(Date(1999, 10, 6)) == -3);
6381 assert(date.diffMonths(Date(1999, 11, 6)) == -4);
6382 assert(date.diffMonths(Date(1999, 12, 6)) == -5);
6383 assert(date.diffMonths(Date(2000, 1, 6)) == -6);
6384 assert(date.diffMonths(Date(2000, 2, 6)) == -7);
6385 assert(date.diffMonths(Date(2000, 3, 6)) == -8);
6386 assert(date.diffMonths(Date(2000, 4, 6)) == -9);
6387 assert(date.diffMonths(Date(2000, 5, 6)) == -10);
6388 assert(date.diffMonths(Date(2000, 6, 6)) == -11);
6389 assert(date.diffMonths(Date(2000, 7, 6)) == -12);
6390 assert(date.diffMonths(Date(2000, 8, 6)) == -13);
6391
6392 assert(Date(1998, 6, 5).diffMonths(date) == -13);
6393 assert(Date(1998, 7, 5).diffMonths(date) == -12);
6394 assert(Date(1998, 8, 5).diffMonths(date) == -11);
6395 assert(Date(1998, 9, 5).diffMonths(date) == -10);
6396 assert(Date(1998, 10, 5).diffMonths(date) == -9);
6397 assert(Date(1998, 11, 5).diffMonths(date) == -8);
6398 assert(Date(1998, 12, 5).diffMonths(date) == -7);
6399 assert(Date(1999, 1, 5).diffMonths(date) == -6);
6400 assert(Date(1999, 2, 6).diffMonths(date) == -5);
6401 assert(Date(1999, 3, 6).diffMonths(date) == -4);
6402 assert(Date(1999, 4, 6).diffMonths(date) == -3);
6403 assert(Date(1999, 5, 6).diffMonths(date) == -2);
6404 assert(Date(1999, 6, 6).diffMonths(date) == -1);
6405 assert(Date(1999, 8, 6).diffMonths(date) == 1);
6406 assert(Date(1999, 9, 6).diffMonths(date) == 2);
6407 assert(Date(1999, 10, 6).diffMonths(date) == 3);
6408 assert(Date(1999, 11, 6).diffMonths(date) == 4);
6409 assert(Date(1999, 12, 6).diffMonths(date) == 5);
6410 assert(Date(2000, 1, 6).diffMonths(date) == 6);
6411 assert(Date(2000, 2, 6).diffMonths(date) == 7);
6412 assert(Date(2000, 3, 6).diffMonths(date) == 8);
6413 assert(Date(2000, 4, 6).diffMonths(date) == 9);
6414 assert(Date(2000, 5, 6).diffMonths(date) == 10);
6415 assert(Date(2000, 6, 6).diffMonths(date) == 11);
6416 assert(Date(2000, 7, 6).diffMonths(date) == 12);
6417 assert(Date(2000, 8, 6).diffMonths(date) == 13);
6418
6419 assert(date.diffMonths(Date(1999, 6, 30)) == 1);
6420 assert(date.diffMonths(Date(1999, 7, 1)) == 0);
6421 assert(date.diffMonths(Date(1999, 7, 6)) == 0);
6422 assert(date.diffMonths(Date(1999, 7, 11)) == 0);
6423 assert(date.diffMonths(Date(1999, 7, 16)) == 0);
6424 assert(date.diffMonths(Date(1999, 7, 21)) == 0);
6425 assert(date.diffMonths(Date(1999, 7, 26)) == 0);
6426 assert(date.diffMonths(Date(1999, 7, 31)) == 0);
6427 assert(date.diffMonths(Date(1999, 8, 1)) == -1);
6428
6429 assert(date.diffMonths(Date(1990, 6, 30)) == 109);
6430 assert(date.diffMonths(Date(1990, 7, 1)) == 108);
6431 assert(date.diffMonths(Date(1990, 7, 6)) == 108);
6432 assert(date.diffMonths(Date(1990, 7, 11)) == 108);
6433 assert(date.diffMonths(Date(1990, 7, 16)) == 108);
6434 assert(date.diffMonths(Date(1990, 7, 21)) == 108);
6435 assert(date.diffMonths(Date(1990, 7, 26)) == 108);
6436 assert(date.diffMonths(Date(1990, 7, 31)) == 108);
6437 assert(date.diffMonths(Date(1990, 8, 1)) == 107);
6438
6439 assert(Date(1999, 6, 30).diffMonths(date) == -1);
6440 assert(Date(1999, 7, 1).diffMonths(date) == 0);
6441 assert(Date(1999, 7, 6).diffMonths(date) == 0);
6442 assert(Date(1999, 7, 11).diffMonths(date) == 0);
6443 assert(Date(1999, 7, 16).diffMonths(date) == 0);
6444 assert(Date(1999, 7, 21).diffMonths(date) == 0);
6445 assert(Date(1999, 7, 26).diffMonths(date) == 0);
6446 assert(Date(1999, 7, 31).diffMonths(date) == 0);
6447 assert(Date(1999, 8, 1).diffMonths(date) == 1);
6448
6449 assert(Date(1990, 6, 30).diffMonths(date) == -109);
6450 assert(Date(1990, 7, 1).diffMonths(date) == -108);
6451 assert(Date(1990, 7, 6).diffMonths(date) == -108);
6452 assert(Date(1990, 7, 11).diffMonths(date) == -108);
6453 assert(Date(1990, 7, 16).diffMonths(date) == -108);
6454 assert(Date(1990, 7, 21).diffMonths(date) == -108);
6455 assert(Date(1990, 7, 26).diffMonths(date) == -108);
6456 assert(Date(1990, 7, 31).diffMonths(date) == -108);
6457 assert(Date(1990, 8, 1).diffMonths(date) == -107);
6458
6459 // Test B.C.
6460 auto dateBC = Date(-1999, 7, 6);
6461
6462 assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13);
6463 assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12);
6464 assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11);
6465 assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10);
6466 assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9);
6467 assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8);
6468 assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7);
6469 assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6);
6470 assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5);
6471 assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4);
6472 assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3);
6473 assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2);
6474 assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1);
6475 assert(dateBC.diffMonths(dateBC) == 0);
6476 assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1);
6477 assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2);
6478 assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3);
6479 assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4);
6480 assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5);
6481 assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6);
6482 assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7);
6483 assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8);
6484 assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9);
6485 assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10);
6486 assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11);
6487 assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12);
6488 assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13);
6489
6490 assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13);
6491 assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12);
6492 assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11);
6493 assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10);
6494 assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9);
6495 assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8);
6496 assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7);
6497 assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6);
6498 assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5);
6499 assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4);
6500 assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3);
6501 assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2);
6502 assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1);
6503 assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1);
6504 assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2);
6505 assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3);
6506 assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4);
6507 assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5);
6508 assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6);
6509 assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7);
6510 assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8);
6511 assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9);
6512 assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10);
6513 assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11);
6514 assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12);
6515 assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13);
6516
6517 assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1);
6518 assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0);
6519 assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0);
6520 assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0);
6521 assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0);
6522 assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0);
6523 assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0);
6524 assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0);
6525 assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1);
6526
6527 assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109);
6528 assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108);
6529 assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108);
6530 assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108);
6531 assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108);
6532 assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108);
6533 assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108);
6534 assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108);
6535 assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107);
6536
6537 assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1);
6538 assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0);
6539 assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0);
6540 assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0);
6541 assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0);
6542 assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0);
6543 assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0);
6544 assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0);
6545 assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1);
6546
6547 assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109);
6548 assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108);
6549 assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108);
6550 assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108);
6551 assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108);
6552 assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108);
6553 assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108);
6554 assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108);
6555 assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107);
6556
6557 // Test Both
6558 assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94);
6559 assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94);
6560
6561 const cdate = Date(1999, 7, 6);
6562 immutable idate = Date(1999, 7, 6);
6563 assert(date.diffMonths(date) == 0);
6564 assert(cdate.diffMonths(date) == 0);
6565 assert(idate.diffMonths(date) == 0);
6566
6567 assert(date.diffMonths(cdate) == 0);
6568 assert(cdate.diffMonths(cdate) == 0);
6569 assert(idate.diffMonths(cdate) == 0);
6570
6571 assert(date.diffMonths(idate) == 0);
6572 assert(cdate.diffMonths(idate) == 0);
6573 assert(idate.diffMonths(idate) == 0);
6574 }
6575
6576
6577 /++
6578 Whether this $(LREF Date) is in a leap year.
6579 +/
6580 @property bool isLeapYear() const @safe pure nothrow @nogc
6581 {
6582 return yearIsLeapYear(_year);
6583 }
6584
6585 @safe unittest
6586 {
6587 auto date = Date(1999, 7, 6);
6588 const cdate = Date(1999, 7, 6);
6589 immutable idate = Date(1999, 7, 6);
6590 static assert(!__traits(compiles, date.isLeapYear = true));
6591 static assert(!__traits(compiles, cdate.isLeapYear = true));
6592 static assert(!__traits(compiles, idate.isLeapYear = true));
6593 }
6594
6595
6596 /++
6597 Day of the week this $(LREF Date) is on.
6598 +/
6599 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc
6600 {
6601 return getDayOfWeek(dayOfGregorianCal);
6602 }
6603
6604 @safe unittest
6605 {
6606 const cdate = Date(1999, 7, 6);
6607 immutable idate = Date(1999, 7, 6);
6608 assert(cdate.dayOfWeek == DayOfWeek.tue);
6609 static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun));
6610 assert(idate.dayOfWeek == DayOfWeek.tue);
6611 static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun));
6612 }
6613
6614
6615 /++
6616 Day of the year this $(LREF Date) is on.
6617 +/
6618 @property ushort dayOfYear() const @safe pure nothrow @nogc
6619 {
6620 if (_month >= Month.jan && _month <= Month.dec)
6621 {
6622 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
6623 auto monthIndex = _month - Month.jan;
6624
6625 return cast(ushort)(lastDay[monthIndex] + _day);
6626 }
6627 assert(0, "Invalid month.");
6628 }
6629
6630 ///
6631 @safe unittest
6632 {
6633 assert(Date(1999, 1, 1).dayOfYear == 1);
6634 assert(Date(1999, 12, 31).dayOfYear == 365);
6635 assert(Date(2000, 12, 31).dayOfYear == 366);
6636 }
6637
6638 @safe unittest
6639 {
6640 import std.algorithm.iteration : filter;
6641 import std.range : chain;
6642
6643 foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD)))
6644 {
6645 foreach (doy; testDaysOfYear)
6646 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day);
6647 }
6648
6649 foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD)))
6650 {
6651 foreach (doy; testDaysOfLeapYear)
6652 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day);
6653 }
6654
6655 const cdate = Date(1999, 7, 6);
6656 immutable idate = Date(1999, 7, 6);
6657 assert(cdate.dayOfYear == 187);
6658 assert(idate.dayOfYear == 187);
6659 }
6660
6661 /++
6662 Day of the year.
6663
6664 Params:
6665 day = The day of the year to set which day of the year this
6666 $(LREF Date) is on.
6667
6668 Throws:
6669 $(REF DateTimeException,std,datetime,date) if the given day is an
6670 invalid day of the year.
6671 +/
6672 @property void dayOfYear(int day) @safe pure
6673 {
6674 setDayOfYear!true(day);
6675 }
6676
6677 private void setDayOfYear(bool useExceptions = false)(int day)
6678 {
6679 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
6680
6681 bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear);
6682 enum errorMsg = "Invalid day of the year.";
6683
6684 static if (useExceptions)
6685 {
6686 if (dayOutOfRange) throw new DateTimeException(errorMsg);
6687 }
6688 else
6689 {
6690 assert(!dayOutOfRange, errorMsg);
6691 }
6692
6693 foreach (i; 1 .. lastDay.length)
6694 {
6695 if (day <= lastDay[i])
6696 {
6697 _month = cast(Month)(cast(int) Month.jan + i - 1);
6698 _day = cast(ubyte)(day - lastDay[i - 1]);
6699 return;
6700 }
6701 }
6702 assert(0, "Invalid day of the year.");
6703 }
6704
6705 @safe unittest
6706 {
6707 static void test(Date date, int day, MonthDay expected, size_t line = __LINE__)
6708 {
6709 date.dayOfYear = day;
6710 assert(date.month == expected.month);
6711 assert(date.day == expected.day);
6712 }
6713
6714 foreach (doy; testDaysOfYear)
6715 {
6716 test(Date(1999, 1, 1), doy.day, doy.md);
6717 test(Date(-1, 1, 1), doy.day, doy.md);
6718 }
6719
6720 foreach (doy; testDaysOfLeapYear)
6721 {
6722 test(Date(2000, 1, 1), doy.day, doy.md);
6723 test(Date(-4, 1, 1), doy.day, doy.md);
6724 }
6725
6726 const cdate = Date(1999, 7, 6);
6727 immutable idate = Date(1999, 7, 6);
6728 static assert(!__traits(compiles, cdate.dayOfYear = 187));
6729 static assert(!__traits(compiles, idate.dayOfYear = 187));
6730 }
6731
6732
6733 /++
6734 The Xth day of the Gregorian Calendar that this $(LREF Date) is on.
6735 +/
6736 @property int dayOfGregorianCal() const @safe pure nothrow @nogc
6737 {
6738 if (isAD)
6739 {
6740 if (_year == 1)
6741 return dayOfYear;
6742
6743 int years = _year - 1;
6744 auto days = (years / 400) * daysIn400Years;
6745 years %= 400;
6746
6747 days += (years / 100) * daysIn100Years;
6748 years %= 100;
6749
6750 days += (years / 4) * daysIn4Years;
6751 years %= 4;
6752
6753 days += years * daysInYear;
6754
6755 days += dayOfYear;
6756
6757 return days;
6758 }
6759 else if (_year == 0)
6760 return dayOfYear - daysInLeapYear;
6761 else
6762 {
6763 int years = _year;
6764 auto days = (years / 400) * daysIn400Years;
6765 years %= 400;
6766
6767 days += (years / 100) * daysIn100Years;
6768 years %= 100;
6769
6770 days += (years / 4) * daysIn4Years;
6771 years %= 4;
6772
6773 if (years < 0)
6774 {
6775 days -= daysInLeapYear;
6776 ++years;
6777
6778 days += years * daysInYear;
6779
6780 days -= daysInYear - dayOfYear;
6781 }
6782 else
6783 days -= daysInLeapYear - dayOfYear;
6784
6785 return days;
6786 }
6787 }
6788
6789 ///
6790 @safe unittest
6791 {
6792 assert(Date(1, 1, 1).dayOfGregorianCal == 1);
6793 assert(Date(1, 12, 31).dayOfGregorianCal == 365);
6794 assert(Date(2, 1, 1).dayOfGregorianCal == 366);
6795
6796 assert(Date(0, 12, 31).dayOfGregorianCal == 0);
6797 assert(Date(0, 1, 1).dayOfGregorianCal == -365);
6798 assert(Date(-1, 12, 31).dayOfGregorianCal == -366);
6799
6800 assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120);
6801 assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137);
6802 }
6803
6804 @safe unittest
6805 {
6806 import std.range : chain;
6807
6808 foreach (gd; chain(testGregDaysBC, testGregDaysAD))
6809 assert(gd.date.dayOfGregorianCal == gd.day);
6810
6811 auto date = Date(1999, 7, 6);
6812 const cdate = Date(1999, 7, 6);
6813 immutable idate = Date(1999, 7, 6);
6814 assert(date.dayOfGregorianCal == 729_941);
6815 assert(cdate.dayOfGregorianCal == 729_941);
6816 assert(idate.dayOfGregorianCal == 729_941);
6817 }
6818
6819 /++
6820 The Xth day of the Gregorian Calendar that this $(LREF Date) is on.
6821
6822 Params:
6823 day = The day of the Gregorian Calendar to set this $(LREF Date) to.
6824 +/
6825 @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc
6826 {
6827 this = Date(day);
6828 }
6829
6830 ///
6831 @safe unittest
6832 {
6833 auto date = Date.init;
6834 date.dayOfGregorianCal = 1;
6835 assert(date == Date(1, 1, 1));
6836
6837 date.dayOfGregorianCal = 365;
6838 assert(date == Date(1, 12, 31));
6839
6840 date.dayOfGregorianCal = 366;
6841 assert(date == Date(2, 1, 1));
6842
6843 date.dayOfGregorianCal = 0;
6844 assert(date == Date(0, 12, 31));
6845
6846 date.dayOfGregorianCal = -365;
6847 assert(date == Date(-0, 1, 1));
6848
6849 date.dayOfGregorianCal = -366;
6850 assert(date == Date(-1, 12, 31));
6851
6852 date.dayOfGregorianCal = 730_120;
6853 assert(date == Date(2000, 1, 1));
6854
6855 date.dayOfGregorianCal = 734_137;
6856 assert(date == Date(2010, 12, 31));
6857 }
6858
6859 @safe unittest
6860 {
6861 auto date = Date(1999, 7, 6);
6862 const cdate = Date(1999, 7, 6);
6863 immutable idate = Date(1999, 7, 6);
6864 date.dayOfGregorianCal = 187;
6865 assert(date.dayOfGregorianCal == 187);
6866 static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187));
6867 static assert(!__traits(compiles, idate.dayOfGregorianCal = 187));
6868 }
6869
6870
6871 /++
6872 The ISO 8601 week of the year that this $(LREF Date) is in.
6873
6874 See_Also:
6875 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
6876 +/
6877 @property ubyte isoWeek() const @safe pure nothrow
6878 {
6879 immutable weekday = dayOfWeek;
6880 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday;
6881 immutable week = (dayOfYear - adjustedWeekday + 10) / 7;
6882
6883 try
6884 {
6885 if (week == 53)
6886 {
6887 switch (Date(_year + 1, 1, 1).dayOfWeek)
6888 {
6889 case DayOfWeek.mon:
6890 case DayOfWeek.tue:
6891 case DayOfWeek.wed:
6892 case DayOfWeek.thu:
6893 return 1;
6894 case DayOfWeek.fri:
6895 case DayOfWeek.sat:
6896 case DayOfWeek.sun:
6897 return 53;
6898 default:
6899 assert(0, "Invalid ISO Week");
6900 }
6901 }
6902 else if (week > 0)
6903 return cast(ubyte) week;
6904 else
6905 return Date(_year - 1, 12, 31).isoWeek;
6906 }
6907 catch (Exception e)
6908 assert(0, "Date's constructor threw.");
6909 }
6910
6911 @safe unittest
6912 {
6913 // Test A.D.
6914 assert(Date(2009, 12, 28).isoWeek == 53);
6915 assert(Date(2009, 12, 29).isoWeek == 53);
6916 assert(Date(2009, 12, 30).isoWeek == 53);
6917 assert(Date(2009, 12, 31).isoWeek == 53);
6918 assert(Date(2010, 1, 1).isoWeek == 53);
6919 assert(Date(2010, 1, 2).isoWeek == 53);
6920 assert(Date(2010, 1, 3).isoWeek == 53);
6921 assert(Date(2010, 1, 4).isoWeek == 1);
6922 assert(Date(2010, 1, 5).isoWeek == 1);
6923 assert(Date(2010, 1, 6).isoWeek == 1);
6924 assert(Date(2010, 1, 7).isoWeek == 1);
6925 assert(Date(2010, 1, 8).isoWeek == 1);
6926 assert(Date(2010, 1, 9).isoWeek == 1);
6927 assert(Date(2010, 1, 10).isoWeek == 1);
6928 assert(Date(2010, 1, 11).isoWeek == 2);
6929 assert(Date(2010, 12, 31).isoWeek == 52);
6930
6931 assert(Date(2004, 12, 26).isoWeek == 52);
6932 assert(Date(2004, 12, 27).isoWeek == 53);
6933 assert(Date(2004, 12, 28).isoWeek == 53);
6934 assert(Date(2004, 12, 29).isoWeek == 53);
6935 assert(Date(2004, 12, 30).isoWeek == 53);
6936 assert(Date(2004, 12, 31).isoWeek == 53);
6937 assert(Date(2005, 1, 1).isoWeek == 53);
6938 assert(Date(2005, 1, 2).isoWeek == 53);
6939
6940 assert(Date(2005, 12, 31).isoWeek == 52);
6941 assert(Date(2007, 1, 1).isoWeek == 1);
6942
6943 assert(Date(2007, 12, 30).isoWeek == 52);
6944 assert(Date(2007, 12, 31).isoWeek == 1);
6945 assert(Date(2008, 1, 1).isoWeek == 1);
6946
6947 assert(Date(2008, 12, 28).isoWeek == 52);
6948 assert(Date(2008, 12, 29).isoWeek == 1);
6949 assert(Date(2008, 12, 30).isoWeek == 1);
6950 assert(Date(2008, 12, 31).isoWeek == 1);
6951 assert(Date(2009, 1, 1).isoWeek == 1);
6952 assert(Date(2009, 1, 2).isoWeek == 1);
6953 assert(Date(2009, 1, 3).isoWeek == 1);
6954 assert(Date(2009, 1, 4).isoWeek == 1);
6955
6956 // Test B.C.
6957 // The algorithm should work identically for both A.D. and B.C. since
6958 // it doesn't really take the year into account, so B.C. testing
6959 // probably isn't really needed.
6960 assert(Date(0, 12, 31).isoWeek == 52);
6961 assert(Date(0, 1, 4).isoWeek == 1);
6962 assert(Date(0, 1, 1).isoWeek == 52);
6963
6964 const cdate = Date(1999, 7, 6);
6965 immutable idate = Date(1999, 7, 6);
6966 assert(cdate.isoWeek == 27);
6967 static assert(!__traits(compiles, cdate.isoWeek = 3));
6968 assert(idate.isoWeek == 27);
6969 static assert(!__traits(compiles, idate.isoWeek = 3));
6970 }
6971
6972
6973 /++
6974 $(LREF Date) for the last day in the month that this $(LREF Date) is in.
6975 +/
6976 @property Date endOfMonth() const @safe pure nothrow
6977 {
6978 try
6979 return Date(_year, _month, maxDay(_year, _month));
6980 catch (Exception e)
6981 assert(0, "Date's constructor threw.");
6982 }
6983
6984 ///
6985 @safe unittest
6986 {
6987 assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31));
6988 assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28));
6989 assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29));
6990 assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30));
6991 }
6992
6993 @safe unittest
6994 {
6995 // Test A.D.
6996 assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31));
6997 assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28));
6998 assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29));
6999 assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31));
7000 assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30));
7001 assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31));
7002 assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30));
7003 assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31));
7004 assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31));
7005 assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30));
7006 assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31));
7007 assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30));
7008 assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31));
7009
7010 // Test B.C.
7011 assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31));
7012 assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28));
7013 assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29));
7014 assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31));
7015 assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30));
7016 assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31));
7017 assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30));
7018 assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31));
7019 assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31));
7020 assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30));
7021 assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31));
7022 assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30));
7023 assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31));
7024
7025 const cdate = Date(1999, 7, 6);
7026 immutable idate = Date(1999, 7, 6);
7027 static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30)));
7028 static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30)));
7029 }
7030
7031
7032 /++
7033 The last day in the month that this $(LREF Date) is in.
7034 +/
7035 @property ubyte daysInMonth() const @safe pure nothrow @nogc
7036 {
7037 return maxDay(_year, _month);
7038 }
7039
7040 ///
7041 @safe unittest
7042 {
7043 assert(Date(1999, 1, 6).daysInMonth == 31);
7044 assert(Date(1999, 2, 7).daysInMonth == 28);
7045 assert(Date(2000, 2, 7).daysInMonth == 29);
7046 assert(Date(2000, 6, 4).daysInMonth == 30);
7047 }
7048
7049 @safe unittest
7050 {
7051 // Test A.D.
7052 assert(Date(1999, 1, 1).daysInMonth == 31);
7053 assert(Date(1999, 2, 1).daysInMonth == 28);
7054 assert(Date(2000, 2, 1).daysInMonth == 29);
7055 assert(Date(1999, 3, 1).daysInMonth == 31);
7056 assert(Date(1999, 4, 1).daysInMonth == 30);
7057 assert(Date(1999, 5, 1).daysInMonth == 31);
7058 assert(Date(1999, 6, 1).daysInMonth == 30);
7059 assert(Date(1999, 7, 1).daysInMonth == 31);
7060 assert(Date(1999, 8, 1).daysInMonth == 31);
7061 assert(Date(1999, 9, 1).daysInMonth == 30);
7062 assert(Date(1999, 10, 1).daysInMonth == 31);
7063 assert(Date(1999, 11, 1).daysInMonth == 30);
7064 assert(Date(1999, 12, 1).daysInMonth == 31);
7065
7066 // Test B.C.
7067 assert(Date(-1999, 1, 1).daysInMonth == 31);
7068 assert(Date(-1999, 2, 1).daysInMonth == 28);
7069 assert(Date(-2000, 2, 1).daysInMonth == 29);
7070 assert(Date(-1999, 3, 1).daysInMonth == 31);
7071 assert(Date(-1999, 4, 1).daysInMonth == 30);
7072 assert(Date(-1999, 5, 1).daysInMonth == 31);
7073 assert(Date(-1999, 6, 1).daysInMonth == 30);
7074 assert(Date(-1999, 7, 1).daysInMonth == 31);
7075 assert(Date(-1999, 8, 1).daysInMonth == 31);
7076 assert(Date(-1999, 9, 1).daysInMonth == 30);
7077 assert(Date(-1999, 10, 1).daysInMonth == 31);
7078 assert(Date(-1999, 11, 1).daysInMonth == 30);
7079 assert(Date(-1999, 12, 1).daysInMonth == 31);
7080
7081 const cdate = Date(1999, 7, 6);
7082 immutable idate = Date(1999, 7, 6);
7083 static assert(!__traits(compiles, cdate.daysInMonth = 30));
7084 static assert(!__traits(compiles, idate.daysInMonth = 30));
7085 }
7086
7087
7088 /++
7089 Whether the current year is a date in A.D.
7090 +/
7091 @property bool isAD() const @safe pure nothrow @nogc
7092 {
7093 return _year > 0;
7094 }
7095
7096 ///
7097 @safe unittest
7098 {
7099 assert(Date(1, 1, 1).isAD);
7100 assert(Date(2010, 12, 31).isAD);
7101 assert(!Date(0, 12, 31).isAD);
7102 assert(!Date(-2010, 1, 1).isAD);
7103 }
7104
7105 @safe unittest
7106 {
7107 assert(Date(2010, 7, 4).isAD);
7108 assert(Date(1, 1, 1).isAD);
7109 assert(!Date(0, 1, 1).isAD);
7110 assert(!Date(-1, 1, 1).isAD);
7111 assert(!Date(-2010, 7, 4).isAD);
7112
7113 const cdate = Date(1999, 7, 6);
7114 immutable idate = Date(1999, 7, 6);
7115 assert(cdate.isAD);
7116 assert(idate.isAD);
7117 }
7118
7119
7120 /++
7121 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this
7122 $(LREF Date) at noon (since the Julian day changes at noon).
7123 +/
7124 @property long julianDay() const @safe pure nothrow @nogc
7125 {
7126 return dayOfGregorianCal + 1_721_425;
7127 }
7128
7129 @safe unittest
7130 {
7131 assert(Date(-4713, 11, 24).julianDay == 0);
7132 assert(Date(0, 12, 31).julianDay == 1_721_425);
7133 assert(Date(1, 1, 1).julianDay == 1_721_426);
7134 assert(Date(1582, 10, 15).julianDay == 2_299_161);
7135 assert(Date(1858, 11, 17).julianDay == 2_400_001);
7136 assert(Date(1982, 1, 4).julianDay == 2_444_974);
7137 assert(Date(1996, 3, 31).julianDay == 2_450_174);
7138 assert(Date(2010, 8, 24).julianDay == 2_455_433);
7139
7140 const cdate = Date(1999, 7, 6);
7141 immutable idate = Date(1999, 7, 6);
7142 assert(cdate.julianDay == 2_451_366);
7143 assert(idate.julianDay == 2_451_366);
7144 }
7145
7146
7147 /++
7148 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7149 any time on this date (since, the modified Julian day changes at
7150 midnight).
7151 +/
7152 @property long modJulianDay() const @safe pure nothrow @nogc
7153 {
7154 return julianDay - 2_400_001;
7155 }
7156
7157 @safe unittest
7158 {
7159 assert(Date(1858, 11, 17).modJulianDay == 0);
7160 assert(Date(2010, 8, 24).modJulianDay == 55_432);
7161
7162 const cdate = Date(1999, 7, 6);
7163 immutable idate = Date(1999, 7, 6);
7164 assert(cdate.modJulianDay == 51_365);
7165 assert(idate.modJulianDay == 51_365);
7166 }
7167
7168
7169 /++
7170 Converts this $(LREF Date) to a string with the format YYYYMMDD.
7171 +/
7172 string toISOString() const @safe pure nothrow
7173 {
7174 import std.format : format;
7175 try
7176 {
7177 if (_year >= 0)
7178 {
7179 if (_year < 10_000)
7180 return format("%04d%02d%02d", _year, _month, _day);
7181 else
7182 return format("+%05d%02d%02d", _year, _month, _day);
7183 }
7184 else if (_year > -10_000)
7185 return format("%05d%02d%02d", _year, _month, _day);
7186 else
7187 return format("%06d%02d%02d", _year, _month, _day);
7188 }
7189 catch (Exception e)
7190 assert(0, "format() threw.");
7191 }
7192
7193 ///
7194 @safe unittest
7195 {
7196 assert(Date(2010, 7, 4).toISOString() == "20100704");
7197 assert(Date(1998, 12, 25).toISOString() == "19981225");
7198 assert(Date(0, 1, 5).toISOString() == "00000105");
7199 assert(Date(-4, 1, 5).toISOString() == "-00040105");
7200 }
7201
7202 @safe unittest
7203 {
7204 // Test A.D.
7205 assert(Date(9, 12, 4).toISOString() == "00091204");
7206 assert(Date(99, 12, 4).toISOString() == "00991204");
7207 assert(Date(999, 12, 4).toISOString() == "09991204");
7208 assert(Date(9999, 7, 4).toISOString() == "99990704");
7209 assert(Date(10000, 10, 20).toISOString() == "+100001020");
7210
7211 // Test B.C.
7212 assert(Date(0, 12, 4).toISOString() == "00001204");
7213 assert(Date(-9, 12, 4).toISOString() == "-00091204");
7214 assert(Date(-99, 12, 4).toISOString() == "-00991204");
7215 assert(Date(-999, 12, 4).toISOString() == "-09991204");
7216 assert(Date(-9999, 7, 4).toISOString() == "-99990704");
7217 assert(Date(-10000, 10, 20).toISOString() == "-100001020");
7218
7219 const cdate = Date(1999, 7, 6);
7220 immutable idate = Date(1999, 7, 6);
7221 assert(cdate.toISOString() == "19990706");
7222 assert(idate.toISOString() == "19990706");
7223 }
7224
7225 /++
7226 Converts this $(LREF Date) to a string with the format YYYY-MM-DD.
7227 +/
7228 string toISOExtString() const @safe pure nothrow
7229 {
7230 import std.format : format;
7231 try
7232 {
7233 if (_year >= 0)
7234 {
7235 if (_year < 10_000)
7236 return format("%04d-%02d-%02d", _year, _month, _day);
7237 else
7238 return format("+%05d-%02d-%02d", _year, _month, _day);
7239 }
7240 else if (_year > -10_000)
7241 return format("%05d-%02d-%02d", _year, _month, _day);
7242 else
7243 return format("%06d-%02d-%02d", _year, _month, _day);
7244 }
7245 catch (Exception e)
7246 assert(0, "format() threw.");
7247 }
7248
7249 ///
7250 @safe unittest
7251 {
7252 assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04");
7253 assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25");
7254 assert(Date(0, 1, 5).toISOExtString() == "0000-01-05");
7255 assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05");
7256 }
7257
7258 @safe unittest
7259 {
7260 // Test A.D.
7261 assert(Date(9, 12, 4).toISOExtString() == "0009-12-04");
7262 assert(Date(99, 12, 4).toISOExtString() == "0099-12-04");
7263 assert(Date(999, 12, 4).toISOExtString() == "0999-12-04");
7264 assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04");
7265 assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20");
7266
7267 // Test B.C.
7268 assert(Date(0, 12, 4).toISOExtString() == "0000-12-04");
7269 assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04");
7270 assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04");
7271 assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04");
7272 assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04");
7273 assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20");
7274
7275 const cdate = Date(1999, 7, 6);
7276 immutable idate = Date(1999, 7, 6);
7277 assert(cdate.toISOExtString() == "1999-07-06");
7278 assert(idate.toISOExtString() == "1999-07-06");
7279 }
7280
7281 /++
7282 Converts this $(LREF Date) to a string with the format YYYY-Mon-DD.
7283 +/
7284 string toSimpleString() const @safe pure nothrow
7285 {
7286 import std.format : format;
7287 try
7288 {
7289 if (_year >= 0)
7290 {
7291 if (_year < 10_000)
7292 return format("%04d-%s-%02d", _year, monthToString(_month), _day);
7293 else
7294 return format("+%05d-%s-%02d", _year, monthToString(_month), _day);
7295 }
7296 else if (_year > -10_000)
7297 return format("%05d-%s-%02d", _year, monthToString(_month), _day);
7298 else
7299 return format("%06d-%s-%02d", _year, monthToString(_month), _day);
7300 }
7301 catch (Exception e)
7302 assert(0, "format() threw.");
7303 }
7304
7305 ///
7306 @safe unittest
7307 {
7308 assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04");
7309 assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25");
7310 assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05");
7311 assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05");
7312 }
7313
7314 @safe unittest
7315 {
7316 // Test A.D.
7317 assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04");
7318 assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04");
7319 assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04");
7320 assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04");
7321 assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20");
7322
7323 // Test B.C.
7324 assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04");
7325 assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04");
7326 assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04");
7327 assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04");
7328 assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04");
7329 assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20");
7330
7331 const cdate = Date(1999, 7, 6);
7332 immutable idate = Date(1999, 7, 6);
7333 assert(cdate.toSimpleString() == "1999-Jul-06");
7334 assert(idate.toSimpleString() == "1999-Jul-06");
7335 }
7336
7337
7338 /++
7339 Converts this $(LREF Date) to a string.
7340
7341 This function exists to make it easy to convert a $(LREF Date) to a
7342 string for code that does not care what the exact format is - just that
7343 it presents the information in a clear manner. It also makes it easy to
7344 simply convert a $(LREF Date) to a string when using functions such as
7345 `to!string`, `format`, or `writeln` which use toString to convert
7346 user-defined types. So, it is unlikely that much code will call
7347 toString directly.
7348
7349 The format of the string is purposefully unspecified, and code that
7350 cares about the format of the string should use `toISOString`,
7351 `toISOExtString`, `toSimpleString`, or some other custom formatting
7352 function that explicitly generates the format that the code needs. The
7353 reason is that the code is then clear about what format it's using,
7354 making it less error-prone to maintain the code and interact with other
7355 software that consumes the generated strings. It's for this same reason
7356 $(LREF Date) has no `fromString` function, whereas it does have
7357 `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
7358
7359 The format returned by toString may or may not change in the future.
7360 +/
7361 string toString() const @safe pure nothrow
7362 {
7363 return toSimpleString();
7364 }
7365
7366 @safe unittest
7367 {
7368 auto date = Date(1999, 7, 6);
7369 const cdate = Date(1999, 7, 6);
7370 immutable idate = Date(1999, 7, 6);
7371 assert(date.toString());
7372 assert(cdate.toString());
7373 assert(idate.toString());
7374 }
7375
7376
7377 /++
7378 Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace
7379 is stripped from the given string.
7380
7381 Params:
7382 isoString = A string formatted in the ISO format for dates.
7383
7384 Throws:
7385 $(REF DateTimeException,std,datetime,date) if the given string is
7386 not in the ISO format or if the resulting $(LREF Date) would not be
7387 valid.
7388 +/
7389 static Date fromISOString(S)(in S isoString) @safe pure
7390 if (isSomeString!S)
7391 {
7392 import std.algorithm.searching : startsWith;
7393 import std.conv : to, text, ConvException;
7394 import std.exception : enforce;
7395 import std.string : strip;
7396
7397 auto str = isoString.strip;
7398
7399 enforce!DateTimeException(str.length >= 8, text("Invalid ISO String: ", isoString));
7400
7401 int day, month, year;
7402 auto yearStr = str[0 .. $ - 4];
7403
7404 try
7405 {
7406 // using conversion to uint plus cast because it checks for +/-
7407 // for us quickly while throwing ConvException
7408 day = cast(int) to!uint(str[$ - 2 .. $]);
7409 month = cast(int) to!uint(str[$ - 4 .. $ - 2]);
7410
7411 if (yearStr.length > 4)
7412 {
7413 enforce!DateTimeException(yearStr.startsWith('-', '+'),
7414 text("Invalid ISO String: ", isoString));
7415 year = to!int(yearStr);
7416 }
7417 else
7418 {
7419 year = cast(int) to!uint(yearStr);
7420 }
7421 }
7422 catch (ConvException)
7423 {
7424 throw new DateTimeException(text("Invalid ISO String: ", isoString));
7425 }
7426
7427 return Date(year, month, day);
7428 }
7429
7430 ///
7431 @safe unittest
7432 {
7433 assert(Date.fromISOString("20100704") == Date(2010, 7, 4));
7434 assert(Date.fromISOString("19981225") == Date(1998, 12, 25));
7435 assert(Date.fromISOString("00000105") == Date(0, 1, 5));
7436 assert(Date.fromISOString("-00040105") == Date(-4, 1, 5));
7437 assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4));
7438 }
7439
7440 @safe unittest
7441 {
7442 assertThrown!DateTimeException(Date.fromISOString(""));
7443 assertThrown!DateTimeException(Date.fromISOString("990704"));
7444 assertThrown!DateTimeException(Date.fromISOString("0100704"));
7445 assertThrown!DateTimeException(Date.fromISOString("2010070"));
7446 assertThrown!DateTimeException(Date.fromISOString("2010070 "));
7447 assertThrown!DateTimeException(Date.fromISOString("120100704"));
7448 assertThrown!DateTimeException(Date.fromISOString("-0100704"));
7449 assertThrown!DateTimeException(Date.fromISOString("+0100704"));
7450 assertThrown!DateTimeException(Date.fromISOString("2010070a"));
7451 assertThrown!DateTimeException(Date.fromISOString("20100a04"));
7452 assertThrown!DateTimeException(Date.fromISOString("2010a704"));
7453
7454 assertThrown!DateTimeException(Date.fromISOString("99-07-04"));
7455 assertThrown!DateTimeException(Date.fromISOString("010-07-04"));
7456 assertThrown!DateTimeException(Date.fromISOString("2010-07-0"));
7457 assertThrown!DateTimeException(Date.fromISOString("2010-07-0 "));
7458 assertThrown!DateTimeException(Date.fromISOString("12010-07-04"));
7459 assertThrown!DateTimeException(Date.fromISOString("-010-07-04"));
7460 assertThrown!DateTimeException(Date.fromISOString("+010-07-04"));
7461 assertThrown!DateTimeException(Date.fromISOString("2010-07-0a"));
7462 assertThrown!DateTimeException(Date.fromISOString("2010-0a-04"));
7463 assertThrown!DateTimeException(Date.fromISOString("2010-a7-04"));
7464 assertThrown!DateTimeException(Date.fromISOString("2010/07/04"));
7465 assertThrown!DateTimeException(Date.fromISOString("2010/7/04"));
7466 assertThrown!DateTimeException(Date.fromISOString("2010/7/4"));
7467 assertThrown!DateTimeException(Date.fromISOString("2010/07/4"));
7468 assertThrown!DateTimeException(Date.fromISOString("2010-7-04"));
7469 assertThrown!DateTimeException(Date.fromISOString("2010-7-4"));
7470 assertThrown!DateTimeException(Date.fromISOString("2010-07-4"));
7471
7472 assertThrown!DateTimeException(Date.fromISOString("99Jul04"));
7473 assertThrown!DateTimeException(Date.fromISOString("010Jul04"));
7474 assertThrown!DateTimeException(Date.fromISOString("2010Jul0"));
7475 assertThrown!DateTimeException(Date.fromISOString("2010Jul0 "));
7476 assertThrown!DateTimeException(Date.fromISOString("12010Jul04"));
7477 assertThrown!DateTimeException(Date.fromISOString("-010Jul04"));
7478 assertThrown!DateTimeException(Date.fromISOString("+010Jul04"));
7479 assertThrown!DateTimeException(Date.fromISOString("2010Jul0a"));
7480 assertThrown!DateTimeException(Date.fromISOString("2010Jua04"));
7481 assertThrown!DateTimeException(Date.fromISOString("2010aul04"));
7482
7483 assertThrown!DateTimeException(Date.fromISOString("99-Jul-04"));
7484 assertThrown!DateTimeException(Date.fromISOString("010-Jul-04"));
7485 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0"));
7486 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 "));
7487 assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04"));
7488 assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04"));
7489 assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04"));
7490 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a"));
7491 assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04"));
7492 assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04"));
7493 assertThrown!DateTimeException(Date.fromISOString("2010-aul-04"));
7494
7495 assertThrown!DateTimeException(Date.fromISOString("2010-07-04"));
7496 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04"));
7497
7498 assert(Date.fromISOString("19990706") == Date(1999, 7, 6));
7499 assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6));
7500 assert(Date.fromISOString("+019990706") == Date(1999, 7, 6));
7501 assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6));
7502 assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6));
7503 assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6));
7504 }
7505
7506 // bug# 17801
7507 @safe unittest
7508 {
7509 import std.conv : to;
7510 import std.meta : AliasSeq;
7511 foreach (C; AliasSeq!(char, wchar, dchar))
7512 {
7513 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7514 assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21));
7515 }
7516 }
7517
7518
7519 /++
7520 Creates a $(LREF Date) from a string with the format YYYY-MM-DD.
7521 Whitespace is stripped from the given string.
7522
7523 Params:
7524 isoExtString = A string formatted in the ISO Extended format for
7525 dates.
7526
7527 Throws:
7528 $(REF DateTimeException,std,datetime,date) if the given string is
7529 not in the ISO Extended format or if the resulting $(LREF Date)
7530 would not be valid.
7531 +/
7532 static Date fromISOExtString(S)(in S isoExtString) @safe pure
7533 if (isSomeString!(S))
7534 {
7535 import std.algorithm.searching : all, startsWith;
7536 import std.ascii : isDigit;
7537 import std.conv : to;
7538 import std.exception : enforce;
7539 import std.format : format;
7540 import std.string : strip;
7541
7542 auto dstr = to!dstring(strip(isoExtString));
7543
7544 enforce(dstr.length >= 10, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7545
7546 auto day = dstr[$-2 .. $];
7547 auto month = dstr[$-5 .. $-3];
7548 auto year = dstr[0 .. $-6];
7549
7550 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7551 enforce(dstr[$-6] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7552 enforce(all!isDigit(day),
7553 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7554 enforce(all!isDigit(month),
7555 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7556
7557 if (year.length > 4)
7558 {
7559 enforce(year.startsWith('-', '+'),
7560 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7561 enforce(all!isDigit(year[1..$]),
7562 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7563 }
7564 else
7565 enforce(all!isDigit(year),
7566 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7567
7568 return Date(to!short(year), to!ubyte(month), to!ubyte(day));
7569 }
7570
7571 ///
7572 @safe unittest
7573 {
7574 assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4));
7575 assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25));
7576 assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5));
7577 assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5));
7578 assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4));
7579 }
7580
7581 @safe unittest
7582 {
7583 assertThrown!DateTimeException(Date.fromISOExtString(""));
7584 assertThrown!DateTimeException(Date.fromISOExtString("990704"));
7585 assertThrown!DateTimeException(Date.fromISOExtString("0100704"));
7586 assertThrown!DateTimeException(Date.fromISOExtString("2010070"));
7587 assertThrown!DateTimeException(Date.fromISOExtString("2010070 "));
7588 assertThrown!DateTimeException(Date.fromISOExtString("120100704"));
7589 assertThrown!DateTimeException(Date.fromISOExtString("-0100704"));
7590 assertThrown!DateTimeException(Date.fromISOExtString("+0100704"));
7591 assertThrown!DateTimeException(Date.fromISOExtString("2010070a"));
7592 assertThrown!DateTimeException(Date.fromISOExtString("20100a04"));
7593 assertThrown!DateTimeException(Date.fromISOExtString("2010a704"));
7594
7595 assertThrown!DateTimeException(Date.fromISOExtString("99-07-04"));
7596 assertThrown!DateTimeException(Date.fromISOExtString("010-07-04"));
7597 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0"));
7598 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 "));
7599 assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04"));
7600 assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04"));
7601 assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04"));
7602 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a"));
7603 assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04"));
7604 assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04"));
7605 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04"));
7606 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04"));
7607 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4"));
7608 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4"));
7609 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04"));
7610 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4"));
7611 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4"));
7612
7613 assertThrown!DateTimeException(Date.fromISOExtString("99Jul04"));
7614 assertThrown!DateTimeException(Date.fromISOExtString("010Jul04"));
7615 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0"));
7616 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 "));
7617 assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04"));
7618 assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04"));
7619 assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04"));
7620 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a"));
7621 assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04"));
7622 assertThrown!DateTimeException(Date.fromISOExtString("2010aul04"));
7623
7624 assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04"));
7625 assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04"));
7626 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0"));
7627 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 "));
7628 assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04"));
7629 assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04"));
7630 assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04"));
7631 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a"));
7632 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04"));
7633 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04"));
7634 assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04"));
7635
7636 assertThrown!DateTimeException(Date.fromISOExtString("20100704"));
7637 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04"));
7638
7639 assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6));
7640 assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6));
7641 assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6));
7642 assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6));
7643 assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6));
7644 assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6));
7645 }
7646
7647 // bug# 17801
7648 @safe unittest
7649 {
7650 import std.conv : to;
7651 import std.meta : AliasSeq;
7652 foreach (C; AliasSeq!(char, wchar, dchar))
7653 {
7654 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7655 assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21));
7656 }
7657 }
7658
7659
7660 /++
7661 Creates a $(LREF Date) from a string with the format YYYY-Mon-DD.
7662 Whitespace is stripped from the given string.
7663
7664 Params:
7665 simpleString = A string formatted in the way that toSimpleString
7666 formats dates.
7667
7668 Throws:
7669 $(REF DateTimeException,std,datetime,date) if the given string is
7670 not in the correct format or if the resulting $(LREF Date) would not
7671 be valid.
7672 +/
7673 static Date fromSimpleString(S)(in S simpleString) @safe pure
7674 if (isSomeString!(S))
7675 {
7676 import std.algorithm.searching : all, startsWith;
7677 import std.ascii : isDigit;
7678 import std.conv : to;
7679 import std.exception : enforce;
7680 import std.format : format;
7681 import std.string : strip;
7682
7683 auto dstr = to!dstring(strip(simpleString));
7684
7685 enforce(dstr.length >= 11, new DateTimeException(format("Invalid string format: %s", simpleString)));
7686
7687 auto day = dstr[$-2 .. $];
7688 auto month = monthFromString(to!string(dstr[$-6 .. $-3]));
7689 auto year = dstr[0 .. $-7];
7690
7691 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
7692 enforce(dstr[$-7] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
7693 enforce(all!isDigit(day), new DateTimeException(format("Invalid string format: %s", simpleString)));
7694
7695 if (year.length > 4)
7696 {
7697 enforce(year.startsWith('-', '+'),
7698 new DateTimeException(format("Invalid string format: %s", simpleString)));
7699 enforce(all!isDigit(year[1..$]),
7700 new DateTimeException(format("Invalid string format: %s", simpleString)));
7701 }
7702 else
7703 enforce(all!isDigit(year),
7704 new DateTimeException(format("Invalid string format: %s", simpleString)));
7705
7706 return Date(to!short(year), month, to!ubyte(day));
7707 }
7708
7709 ///
7710 @safe unittest
7711 {
7712 assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4));
7713 assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25));
7714 assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5));
7715 assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5));
7716 assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4));
7717 }
7718
7719 @safe unittest
7720 {
7721 assertThrown!DateTimeException(Date.fromSimpleString(""));
7722 assertThrown!DateTimeException(Date.fromSimpleString("990704"));
7723 assertThrown!DateTimeException(Date.fromSimpleString("0100704"));
7724 assertThrown!DateTimeException(Date.fromSimpleString("2010070"));
7725 assertThrown!DateTimeException(Date.fromSimpleString("2010070 "));
7726 assertThrown!DateTimeException(Date.fromSimpleString("120100704"));
7727 assertThrown!DateTimeException(Date.fromSimpleString("-0100704"));
7728 assertThrown!DateTimeException(Date.fromSimpleString("+0100704"));
7729 assertThrown!DateTimeException(Date.fromSimpleString("2010070a"));
7730 assertThrown!DateTimeException(Date.fromSimpleString("20100a04"));
7731 assertThrown!DateTimeException(Date.fromSimpleString("2010a704"));
7732
7733 assertThrown!DateTimeException(Date.fromSimpleString("99-07-04"));
7734 assertThrown!DateTimeException(Date.fromSimpleString("010-07-04"));
7735 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0"));
7736 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 "));
7737 assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04"));
7738 assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04"));
7739 assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04"));
7740 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a"));
7741 assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04"));
7742 assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04"));
7743 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04"));
7744 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04"));
7745 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4"));
7746 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4"));
7747 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04"));
7748 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4"));
7749 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4"));
7750
7751 assertThrown!DateTimeException(Date.fromSimpleString("99Jul04"));
7752 assertThrown!DateTimeException(Date.fromSimpleString("010Jul04"));
7753 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0"));
7754 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 "));
7755 assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04"));
7756 assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04"));
7757 assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04"));
7758 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a"));
7759 assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04"));
7760 assertThrown!DateTimeException(Date.fromSimpleString("2010aul04"));
7761
7762 assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04"));
7763 assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04"));
7764 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0"));
7765 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 "));
7766 assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04"));
7767 assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04"));
7768 assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04"));
7769 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a"));
7770 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04"));
7771 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04"));
7772 assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04"));
7773
7774 assertThrown!DateTimeException(Date.fromSimpleString("20100704"));
7775 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04"));
7776
7777 assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6));
7778 assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6));
7779 assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6));
7780 assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6));
7781 assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6));
7782 assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6));
7783 }
7784
7785 // bug# 17801
7786 @safe unittest
7787 {
7788 import std.conv : to;
7789 import std.meta : AliasSeq;
7790 foreach (C; AliasSeq!(char, wchar, dchar))
7791 {
7792 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7793 assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21));
7794 }
7795 }
7796
7797
7798 /++
7799 Returns the $(LREF Date) farthest in the past which is representable by
7800 $(LREF Date).
7801 +/
7802 @property static Date min() @safe pure nothrow @nogc
7803 {
7804 auto date = Date.init;
7805 date._year = short.min;
7806 date._month = Month.jan;
7807 date._day = 1;
7808
7809 return date;
7810 }
7811
7812 @safe unittest
7813 {
7814 assert(Date.min.year < 0);
7815 assert(Date.min < Date.max);
7816 }
7817
7818
7819 /++
7820 Returns the $(LREF Date) farthest in the future which is representable
7821 by $(LREF Date).
7822 +/
7823 @property static Date max() @safe pure nothrow @nogc
7824 {
7825 auto date = Date.init;
7826 date._year = short.max;
7827 date._month = Month.dec;
7828 date._day = 31;
7829
7830 return date;
7831 }
7832
7833 @safe unittest
7834 {
7835 assert(Date.max.year > 0);
7836 assert(Date.max > Date.min);
7837 }
7838
7839
7840 private:
7841
7842 /+
7843 Whether the given values form a valid date.
7844
7845 Params:
7846 year = The year to test.
7847 month = The month of the Gregorian Calendar to test.
7848 day = The day of the month to test.
7849 +/
7850 static bool _valid(int year, int month, int day) @safe pure nothrow @nogc
7851 {
7852 if (!valid!"months"(month))
7853 return false;
7854 return valid!"days"(year, month, day);
7855 }
7856
7857
7858 package:
7859
7860 /+
7861 Adds the given number of days to this $(LREF Date). A negative number
7862 will subtract.
7863
7864 The month will be adjusted along with the day if the number of days
7865 added (or subtracted) would overflow (or underflow) the current month.
7866 The year will be adjusted along with the month if the increase (or
7867 decrease) to the month would cause it to overflow (or underflow) the
7868 current year.
7869
7870 $(D _addDays(numDays)) is effectively equivalent to
7871 $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days).
7872
7873 Params:
7874 days = The number of days to add to this Date.
7875 +/
7876 ref Date _addDays(long days) return @safe pure nothrow @nogc
7877 {
7878 dayOfGregorianCal = cast(int)(dayOfGregorianCal + days);
7879 return this;
7880 }
7881
7882 @safe unittest
7883 {
7884 // Test A.D.
7885 {
7886 auto date = Date(1999, 2, 28);
7887 date._addDays(1);
7888 assert(date == Date(1999, 3, 1));
7889 date._addDays(-1);
7890 assert(date == Date(1999, 2, 28));
7891 }
7892
7893 {
7894 auto date = Date(2000, 2, 28);
7895 date._addDays(1);
7896 assert(date == Date(2000, 2, 29));
7897 date._addDays(1);
7898 assert(date == Date(2000, 3, 1));
7899 date._addDays(-1);
7900 assert(date == Date(2000, 2, 29));
7901 }
7902
7903 {
7904 auto date = Date(1999, 6, 30);
7905 date._addDays(1);
7906 assert(date == Date(1999, 7, 1));
7907 date._addDays(-1);
7908 assert(date == Date(1999, 6, 30));
7909 }
7910
7911 {
7912 auto date = Date(1999, 7, 31);
7913 date._addDays(1);
7914 assert(date == Date(1999, 8, 1));
7915 date._addDays(-1);
7916 assert(date == Date(1999, 7, 31));
7917 }
7918
7919 {
7920 auto date = Date(1999, 1, 1);
7921 date._addDays(-1);
7922 assert(date == Date(1998, 12, 31));
7923 date._addDays(1);
7924 assert(date == Date(1999, 1, 1));
7925 }
7926
7927 {
7928 auto date = Date(1999, 7, 6);
7929 date._addDays(9);
7930 assert(date == Date(1999, 7, 15));
7931 date._addDays(-11);
7932 assert(date == Date(1999, 7, 4));
7933 date._addDays(30);
7934 assert(date == Date(1999, 8, 3));
7935 date._addDays(-3);
7936 assert(date == Date(1999, 7, 31));
7937 }
7938
7939 {
7940 auto date = Date(1999, 7, 6);
7941 date._addDays(365);
7942 assert(date == Date(2000, 7, 5));
7943 date._addDays(-365);
7944 assert(date == Date(1999, 7, 6));
7945 date._addDays(366);
7946 assert(date == Date(2000, 7, 6));
7947 date._addDays(730);
7948 assert(date == Date(2002, 7, 6));
7949 date._addDays(-1096);
7950 assert(date == Date(1999, 7, 6));
7951 }
7952
7953 // Test B.C.
7954 {
7955 auto date = Date(-1999, 2, 28);
7956 date._addDays(1);
7957 assert(date == Date(-1999, 3, 1));
7958 date._addDays(-1);
7959 assert(date == Date(-1999, 2, 28));
7960 }
7961
7962 {
7963 auto date = Date(-2000, 2, 28);
7964 date._addDays(1);
7965 assert(date == Date(-2000, 2, 29));
7966 date._addDays(1);
7967 assert(date == Date(-2000, 3, 1));
7968 date._addDays(-1);
7969 assert(date == Date(-2000, 2, 29));
7970 }
7971
7972 {
7973 auto date = Date(-1999, 6, 30);
7974 date._addDays(1);
7975 assert(date == Date(-1999, 7, 1));
7976 date._addDays(-1);
7977 assert(date == Date(-1999, 6, 30));
7978 }
7979
7980 {
7981 auto date = Date(-1999, 7, 31);
7982 date._addDays(1);
7983 assert(date == Date(-1999, 8, 1));
7984 date._addDays(-1);
7985 assert(date == Date(-1999, 7, 31));
7986 }
7987
7988 {
7989 auto date = Date(-1999, 1, 1);
7990 date._addDays(-1);
7991 assert(date == Date(-2000, 12, 31));
7992 date._addDays(1);
7993 assert(date == Date(-1999, 1, 1));
7994 }
7995
7996 {
7997 auto date = Date(-1999, 7, 6);
7998 date._addDays(9);
7999 assert(date == Date(-1999, 7, 15));
8000 date._addDays(-11);
8001 assert(date == Date(-1999, 7, 4));
8002 date._addDays(30);
8003 assert(date == Date(-1999, 8, 3));
8004 date._addDays(-3);
8005 }
8006
8007 {
8008 auto date = Date(-1999, 7, 6);
8009 date._addDays(365);
8010 assert(date == Date(-1998, 7, 6));
8011 date._addDays(-365);
8012 assert(date == Date(-1999, 7, 6));
8013 date._addDays(366);
8014 assert(date == Date(-1998, 7, 7));
8015 date._addDays(730);
8016 assert(date == Date(-1996, 7, 6));
8017 date._addDays(-1096);
8018 assert(date == Date(-1999, 7, 6));
8019 }
8020
8021 // Test Both
8022 {
8023 auto date = Date(1, 7, 6);
8024 date._addDays(-365);
8025 assert(date == Date(0, 7, 6));
8026 date._addDays(365);
8027 assert(date == Date(1, 7, 6));
8028 date._addDays(-731);
8029 assert(date == Date(-1, 7, 6));
8030 date._addDays(730);
8031 assert(date == Date(1, 7, 5));
8032 }
8033
8034 const cdate = Date(1999, 7, 6);
8035 immutable idate = Date(1999, 7, 6);
8036 static assert(!__traits(compiles, cdate._addDays(12)));
8037 static assert(!__traits(compiles, idate._addDays(12)));
8038 }
8039
8040
8041 @safe pure invariant()
8042 {
8043 import std.format : format;
8044 assert(valid!"months"(_month),
8045 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day));
8046 assert(valid!"days"(_year, _month, _day),
8047 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day));
8048 }
8049
8050 short _year = 1;
8051 Month _month = Month.jan;
8052 ubyte _day = 1;
8053 }
8054
8055
8056 /++
8057 Represents a time of day with hours, minutes, and seconds. It uses 24 hour
8058 time.
8059 +/
8060 struct TimeOfDay
8061 {
8062 public:
8063
8064 /++
8065 Params:
8066 hour = Hour of the day [0 - 24$(RPAREN).
8067 minute = Minute of the hour [0 - 60$(RPAREN).
8068 second = Second of the minute [0 - 60$(RPAREN).
8069
8070 Throws:
8071 $(REF DateTimeException,std,datetime,date) if the resulting
8072 $(LREF TimeOfDay) would be not be valid.
8073 +/
8074 this(int hour, int minute, int second = 0) @safe pure
8075 {
8076 enforceValid!"hours"(hour);
8077 enforceValid!"minutes"(minute);
8078 enforceValid!"seconds"(second);
8079
8080 _hour = cast(ubyte) hour;
8081 _minute = cast(ubyte) minute;
8082 _second = cast(ubyte) second;
8083 }
8084
8085 @safe unittest
8086 {
8087 assert(TimeOfDay(0, 0) == TimeOfDay.init);
8088
8089 {
8090 auto tod = TimeOfDay(0, 0);
8091 assert(tod._hour == 0);
8092 assert(tod._minute == 0);
8093 assert(tod._second == 0);
8094 }
8095
8096 {
8097 auto tod = TimeOfDay(12, 30, 33);
8098 assert(tod._hour == 12);
8099 assert(tod._minute == 30);
8100 assert(tod._second == 33);
8101 }
8102
8103 {
8104 auto tod = TimeOfDay(23, 59, 59);
8105 assert(tod._hour == 23);
8106 assert(tod._minute == 59);
8107 assert(tod._second == 59);
8108 }
8109
8110 assertThrown!DateTimeException(TimeOfDay(24, 0, 0));
8111 assertThrown!DateTimeException(TimeOfDay(0, 60, 0));
8112 assertThrown!DateTimeException(TimeOfDay(0, 0, 60));
8113 }
8114
8115
8116 /++
8117 Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay).
8118
8119 Returns:
8120 $(BOOKTABLE,
8121 $(TR $(TD this &lt; rhs) $(TD &lt; 0))
8122 $(TR $(TD this == rhs) $(TD 0))
8123 $(TR $(TD this &gt; rhs) $(TD &gt; 0))
8124 )
8125 +/
8126 int opCmp(in TimeOfDay rhs) const @safe pure nothrow @nogc
8127 {
8128 if (_hour < rhs._hour)
8129 return -1;
8130 if (_hour > rhs._hour)
8131 return 1;
8132
8133 if (_minute < rhs._minute)
8134 return -1;
8135 if (_minute > rhs._minute)
8136 return 1;
8137
8138 if (_second < rhs._second)
8139 return -1;
8140 if (_second > rhs._second)
8141 return 1;
8142
8143 return 0;
8144 }
8145
8146 @safe unittest
8147 {
8148 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0);
8149
8150 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0);
8151 assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0);
8152 assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0);
8153 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
8154
8155 assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0);
8156 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0);
8157
8158 assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0);
8159 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
8160
8161 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
8162 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
8163 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0);
8164 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
8165 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0);
8166 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0);
8167
8168 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
8169 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0);
8170 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0);
8171 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
8172
8173 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
8174 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0);
8175
8176 const ctod = TimeOfDay(12, 30, 33);
8177 immutable itod = TimeOfDay(12, 30, 33);
8178 assert(ctod.opCmp(itod) == 0);
8179 assert(itod.opCmp(ctod) == 0);
8180 }
8181
8182
8183 /++
8184 Hours past midnight.
8185 +/
8186 @property ubyte hour() const @safe pure nothrow @nogc
8187 {
8188 return _hour;
8189 }
8190
8191 @safe unittest
8192 {
8193 assert(TimeOfDay.init.hour == 0);
8194 assert(TimeOfDay(12, 0, 0).hour == 12);
8195
8196 const ctod = TimeOfDay(12, 0, 0);
8197 immutable itod = TimeOfDay(12, 0, 0);
8198 assert(ctod.hour == 12);
8199 assert(itod.hour == 12);
8200 }
8201
8202
8203 /++
8204 Hours past midnight.
8205
8206 Params:
8207 hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to.
8208
8209 Throws:
8210 $(REF DateTimeException,std,datetime,date) if the given hour would
8211 result in an invalid $(LREF TimeOfDay).
8212 +/
8213 @property void hour(int hour) @safe pure
8214 {
8215 enforceValid!"hours"(hour);
8216 _hour = cast(ubyte) hour;
8217 }
8218
8219 @safe unittest
8220 {
8221 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}());
8222
8223 auto tod = TimeOfDay(0, 0, 0);
8224 tod.hour = 12;
8225 assert(tod == TimeOfDay(12, 0, 0));
8226
8227 const ctod = TimeOfDay(0, 0, 0);
8228 immutable itod = TimeOfDay(0, 0, 0);
8229 static assert(!__traits(compiles, ctod.hour = 12));
8230 static assert(!__traits(compiles, itod.hour = 12));
8231 }
8232
8233
8234 /++
8235 Minutes past the hour.
8236 +/
8237 @property ubyte minute() const @safe pure nothrow @nogc
8238 {
8239 return _minute;
8240 }
8241
8242 @safe unittest
8243 {
8244 assert(TimeOfDay.init.minute == 0);
8245 assert(TimeOfDay(0, 30, 0).minute == 30);
8246
8247 const ctod = TimeOfDay(0, 30, 0);
8248 immutable itod = TimeOfDay(0, 30, 0);
8249 assert(ctod.minute == 30);
8250 assert(itod.minute == 30);
8251 }
8252
8253
8254 /++
8255 Minutes past the hour.
8256
8257 Params:
8258 minute = The minute to set this $(LREF TimeOfDay)'s minute to.
8259
8260 Throws:
8261 $(REF DateTimeException,std,datetime,date) if the given minute
8262 would result in an invalid $(LREF TimeOfDay).
8263 +/
8264 @property void minute(int minute) @safe pure
8265 {
8266 enforceValid!"minutes"(minute);
8267 _minute = cast(ubyte) minute;
8268 }
8269
8270 @safe unittest
8271 {
8272 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}());
8273
8274 auto tod = TimeOfDay(0, 0, 0);
8275 tod.minute = 30;
8276 assert(tod == TimeOfDay(0, 30, 0));
8277
8278 const ctod = TimeOfDay(0, 0, 0);
8279 immutable itod = TimeOfDay(0, 0, 0);
8280 static assert(!__traits(compiles, ctod.minute = 30));
8281 static assert(!__traits(compiles, itod.minute = 30));
8282 }
8283
8284
8285 /++
8286 Seconds past the minute.
8287 +/
8288 @property ubyte second() const @safe pure nothrow @nogc
8289 {
8290 return _second;
8291 }
8292
8293 @safe unittest
8294 {
8295 assert(TimeOfDay.init.second == 0);
8296 assert(TimeOfDay(0, 0, 33).second == 33);
8297
8298 const ctod = TimeOfDay(0, 0, 33);
8299 immutable itod = TimeOfDay(0, 0, 33);
8300 assert(ctod.second == 33);
8301 assert(itod.second == 33);
8302 }
8303
8304
8305 /++
8306 Seconds past the minute.
8307
8308 Params:
8309 second = The second to set this $(LREF TimeOfDay)'s second to.
8310
8311 Throws:
8312 $(REF DateTimeException,std,datetime,date) if the given second
8313 would result in an invalid $(LREF TimeOfDay).
8314 +/
8315 @property void second(int second) @safe pure
8316 {
8317 enforceValid!"seconds"(second);
8318 _second = cast(ubyte) second;
8319 }
8320
8321 @safe unittest
8322 {
8323 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}());
8324
8325 auto tod = TimeOfDay(0, 0, 0);
8326 tod.second = 33;
8327 assert(tod == TimeOfDay(0, 0, 33));
8328
8329 const ctod = TimeOfDay(0, 0, 0);
8330 immutable itod = TimeOfDay(0, 0, 0);
8331 static assert(!__traits(compiles, ctod.second = 33));
8332 static assert(!__traits(compiles, itod.second = 33));
8333 }
8334
8335
8336 /++
8337 Adds the given number of units to this $(LREF TimeOfDay). A negative
8338 number will subtract.
8339
8340 The difference between rolling and adding is that rolling does not
8341 affect larger units. For instance, rolling a $(LREF TimeOfDay)
8342 one hours's worth of minutes gets the exact same
8343 $(LREF TimeOfDay).
8344
8345 Accepted units are $(D "hours"), $(D "minutes"), and $(D "seconds").
8346
8347 Params:
8348 units = The units to add.
8349 value = The number of $(D_PARAM units) to add to this
8350 $(LREF TimeOfDay).
8351 +/
8352 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
8353 if (units == "hours")
8354 {
8355 return this += dur!"hours"(value);
8356 }
8357
8358 ///
8359 @safe unittest
8360 {
8361 auto tod1 = TimeOfDay(7, 12, 0);
8362 tod1.roll!"hours"(1);
8363 assert(tod1 == TimeOfDay(8, 12, 0));
8364
8365 auto tod2 = TimeOfDay(7, 12, 0);
8366 tod2.roll!"hours"(-1);
8367 assert(tod2 == TimeOfDay(6, 12, 0));
8368
8369 auto tod3 = TimeOfDay(23, 59, 0);
8370 tod3.roll!"minutes"(1);
8371 assert(tod3 == TimeOfDay(23, 0, 0));
8372
8373 auto tod4 = TimeOfDay(0, 0, 0);
8374 tod4.roll!"minutes"(-1);
8375 assert(tod4 == TimeOfDay(0, 59, 0));
8376
8377 auto tod5 = TimeOfDay(23, 59, 59);
8378 tod5.roll!"seconds"(1);
8379 assert(tod5 == TimeOfDay(23, 59, 0));
8380
8381 auto tod6 = TimeOfDay(0, 0, 0);
8382 tod6.roll!"seconds"(-1);
8383 assert(tod6 == TimeOfDay(0, 0, 59));
8384 }
8385
8386 @safe unittest
8387 {
8388 auto tod = TimeOfDay(12, 27, 2);
8389 tod.roll!"hours"(22).roll!"hours"(-7);
8390 assert(tod == TimeOfDay(3, 27, 2));
8391
8392 const ctod = TimeOfDay(0, 0, 0);
8393 immutable itod = TimeOfDay(0, 0, 0);
8394 static assert(!__traits(compiles, ctod.roll!"hours"(53)));
8395 static assert(!__traits(compiles, itod.roll!"hours"(53)));
8396 }
8397
8398
8399 // Shares documentation with "hours" version.
8400 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
8401 if (units == "minutes" || units == "seconds")
8402 {
8403 import std.format : format;
8404
8405 enum memberVarStr = units[0 .. $ - 1];
8406 value %= 60;
8407 mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr));
8408
8409 if (value < 0)
8410 {
8411 if (newVal < 0)
8412 newVal += 60;
8413 }
8414 else if (newVal >= 60)
8415 newVal -= 60;
8416
8417 mixin(format("_%s = cast(ubyte) newVal;", memberVarStr));
8418 return this;
8419 }
8420
8421 // Test roll!"minutes"().
8422 @safe unittest
8423 {
8424 static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__)
8425 {
8426 orig.roll!"minutes"(minutes);
8427 assert(orig == expected);
8428 }
8429
8430 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
8431 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33));
8432 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33));
8433 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33));
8434 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33));
8435 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33));
8436 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33));
8437 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33));
8438 testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33));
8439 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33));
8440 testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33));
8441 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
8442 testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33));
8443 testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33));
8444 testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33));
8445
8446 testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33));
8447 testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33));
8448 testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33));
8449 testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33));
8450 testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33));
8451 testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33));
8452 testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33));
8453 testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33));
8454
8455 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33));
8456 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33));
8457 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33));
8458 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33));
8459 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33));
8460 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33));
8461 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33));
8462 testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33));
8463 testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33));
8464 testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33));
8465 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
8466 testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33));
8467 testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33));
8468 testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33));
8469
8470 testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33));
8471 testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33));
8472 testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33));
8473 testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33));
8474 testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33));
8475 testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33));
8476 testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33));
8477 testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33));
8478
8479 testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33));
8480 testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33));
8481 testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33));
8482
8483 testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33));
8484 testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33));
8485 testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33));
8486
8487 testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33));
8488 testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33));
8489 testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33));
8490
8491 testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33));
8492 testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33));
8493 testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33));
8494
8495 auto tod = TimeOfDay(12, 27, 2);
8496 tod.roll!"minutes"(97).roll!"minutes"(-102);
8497 assert(tod == TimeOfDay(12, 22, 2));
8498
8499 const ctod = TimeOfDay(0, 0, 0);
8500 immutable itod = TimeOfDay(0, 0, 0);
8501 static assert(!__traits(compiles, ctod.roll!"minutes"(7)));
8502 static assert(!__traits(compiles, itod.roll!"minutes"(7)));
8503 }
8504
8505 // Test roll!"seconds"().
8506 @safe unittest
8507 {
8508 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
8509 {
8510 orig.roll!"seconds"(seconds);
8511 assert(orig == expected);
8512 }
8513
8514 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
8515 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
8516 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
8517 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
8518 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
8519 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
8520 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
8521 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
8522 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
8523 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0));
8524 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3));
8525 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32));
8526 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
8527 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34));
8528
8529 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59));
8530 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0));
8531 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1));
8532 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0));
8533 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32));
8534 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33));
8535 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34));
8536 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33));
8537
8538 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
8539 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
8540 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
8541 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
8542 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
8543 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
8544 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
8545 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
8546 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59));
8547 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58));
8548 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34));
8549 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
8550 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32));
8551
8552 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
8553 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
8554 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59));
8555
8556 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
8557 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
8558 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59));
8559
8560 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
8561 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
8562 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59));
8563
8564 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0));
8565 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
8566 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
8567
8568 auto tod = TimeOfDay(12, 27, 2);
8569 tod.roll!"seconds"(105).roll!"seconds"(-77);
8570 assert(tod == TimeOfDay(12, 27, 30));
8571
8572 const ctod = TimeOfDay(0, 0, 0);
8573 immutable itod = TimeOfDay(0, 0, 0);
8574 static assert(!__traits(compiles, ctod.roll!"seconds"(7)));
8575 static assert(!__traits(compiles, itod.roll!"seconds"(7)));
8576 }
8577
8578
8579 /++
8580 Gives the result of adding or subtracting a $(REF Duration, core,time)
8581 from this $(LREF TimeOfDay).
8582
8583 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8584 are
8585
8586 $(BOOKTABLE,
8587 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8588 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8589 )
8590
8591 Params:
8592 duration = The $(REF Duration, core,time) to add to or subtract from
8593 this $(LREF TimeOfDay).
8594 +/
8595 TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
8596 if (op == "+" || op == "-")
8597 {
8598 TimeOfDay retval = this;
8599 immutable seconds = duration.total!"seconds";
8600 mixin("return retval._addSeconds(" ~ op ~ "seconds);");
8601 }
8602
8603 ///
8604 @safe unittest
8605 {
8606 import core.time : hours, minutes, seconds;
8607
8608 assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13));
8609 assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12));
8610 assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12));
8611 assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0));
8612
8613 assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11));
8614 assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12));
8615 assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12));
8616 assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59));
8617 }
8618
8619 @safe unittest
8620 {
8621 auto tod = TimeOfDay(12, 30, 33);
8622
8623 assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33));
8624 assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
8625 assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
8626 assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
8627 assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
8628 assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
8629
8630 assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
8631 assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
8632 assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
8633 assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
8634 assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
8635 assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26));
8636
8637 assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
8638 assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33));
8639 assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
8640 assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
8641 assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
8642 assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
8643
8644 assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
8645 assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
8646 assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
8647 assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
8648 assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
8649 assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26));
8650
8651 auto duration = dur!"hours"(11);
8652 const ctod = TimeOfDay(12, 30, 33);
8653 immutable itod = TimeOfDay(12, 30, 33);
8654 assert(tod + duration == TimeOfDay(23, 30, 33));
8655 assert(ctod + duration == TimeOfDay(23, 30, 33));
8656 assert(itod + duration == TimeOfDay(23, 30, 33));
8657
8658 assert(tod - duration == TimeOfDay(1, 30, 33));
8659 assert(ctod - duration == TimeOfDay(1, 30, 33));
8660 assert(itod - duration == TimeOfDay(1, 30, 33));
8661 }
8662
8663 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
8664 deprecated("Use Duration instead of TickDuration.")
8665 TimeOfDay opBinary(string op)(TickDuration td) const @safe pure nothrow @nogc
8666 if (op == "+" || op == "-")
8667 {
8668 TimeOfDay retval = this;
8669 immutable seconds = td.seconds;
8670 mixin("return retval._addSeconds(" ~ op ~ "seconds);");
8671 }
8672
8673 deprecated @safe unittest
8674 {
8675 // This probably only runs in cases where gettimeofday() is used, but it's
8676 // hard to do this test correctly with variable ticksPerSec.
8677 if (TickDuration.ticksPerSec == 1_000_000)
8678 {
8679 auto tod = TimeOfDay(12, 30, 33);
8680
8681 assert(tod + TickDuration.from!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
8682 assert(tod + TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
8683
8684 assert(tod - TickDuration.from!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
8685 assert(tod - TickDuration.from!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
8686 }
8687 }
8688
8689
8690 /++
8691 Gives the result of adding or subtracting a $(REF Duration, core,time)
8692 from this $(LREF TimeOfDay), as well as assigning the result to this
8693 $(LREF TimeOfDay).
8694
8695 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8696 are
8697
8698 $(BOOKTABLE,
8699 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8700 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8701 )
8702
8703 Params:
8704 duration = The $(REF Duration, core,time) to add to or subtract from
8705 this $(LREF TimeOfDay).
8706 +/
8707 ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
8708 if (op == "+" || op == "-")
8709 {
8710 immutable seconds = duration.total!"seconds";
8711 mixin("return _addSeconds(" ~ op ~ "seconds);");
8712 }
8713
8714 @safe unittest
8715 {
8716 auto duration = dur!"hours"(12);
8717
8718 assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33));
8719 assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
8720 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
8721 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
8722 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
8723 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
8724
8725 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
8726 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
8727 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
8728 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
8729 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
8730 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26));
8731
8732 assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
8733 assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33));
8734 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
8735 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
8736 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
8737 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
8738
8739 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
8740 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
8741 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
8742 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
8743 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
8744 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26));
8745
8746 auto tod = TimeOfDay(19, 17, 22);
8747 (tod += dur!"seconds"(9)) += dur!"seconds"(-7292);
8748 assert(tod == TimeOfDay(17, 15, 59));
8749
8750 const ctod = TimeOfDay(12, 33, 30);
8751 immutable itod = TimeOfDay(12, 33, 30);
8752 static assert(!__traits(compiles, ctod += duration));
8753 static assert(!__traits(compiles, itod += duration));
8754 static assert(!__traits(compiles, ctod -= duration));
8755 static assert(!__traits(compiles, itod -= duration));
8756 }
8757
8758 // Explicitly undocumented. It will be removed in January 2018. @@@DEPRECATED_2018-01@@@
8759 deprecated("Use Duration instead of TickDuration.")
8760 ref TimeOfDay opOpAssign(string op)(TickDuration td) @safe pure nothrow @nogc
8761 if (op == "+" || op == "-")
8762 {
8763 immutable seconds = td.seconds;
8764 mixin("return _addSeconds(" ~ op ~ "seconds);");
8765 }
8766
8767 deprecated @safe unittest
8768 {
8769 // This probably only runs in cases where gettimeofday() is used, but it's
8770 // hard to do this test correctly with variable ticksPerSec.
8771 if (TickDuration.ticksPerSec == 1_000_000)
8772 {
8773 {
8774 auto tod = TimeOfDay(12, 30, 33);
8775 tod += TickDuration.from!"usecs"(7_000_000);
8776 assert(tod == TimeOfDay(12, 30, 40));
8777 }
8778
8779 {
8780 auto tod = TimeOfDay(12, 30, 33);
8781 tod += TickDuration.from!"usecs"(-7_000_000);
8782 assert(tod == TimeOfDay(12, 30, 26));
8783 }
8784
8785 {
8786 auto tod = TimeOfDay(12, 30, 33);
8787 tod -= TickDuration.from!"usecs"(-7_000_000);
8788 assert(tod == TimeOfDay(12, 30, 40));
8789 }
8790
8791 {
8792 auto tod = TimeOfDay(12, 30, 33);
8793 tod -= TickDuration.from!"usecs"(7_000_000);
8794 assert(tod == TimeOfDay(12, 30, 26));
8795 }
8796 }
8797 }
8798
8799
8800 /++
8801 Gives the difference between two $(LREF TimeOfDay)s.
8802
8803 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8804 are
8805
8806 $(BOOKTABLE,
8807 $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration))
8808 )
8809
8810 Params:
8811 rhs = The $(LREF TimeOfDay) to subtract from this one.
8812 +/
8813 Duration opBinary(string op)(in TimeOfDay rhs) const @safe pure nothrow @nogc
8814 if (op == "-")
8815 {
8816 immutable lhsSec = _hour * 3600 + _minute * 60 + _second;
8817 immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second;
8818
8819 return dur!"seconds"(lhsSec - rhsSec);
8820 }
8821
8822 @safe unittest
8823 {
8824 auto tod = TimeOfDay(12, 30, 33);
8825
8826 assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061));
8827 assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061));
8828 assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200));
8829 assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200));
8830 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240));
8831 assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240));
8832 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1));
8833 assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1));
8834
8835 const ctod = TimeOfDay(12, 30, 33);
8836 immutable itod = TimeOfDay(12, 30, 33);
8837 assert(tod - tod == Duration.zero);
8838 assert(ctod - tod == Duration.zero);
8839 assert(itod - tod == Duration.zero);
8840
8841 assert(tod - ctod == Duration.zero);
8842 assert(ctod - ctod == Duration.zero);
8843 assert(itod - ctod == Duration.zero);
8844
8845 assert(tod - itod == Duration.zero);
8846 assert(ctod - itod == Duration.zero);
8847 assert(itod - itod == Duration.zero);
8848 }
8849
8850
8851 /++
8852 Converts this $(LREF TimeOfDay) to a string with the format HHMMSS.
8853 +/
8854 string toISOString() const @safe pure nothrow
8855 {
8856 import std.format : format;
8857 try
8858 return format("%02d%02d%02d", _hour, _minute, _second);
8859 catch (Exception e)
8860 assert(0, "format() threw.");
8861 }
8862
8863 ///
8864 @safe unittest
8865 {
8866 assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
8867 assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
8868 }
8869
8870 @safe unittest
8871 {
8872 auto tod = TimeOfDay(12, 30, 33);
8873 const ctod = TimeOfDay(12, 30, 33);
8874 immutable itod = TimeOfDay(12, 30, 33);
8875 assert(tod.toISOString() == "123033");
8876 assert(ctod.toISOString() == "123033");
8877 assert(itod.toISOString() == "123033");
8878 }
8879
8880
8881 /++
8882 Converts this $(LREF TimeOfDay) to a string with the format HH:MM:SS.
8883 +/
8884 string toISOExtString() const @safe pure nothrow
8885 {
8886 import std.format : format;
8887 try
8888 return format("%02d:%02d:%02d", _hour, _minute, _second);
8889 catch (Exception e)
8890 assert(0, "format() threw.");
8891 }
8892
8893 ///
8894 @safe unittest
8895 {
8896 assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00");
8897 assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33");
8898 }
8899
8900 @safe unittest
8901 {
8902 auto tod = TimeOfDay(12, 30, 33);
8903 const ctod = TimeOfDay(12, 30, 33);
8904 immutable itod = TimeOfDay(12, 30, 33);
8905 assert(tod.toISOExtString() == "12:30:33");
8906 assert(ctod.toISOExtString() == "12:30:33");
8907 assert(itod.toISOExtString() == "12:30:33");
8908 }
8909
8910
8911 /++
8912 Converts this TimeOfDay to a string.
8913
8914 This function exists to make it easy to convert a $(LREF TimeOfDay) to a
8915 string for code that does not care what the exact format is - just that
8916 it presents the information in a clear manner. It also makes it easy to
8917 simply convert a $(LREF TimeOfDay) to a string when using functions such
8918 as `to!string`, `format`, or `writeln` which use toString to convert
8919 user-defined types. So, it is unlikely that much code will call
8920 toString directly.
8921
8922 The format of the string is purposefully unspecified, and code that
8923 cares about the format of the string should use `toISOString`,
8924 `toISOExtString`, or some other custom formatting function that
8925 explicitly generates the format that the code needs. The reason is that
8926 the code is then clear about what format it's using, making it less
8927 error-prone to maintain the code and interact with other software that
8928 consumes the generated strings. It's for this same reason that
8929 $(LREF TimeOfDay) has no `fromString` function, whereas it does have
8930 `fromISOString` and `fromISOExtString`.
8931
8932 The format returned by toString may or may not change in the future.
8933 +/
8934 string toString() const @safe pure nothrow
8935 {
8936 return toISOExtString();
8937 }
8938
8939 @safe unittest
8940 {
8941 auto tod = TimeOfDay(12, 30, 33);
8942 const ctod = TimeOfDay(12, 30, 33);
8943 immutable itod = TimeOfDay(12, 30, 33);
8944 assert(tod.toString());
8945 assert(ctod.toString());
8946 assert(itod.toString());
8947 }
8948
8949
8950 /++
8951 Creates a $(LREF TimeOfDay) from a string with the format HHMMSS.
8952 Whitespace is stripped from the given string.
8953
8954 Params:
8955 isoString = A string formatted in the ISO format for times.
8956
8957 Throws:
8958 $(REF DateTimeException,std,datetime,date) if the given string is
8959 not in the ISO format or if the resulting $(LREF TimeOfDay) would
8960 not be valid.
8961 +/
8962 static TimeOfDay fromISOString(S)(in S isoString) @safe pure
8963 if (isSomeString!S)
8964 {
8965 import std.conv : to, text, ConvException;
8966 import std.exception : enforce;
8967 import std.string : strip;
8968
8969 int hours, minutes, seconds;
8970 auto str = strip(isoString);
8971
8972 enforce!DateTimeException(str.length == 6, text("Invalid ISO String: ", isoString));
8973
8974 try
8975 {
8976 // cast to int from uint is used because it checks for
8977 // non digits without extra loops
8978 hours = cast(int) to!uint(str[0 .. 2]);
8979 minutes = cast(int) to!uint(str[2 .. 4]);
8980 seconds = cast(int) to!uint(str[4 .. $]);
8981 }
8982 catch (ConvException)
8983 {
8984 throw new DateTimeException(text("Invalid ISO String: ", isoString));
8985 }
8986
8987 return TimeOfDay(hours, minutes, seconds);
8988 }
8989
8990 ///
8991 @safe unittest
8992 {
8993 assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
8994 assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
8995 assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));
8996 }
8997
8998 @safe unittest
8999 {
9000 assertThrown!DateTimeException(TimeOfDay.fromISOString(""));
9001 assertThrown!DateTimeException(TimeOfDay.fromISOString("0"));
9002 assertThrown!DateTimeException(TimeOfDay.fromISOString("00"));
9003 assertThrown!DateTimeException(TimeOfDay.fromISOString("000"));
9004 assertThrown!DateTimeException(TimeOfDay.fromISOString("0000"));
9005 assertThrown!DateTimeException(TimeOfDay.fromISOString("00000"));
9006 assertThrown!DateTimeException(TimeOfDay.fromISOString("13033"));
9007 assertThrown!DateTimeException(TimeOfDay.fromISOString("1277"));
9008 assertThrown!DateTimeException(TimeOfDay.fromISOString("12707"));
9009 assertThrown!DateTimeException(TimeOfDay.fromISOString("12070"));
9010 assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a"));
9011 assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3"));
9012 assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33"));
9013 assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033"));
9014 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033"));
9015 assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033"));
9016 assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330"));
9017 assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033"));
9018 assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033"));
9019 assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033"));
9020 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am"));
9021 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm"));
9022
9023 assertThrown!DateTimeException(TimeOfDay.fromISOString("0::"));
9024 assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:"));
9025 assertThrown!DateTimeException(TimeOfDay.fromISOString("::0"));
9026 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0"));
9027 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00"));
9028 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0"));
9029 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0"));
9030 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0"));
9031 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00"));
9032 assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33"));
9033 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7"));
9034 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07"));
9035 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0"));
9036 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a"));
9037 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3"));
9038 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33"));
9039 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33"));
9040 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33"));
9041 assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33"));
9042 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30"));
9043 assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30"));
9044 assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33"));
9045 assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33"));
9046 assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33"));
9047 assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33"));
9048 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am"));
9049 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm"));
9050
9051 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33"));
9052
9053 assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17));
9054 assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12));
9055 assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7));
9056 assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17));
9057 assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17));
9058 assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17));
9059 }
9060
9061 // bug# 17801
9062 @safe unittest
9063 {
9064 import std.conv : to;
9065 import std.meta : AliasSeq;
9066 foreach (C; AliasSeq!(char, wchar, dchar))
9067 {
9068 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9069 assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16));
9070 }
9071 }
9072
9073
9074 /++
9075 Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS.
9076 Whitespace is stripped from the given string.
9077
9078 Params:
9079 isoExtString = A string formatted in the ISO Extended format for
9080 times.
9081
9082 Throws:
9083 $(REF DateTimeException,std,datetime,date) if the given string is
9084 not in the ISO Extended format or if the resulting $(LREF TimeOfDay)
9085 would not be valid.
9086 +/
9087 static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure
9088 if (isSomeString!S)
9089 {
9090 import std.algorithm.searching : all;
9091 import std.ascii : isDigit;
9092 import std.conv : to;
9093 import std.exception : enforce;
9094 import std.format : format;
9095 import std.string : strip;
9096
9097 auto dstr = to!dstring(strip(isoExtString));
9098
9099 enforce(dstr.length == 8, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9100
9101 auto hours = dstr[0 .. 2];
9102 auto minutes = dstr[3 .. 5];
9103 auto seconds = dstr[6 .. $];
9104
9105 enforce(dstr[2] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9106 enforce(dstr[5] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9107 enforce(all!isDigit(hours),
9108 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9109 enforce(all!isDigit(minutes),
9110 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9111 enforce(all!isDigit(seconds),
9112 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
9113
9114 return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
9115 }
9116
9117 ///
9118 @safe unittest
9119 {
9120 assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0));
9121 assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33));
9122 assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33));
9123 }
9124
9125 @safe unittest
9126 {
9127 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(""));
9128 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0"));
9129 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00"));
9130 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000"));
9131 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000"));
9132 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000"));
9133 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033"));
9134 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277"));
9135 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707"));
9136 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070"));
9137 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a"));
9138 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3"));
9139 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33"));
9140 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033"));
9141 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033"));
9142 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033"));
9143 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330"));
9144 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033"));
9145 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033"));
9146 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033"));
9147 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am"));
9148 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm"));
9149
9150 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::"));
9151 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:"));
9152 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0"));
9153 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0"));
9154 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00"));
9155 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0"));
9156 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0"));
9157 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0"));
9158 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00"));
9159 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33"));
9160 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7"));
9161 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07"));
9162 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0"));
9163 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a"));
9164 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3"));
9165 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33"));
9166 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33"));
9167 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33"));
9168 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33"));
9169 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30"));
9170 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30"));
9171 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33"));
9172 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33"));
9173 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33"));
9174 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33"));
9175 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am"));
9176 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm"));
9177
9178 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033"));
9179
9180 assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17));
9181 assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12));
9182 assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7));
9183 assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17));
9184 assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17));
9185 assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17));
9186 }
9187
9188 // bug# 17801
9189 @safe unittest
9190 {
9191 import std.conv : to;
9192 import std.meta : AliasSeq;
9193 foreach (C; AliasSeq!(char, wchar, dchar))
9194 {
9195 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
9196 assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16));
9197 }
9198 }
9199
9200
9201 /++
9202 Returns midnight.
9203 +/
9204 @property static TimeOfDay min() @safe pure nothrow @nogc
9205 {
9206 return TimeOfDay.init;
9207 }
9208
9209 @safe unittest
9210 {
9211 assert(TimeOfDay.min.hour == 0);
9212 assert(TimeOfDay.min.minute == 0);
9213 assert(TimeOfDay.min.second == 0);
9214 assert(TimeOfDay.min < TimeOfDay.max);
9215 }
9216
9217
9218 /++
9219 Returns one second short of midnight.
9220 +/
9221 @property static TimeOfDay max() @safe pure nothrow @nogc
9222 {
9223 auto tod = TimeOfDay.init;
9224 tod._hour = maxHour;
9225 tod._minute = maxMinute;
9226 tod._second = maxSecond;
9227
9228 return tod;
9229 }
9230
9231 @safe unittest
9232 {
9233 assert(TimeOfDay.max.hour == 23);
9234 assert(TimeOfDay.max.minute == 59);
9235 assert(TimeOfDay.max.second == 59);
9236 assert(TimeOfDay.max > TimeOfDay.min);
9237 }
9238
9239
9240 private:
9241
9242 /+
9243 Add seconds to the time of day. Negative values will subtract. If the
9244 number of seconds overflows (or underflows), then the seconds will wrap,
9245 increasing (or decreasing) the number of minutes accordingly. If the
9246 number of minutes overflows (or underflows), then the minutes will wrap.
9247 If the number of minutes overflows(or underflows), then the hour will
9248 wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30).
9249
9250 Params:
9251 seconds = The number of seconds to add to this TimeOfDay.
9252 +/
9253 ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc
9254 {
9255 long hnsecs = convert!("seconds", "hnsecs")(seconds);
9256 hnsecs += convert!("hours", "hnsecs")(_hour);
9257 hnsecs += convert!("minutes", "hnsecs")(_minute);
9258 hnsecs += convert!("seconds", "hnsecs")(_second);
9259
9260 hnsecs %= convert!("days", "hnsecs")(1);
9261
9262 if (hnsecs < 0)
9263 hnsecs += convert!("days", "hnsecs")(1);
9264
9265 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
9266 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
9267 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
9268
9269 _hour = cast(ubyte) newHours;
9270 _minute = cast(ubyte) newMinutes;
9271 _second = cast(ubyte) newSeconds;
9272
9273 return this;
9274 }
9275
9276 @safe unittest
9277 {
9278 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
9279 {
9280 orig._addSeconds(seconds);
9281 assert(orig == expected);
9282 }
9283
9284 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
9285 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
9286 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
9287 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
9288 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
9289 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
9290 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
9291 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
9292 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
9293 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0));
9294 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3));
9295 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32));
9296 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33));
9297 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34));
9298
9299 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59));
9300 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0));
9301 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1));
9302 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0));
9303 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32));
9304 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33));
9305 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34));
9306 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33));
9307
9308 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
9309 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
9310 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
9311 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
9312 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
9313 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
9314 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
9315 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
9316 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59));
9317 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58));
9318 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34));
9319 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33));
9320 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32));
9321
9322 testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0));
9323 testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59));
9324 testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33));
9325 testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32));
9326 testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59));
9327 testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33));
9328
9329 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
9330 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
9331 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59));
9332
9333 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
9334 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
9335 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59));
9336
9337 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
9338 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
9339 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59));
9340
9341 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0));
9342 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
9343 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
9344
9345 const ctod = TimeOfDay(0, 0, 0);
9346 immutable itod = TimeOfDay(0, 0, 0);
9347 static assert(!__traits(compiles, ctod._addSeconds(7)));
9348 static assert(!__traits(compiles, itod._addSeconds(7)));
9349 }
9350
9351
9352 /+
9353 Whether the given values form a valid $(LREF TimeOfDay).
9354 +/
9355 static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc
9356 {
9357 return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second);
9358 }
9359
9360
9361 @safe pure invariant()
9362 {
9363 import std.format : format;
9364 assert(_valid(_hour, _minute, _second),
9365 format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second));
9366 }
9367
9368
9369 package:
9370
9371 ubyte _hour;
9372 ubyte _minute;
9373 ubyte _second;
9374
9375 enum ubyte maxHour = 24 - 1;
9376 enum ubyte maxMinute = 60 - 1;
9377 enum ubyte maxSecond = 60 - 1;
9378 }
9379
9380
9381 /++
9382 Returns whether the given value is valid for the given unit type when in a
9383 time point. Naturally, a duration is not held to a particular range, but
9384 the values in a time point are (e.g. a month must be in the range of
9385 1 - 12 inclusive).
9386
9387 Params:
9388 units = The units of time to validate.
9389 value = The number to validate.
9390 +/
9391 bool valid(string units)(int value) @safe pure nothrow @nogc
9392 if (units == "months" ||
9393 units == "hours" ||
9394 units == "minutes" ||
9395 units == "seconds")
9396 {
9397 static if (units == "months")
9398 return value >= Month.jan && value <= Month.dec;
9399 else static if (units == "hours")
9400 return value >= 0 && value <= 23;
9401 else static if (units == "minutes")
9402 return value >= 0 && value <= 59;
9403 else static if (units == "seconds")
9404 return value >= 0 && value <= 59;
9405 }
9406
9407 ///
9408 @safe unittest
9409 {
9410 assert(valid!"hours"(12));
9411 assert(!valid!"hours"(32));
9412 assert(valid!"months"(12));
9413 assert(!valid!"months"(13));
9414 }
9415
9416 /++
9417 Returns whether the given day is valid for the given year and month.
9418
9419 Params:
9420 units = The units of time to validate.
9421 year = The year of the day to validate.
9422 month = The month of the day to validate (January is 1).
9423 day = The day to validate.
9424 +/
9425 bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc
9426 if (units == "days")
9427 {
9428 return day > 0 && day <= maxDay(year, month);
9429 }
9430
9431 ///
9432 @safe pure nothrow @nogc unittest
9433 {
9434 assert(valid!"days"(2016, 2, 29));
9435 assert(!valid!"days"(2016, 2, 30));
9436 assert(valid!"days"(2017, 2, 20));
9437 assert(!valid!"days"(2017, 2, 29));
9438 }
9439
9440
9441 /++
9442 Params:
9443 units = The units of time to validate.
9444 value = The number to validate.
9445 file = The file that the $(LREF DateTimeException) will list if thrown.
9446 line = The line number that the $(LREF DateTimeException) will list if
9447 thrown.
9448
9449 Throws:
9450 $(LREF DateTimeException) if $(D valid!units(value)) is false.
9451 +/
9452 void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure
9453 if (units == "months" ||
9454 units == "hours" ||
9455 units == "minutes" ||
9456 units == "seconds")
9457 {
9458 import std.format : format;
9459
9460 static if (units == "months")
9461 {
9462 if (!valid!units(value))
9463 throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line);
9464 }
9465 else static if (units == "hours")
9466 {
9467 if (!valid!units(value))
9468 throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line);
9469 }
9470 else static if (units == "minutes")
9471 {
9472 if (!valid!units(value))
9473 throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line);
9474 }
9475 else static if (units == "seconds")
9476 {
9477 if (!valid!units(value))
9478 throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line);
9479 }
9480 }
9481
9482
9483 /++
9484 Params:
9485 units = The units of time to validate.
9486 year = The year of the day to validate.
9487 month = The month of the day to validate.
9488 day = The day to validate.
9489 file = The file that the $(LREF DateTimeException) will list if thrown.
9490 line = The line number that the $(LREF DateTimeException) will list if
9491 thrown.
9492
9493 Throws:
9494 $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false.
9495 +/
9496 void enforceValid(string units)
9497 (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure
9498 if (units == "days")
9499 {
9500 import std.format : format;
9501 if (!valid!"days"(year, month, day))
9502 throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line);
9503 }
9504
9505
9506 /++
9507 Returns the number of days from the current day of the week to the given
9508 day of the week. If they are the same, then the result is 0.
9509
9510 Params:
9511 currDoW = The current day of the week.
9512 dow = The day of the week to get the number of days to.
9513 +/
9514 int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc
9515 {
9516 if (currDoW == dow)
9517 return 0;
9518 if (currDoW < dow)
9519 return dow - currDoW;
9520 return DayOfWeek.sat - currDoW + dow + 1;
9521 }
9522
9523 ///
9524 @safe pure nothrow @nogc unittest
9525 {
9526 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
9527 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
9528 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
9529 }
9530
9531 @safe unittest
9532 {
9533 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0);
9534 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1);
9535 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2);
9536 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3);
9537 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4);
9538 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5);
9539 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6);
9540
9541 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
9542 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
9543 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1);
9544 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
9545 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3);
9546 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4);
9547 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5);
9548
9549 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5);
9550 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6);
9551 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0);
9552 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1);
9553 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2);
9554 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3);
9555 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4);
9556
9557 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4);
9558 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5);
9559 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6);
9560 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0);
9561 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1);
9562 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2);
9563 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3);
9564
9565 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3);
9566 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4);
9567 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5);
9568 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6);
9569 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0);
9570 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1);
9571 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2);
9572
9573 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2);
9574 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3);
9575 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4);
9576 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5);
9577 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6);
9578 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0);
9579 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1);
9580
9581 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1);
9582 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2);
9583 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3);
9584 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4);
9585 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5);
9586 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6);
9587 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0);
9588 }
9589
9590
9591 /++
9592 Returns the number of months from the current months of the year to the
9593 given month of the year. If they are the same, then the result is 0.
9594
9595 Params:
9596 currMonth = The current month of the year.
9597 month = The month of the year to get the number of months to.
9598 +/
9599 int monthsToMonth(int currMonth, int month) @safe pure
9600 {
9601 enforceValid!"months"(currMonth);
9602 enforceValid!"months"(month);
9603
9604 if (currMonth == month)
9605 return 0;
9606 if (currMonth < month)
9607 return month - currMonth;
9608 return Month.dec - currMonth + month;
9609 }
9610
9611 ///
9612 @safe pure unittest
9613 {
9614 assert(monthsToMonth(Month.jan, Month.jan) == 0);
9615 assert(monthsToMonth(Month.jan, Month.dec) == 11);
9616 assert(monthsToMonth(Month.jul, Month.oct) == 3);
9617 }
9618
9619 @safe unittest
9620 {
9621 assert(monthsToMonth(Month.jan, Month.jan) == 0);
9622 assert(monthsToMonth(Month.jan, Month.feb) == 1);
9623 assert(monthsToMonth(Month.jan, Month.mar) == 2);
9624 assert(monthsToMonth(Month.jan, Month.apr) == 3);
9625 assert(monthsToMonth(Month.jan, Month.may) == 4);
9626 assert(monthsToMonth(Month.jan, Month.jun) == 5);
9627 assert(monthsToMonth(Month.jan, Month.jul) == 6);
9628 assert(monthsToMonth(Month.jan, Month.aug) == 7);
9629 assert(monthsToMonth(Month.jan, Month.sep) == 8);
9630 assert(monthsToMonth(Month.jan, Month.oct) == 9);
9631 assert(monthsToMonth(Month.jan, Month.nov) == 10);
9632 assert(monthsToMonth(Month.jan, Month.dec) == 11);
9633
9634 assert(monthsToMonth(Month.may, Month.jan) == 8);
9635 assert(monthsToMonth(Month.may, Month.feb) == 9);
9636 assert(monthsToMonth(Month.may, Month.mar) == 10);
9637 assert(monthsToMonth(Month.may, Month.apr) == 11);
9638 assert(monthsToMonth(Month.may, Month.may) == 0);
9639 assert(monthsToMonth(Month.may, Month.jun) == 1);
9640 assert(monthsToMonth(Month.may, Month.jul) == 2);
9641 assert(monthsToMonth(Month.may, Month.aug) == 3);
9642 assert(monthsToMonth(Month.may, Month.sep) == 4);
9643 assert(monthsToMonth(Month.may, Month.oct) == 5);
9644 assert(monthsToMonth(Month.may, Month.nov) == 6);
9645 assert(monthsToMonth(Month.may, Month.dec) == 7);
9646
9647 assert(monthsToMonth(Month.oct, Month.jan) == 3);
9648 assert(monthsToMonth(Month.oct, Month.feb) == 4);
9649 assert(monthsToMonth(Month.oct, Month.mar) == 5);
9650 assert(monthsToMonth(Month.oct, Month.apr) == 6);
9651 assert(monthsToMonth(Month.oct, Month.may) == 7);
9652 assert(monthsToMonth(Month.oct, Month.jun) == 8);
9653 assert(monthsToMonth(Month.oct, Month.jul) == 9);
9654 assert(monthsToMonth(Month.oct, Month.aug) == 10);
9655 assert(monthsToMonth(Month.oct, Month.sep) == 11);
9656 assert(monthsToMonth(Month.oct, Month.oct) == 0);
9657 assert(monthsToMonth(Month.oct, Month.nov) == 1);
9658 assert(monthsToMonth(Month.oct, Month.dec) == 2);
9659
9660 assert(monthsToMonth(Month.dec, Month.jan) == 1);
9661 assert(monthsToMonth(Month.dec, Month.feb) == 2);
9662 assert(monthsToMonth(Month.dec, Month.mar) == 3);
9663 assert(monthsToMonth(Month.dec, Month.apr) == 4);
9664 assert(monthsToMonth(Month.dec, Month.may) == 5);
9665 assert(monthsToMonth(Month.dec, Month.jun) == 6);
9666 assert(monthsToMonth(Month.dec, Month.jul) == 7);
9667 assert(monthsToMonth(Month.dec, Month.aug) == 8);
9668 assert(monthsToMonth(Month.dec, Month.sep) == 9);
9669 assert(monthsToMonth(Month.dec, Month.oct) == 10);
9670 assert(monthsToMonth(Month.dec, Month.nov) == 11);
9671 assert(monthsToMonth(Month.dec, Month.dec) == 0);
9672 }
9673
9674
9675 /++
9676 Whether the given Gregorian Year is a leap year.
9677
9678 Params:
9679 year = The year to to be tested.
9680 +/
9681 bool yearIsLeapYear(int year) @safe pure nothrow @nogc
9682 {
9683 if (year % 400 == 0)
9684 return true;
9685 if (year % 100 == 0)
9686 return false;
9687 return year % 4 == 0;
9688 }
9689
9690 ///
9691 @safe unittest
9692 {
9693 foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010])
9694 {
9695 assert(!yearIsLeapYear(year));
9696 assert(!yearIsLeapYear(-year));
9697 }
9698
9699 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
9700 {
9701 assert(yearIsLeapYear(year));
9702 assert(yearIsLeapYear(-year));
9703 }
9704 }
9705
9706 @safe unittest
9707 {
9708 import std.format : format;
9709 foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999,
9710 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011])
9711 {
9712 assert(!yearIsLeapYear(year), format("year: %s.", year));
9713 assert(!yearIsLeapYear(-year), format("year: %s.", year));
9714 }
9715
9716 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
9717 {
9718 assert(yearIsLeapYear(year), format("year: %s.", year));
9719 assert(yearIsLeapYear(-year), format("year: %s.", year));
9720 }
9721 }
9722
9723
9724 /++
9725 Whether the given type defines all of the necessary functions for it to
9726 function as a time point.
9727
9728 1. $(D T) must define a static property named $(D min) which is the smallest
9729 value of $(D T) as $(D Unqual!T).
9730
9731 2. $(D T) must define a static property named $(D max) which is the largest
9732 value of $(D T) as $(D Unqual!T).
9733
9734 3. $(D T) must define an $(D opBinary) for addition and subtraction that
9735 accepts $(REF Duration, core,time) and returns $(D Unqual!T).
9736
9737 4. $(D T) must define an $(D opOpAssign) for addition and subtraction that
9738 accepts $(REF Duration, core,time) and returns $(D ref Unqual!T).
9739
9740 5. $(D T) must define a $(D opBinary) for subtraction which accepts $(D T)
9741 and returns returns $(REF Duration, core,time).
9742 +/
9743 template isTimePoint(T)
9744 {
9745 import core.time : Duration;
9746 import std.traits : FunctionAttribute, functionAttributes, Unqual;
9747
9748 enum isTimePoint = hasMin &&
9749 hasMax &&
9750 hasOverloadedOpBinaryWithDuration &&
9751 hasOverloadedOpAssignWithDuration &&
9752 hasOverloadedOpBinaryWithSelf &&
9753 !is(U == Duration);
9754
9755 private:
9756
9757 alias U = Unqual!T;
9758
9759 enum hasMin = __traits(hasMember, T, "min") &&
9760 is(typeof(T.min) == U) &&
9761 is(typeof({static assert(__traits(isStaticFunction, T.min));}));
9762
9763 enum hasMax = __traits(hasMember, T, "max") &&
9764 is(typeof(T.max) == U) &&
9765 is(typeof({static assert(__traits(isStaticFunction, T.max));}));
9766
9767 enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) &&
9768 is(typeof(T.init - Duration.init) == U);
9769
9770 enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) &&
9771 is(typeof(U.init -= Duration.init) == U) &&
9772 is(typeof(
9773 {
9774 // Until the overload with TickDuration is removed, this is ambiguous.
9775 //alias add = U.opOpAssign!"+";
9776 //alias sub = U.opOpAssign!"-";
9777 U u;
9778 auto ref add() { return u += Duration.init; }
9779 auto ref sub() { return u -= Duration.init; }
9780 alias FA = FunctionAttribute;
9781 static assert((functionAttributes!add & FA.ref_) != 0);
9782 static assert((functionAttributes!sub & FA.ref_) != 0);
9783 }));
9784
9785 enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration);
9786 }
9787
9788 ///
9789 @safe unittest
9790 {
9791 import core.time : Duration;
9792 import std.datetime.interval : Interval;
9793 import std.datetime.systime : SysTime;
9794
9795 static assert(isTimePoint!Date);
9796 static assert(isTimePoint!DateTime);
9797 static assert(isTimePoint!SysTime);
9798 static assert(isTimePoint!TimeOfDay);
9799
9800 static assert(!isTimePoint!int);
9801 static assert(!isTimePoint!Duration);
9802 static assert(!isTimePoint!(Interval!SysTime));
9803 }
9804
9805 @safe unittest
9806 {
9807 import core.time;
9808 import std.datetime.interval;
9809 import std.datetime.systime;
9810 import std.meta : AliasSeq;
9811
9812 foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay))
9813 {
9814 static assert(isTimePoint!(const TP), TP.stringof);
9815 static assert(isTimePoint!(immutable TP), TP.stringof);
9816 }
9817
9818 foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date))
9819 static assert(!isTimePoint!T, T.stringof);
9820 }
9821
9822
9823 /++
9824 Whether all of the given strings are valid units of time.
9825
9826 $(D "nsecs") is not considered a valid unit of time. Nothing in std.datetime
9827 can handle precision greater than hnsecs, and the few functions in core.time
9828 which deal with "nsecs" deal with it explicitly.
9829 +/
9830 bool validTimeUnits(string[] units...) @safe pure nothrow @nogc
9831 {
9832 import std.algorithm.searching : canFind;
9833 foreach (str; units)
9834 {
9835 if (!canFind(timeStrings[], str))
9836 return false;
9837 }
9838 return true;
9839 }
9840
9841 ///
9842 @safe @nogc nothrow unittest
9843 {
9844 assert(validTimeUnits("msecs", "seconds", "minutes"));
9845 assert(validTimeUnits("days", "weeks", "months"));
9846 assert(!validTimeUnits("ms", "seconds", "minutes"));
9847 }
9848
9849
9850 /++
9851 Compares two time unit strings. $(D "years") are the largest units and
9852 $(D "hnsecs") are the smallest.
9853
9854 Returns:
9855 $(BOOKTABLE,
9856 $(TR $(TD this &lt; rhs) $(TD &lt; 0))
9857 $(TR $(TD this == rhs) $(TD 0))
9858 $(TR $(TD this &gt; rhs) $(TD &gt; 0))
9859 )
9860
9861 Throws:
9862 $(LREF DateTimeException) if either of the given strings is not a valid
9863 time unit string.
9864 +/
9865 int cmpTimeUnits(string lhs, string rhs) @safe pure
9866 {
9867 import std.algorithm.searching : countUntil;
9868 import std.exception : enforce;
9869 import std.format : format;
9870
9871 auto tstrings = timeStrings;
9872 immutable indexOfLHS = countUntil(tstrings, lhs);
9873 immutable indexOfRHS = countUntil(tstrings, rhs);
9874
9875 enforce(indexOfLHS != -1, format("%s is not a valid TimeString", lhs));
9876 enforce(indexOfRHS != -1, format("%s is not a valid TimeString", rhs));
9877
9878 if (indexOfLHS < indexOfRHS)
9879 return -1;
9880 if (indexOfLHS > indexOfRHS)
9881 return 1;
9882
9883 return 0;
9884 }
9885
9886 ///
9887 @safe pure unittest
9888 {
9889 assert(cmpTimeUnits("hours", "hours") == 0);
9890 assert(cmpTimeUnits("hours", "weeks") < 0);
9891 assert(cmpTimeUnits("months", "seconds") > 0);
9892 }
9893
9894 @safe unittest
9895 {
9896 foreach (i, outerUnits; timeStrings)
9897 {
9898 assert(cmpTimeUnits(outerUnits, outerUnits) == 0);
9899
9900 // For some reason, $ won't compile.
9901 foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length])
9902 assert(cmpTimeUnits(outerUnits, innerUnits) == -1);
9903 }
9904
9905 foreach (i, outerUnits; timeStrings)
9906 {
9907 foreach (innerUnits; timeStrings[0 .. i])
9908 assert(cmpTimeUnits(outerUnits, innerUnits) == 1);
9909 }
9910 }
9911
9912
9913 /++
9914 Compares two time unit strings at compile time. $(D "years") are the largest
9915 units and $(D "hnsecs") are the smallest.
9916
9917 This template is used instead of $(D cmpTimeUnits) because exceptions
9918 can't be thrown at compile time and $(D cmpTimeUnits) must enforce that
9919 the strings it's given are valid time unit strings. This template uses a
9920 template constraint instead.
9921
9922 Returns:
9923 $(BOOKTABLE,
9924 $(TR $(TD this &lt; rhs) $(TD &lt; 0))
9925 $(TR $(TD this == rhs) $(TD 0))
9926 $(TR $(TD this &gt; rhs) $(TD &gt; 0))
9927 )
9928 +/
9929 template CmpTimeUnits(string lhs, string rhs)
9930 if (validTimeUnits(lhs, rhs))
9931 {
9932 enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs);
9933 }
9934
9935
9936 // Helper function for CmpTimeUnits.
9937 private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc
9938 {
9939 import std.algorithm.searching : countUntil;
9940 auto tstrings = timeStrings;
9941 immutable indexOfLHS = countUntil(tstrings, lhs);
9942 immutable indexOfRHS = countUntil(tstrings, rhs);
9943
9944 if (indexOfLHS < indexOfRHS)
9945 return -1;
9946 if (indexOfLHS > indexOfRHS)
9947 return 1;
9948
9949 return 0;
9950 }
9951
9952 @safe unittest
9953 {
9954 import std.format : format;
9955 import std.meta : AliasSeq;
9956
9957 static string genTest(size_t index)
9958 {
9959 auto currUnits = timeStrings[index];
9960 auto test = format(`assert(CmpTimeUnits!("%s", "%s") == 0);`, currUnits, currUnits);
9961
9962 foreach (units; timeStrings[index + 1 .. $])
9963 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == -1);`, currUnits, units);
9964
9965 foreach (units; timeStrings[0 .. index])
9966 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == 1);`, currUnits, units);
9967
9968 return test;
9969 }
9970
9971 static assert(timeStrings.length == 10);
9972 foreach (n; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
9973 mixin(genTest(n));
9974 }
9975
9976
9977 package:
9978
9979
9980 /+
9981 Array of the short (three letter) names of each month.
9982 +/
9983 immutable string[12] _monthNames = ["Jan",
9984 "Feb",
9985 "Mar",
9986 "Apr",
9987 "May",
9988 "Jun",
9989 "Jul",
9990 "Aug",
9991 "Sep",
9992 "Oct",
9993 "Nov",
9994 "Dec"];
9995
9996 /+
9997 The maximum valid Day in the given month in the given year.
9998
9999 Params:
10000 year = The year to get the day for.
10001 month = The month of the Gregorian Calendar to get the day for.
10002 +/
10003 ubyte maxDay(int year, int month) @safe pure nothrow @nogc
10004 in
10005 {
10006 assert(valid!"months"(month));
10007 }
10008 body
10009 {
10010 switch (month)
10011 {
10012 case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec:
10013 return 31;
10014 case Month.feb:
10015 return yearIsLeapYear(year) ? 29 : 28;
10016 case Month.apr, Month.jun, Month.sep, Month.nov:
10017 return 30;
10018 default:
10019 assert(0, "Invalid month.");
10020 }
10021 }
10022
10023 @safe unittest
10024 {
10025 // Test A.D.
10026 assert(maxDay(1999, 1) == 31);
10027 assert(maxDay(1999, 2) == 28);
10028 assert(maxDay(1999, 3) == 31);
10029 assert(maxDay(1999, 4) == 30);
10030 assert(maxDay(1999, 5) == 31);
10031 assert(maxDay(1999, 6) == 30);
10032 assert(maxDay(1999, 7) == 31);
10033 assert(maxDay(1999, 8) == 31);
10034 assert(maxDay(1999, 9) == 30);
10035 assert(maxDay(1999, 10) == 31);
10036 assert(maxDay(1999, 11) == 30);
10037 assert(maxDay(1999, 12) == 31);
10038
10039 assert(maxDay(2000, 1) == 31);
10040 assert(maxDay(2000, 2) == 29);
10041 assert(maxDay(2000, 3) == 31);
10042 assert(maxDay(2000, 4) == 30);
10043 assert(maxDay(2000, 5) == 31);
10044 assert(maxDay(2000, 6) == 30);
10045 assert(maxDay(2000, 7) == 31);
10046 assert(maxDay(2000, 8) == 31);
10047 assert(maxDay(2000, 9) == 30);
10048 assert(maxDay(2000, 10) == 31);
10049 assert(maxDay(2000, 11) == 30);
10050 assert(maxDay(2000, 12) == 31);
10051
10052 // Test B.C.
10053 assert(maxDay(-1999, 1) == 31);
10054 assert(maxDay(-1999, 2) == 28);
10055 assert(maxDay(-1999, 3) == 31);
10056 assert(maxDay(-1999, 4) == 30);
10057 assert(maxDay(-1999, 5) == 31);
10058 assert(maxDay(-1999, 6) == 30);
10059 assert(maxDay(-1999, 7) == 31);
10060 assert(maxDay(-1999, 8) == 31);
10061 assert(maxDay(-1999, 9) == 30);
10062 assert(maxDay(-1999, 10) == 31);
10063 assert(maxDay(-1999, 11) == 30);
10064 assert(maxDay(-1999, 12) == 31);
10065
10066 assert(maxDay(-2000, 1) == 31);
10067 assert(maxDay(-2000, 2) == 29);
10068 assert(maxDay(-2000, 3) == 31);
10069 assert(maxDay(-2000, 4) == 30);
10070 assert(maxDay(-2000, 5) == 31);
10071 assert(maxDay(-2000, 6) == 30);
10072 assert(maxDay(-2000, 7) == 31);
10073 assert(maxDay(-2000, 8) == 31);
10074 assert(maxDay(-2000, 9) == 30);
10075 assert(maxDay(-2000, 10) == 31);
10076 assert(maxDay(-2000, 11) == 30);
10077 assert(maxDay(-2000, 12) == 31);
10078 }
10079
10080 /+
10081 Splits out a particular unit from hnsecs and gives the value for that
10082 unit and the remaining hnsecs. It really shouldn't be used unless unless
10083 all units larger than the given units have already been split out.
10084
10085 Params:
10086 units = The units to split out.
10087 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left
10088 after splitting out the given units.
10089
10090 Returns:
10091 The number of the given units from converting hnsecs to those units.
10092 +/
10093 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc
10094 if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0)
10095 {
10096 import core.time : convert;
10097 immutable value = convert!("hnsecs", units)(hnsecs);
10098 hnsecs -= convert!(units, "hnsecs")(value);
10099 return value;
10100 }
10101
10102 @safe unittest
10103 {
10104 auto hnsecs = 2595000000007L;
10105 immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
10106 assert(days == 3);
10107 assert(hnsecs == 3000000007);
10108
10109 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
10110 assert(minutes == 5);
10111 assert(hnsecs == 7);
10112 }
10113
10114
10115 /+
10116 Returns the day of the week for the given day of the Gregorian Calendar.
10117
10118 Params:
10119 day = The day of the Gregorian Calendar for which to get the day of
10120 the week.
10121 +/
10122 DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc
10123 {
10124 // January 1st, 1 A.D. was a Monday
10125 if (day >= 0)
10126 return cast(DayOfWeek)(day % 7);
10127 else
10128 {
10129 immutable dow = cast(DayOfWeek)((day % 7) + 7);
10130
10131 if (dow == 7)
10132 return DayOfWeek.sun;
10133 else
10134 return dow;
10135 }
10136 }
10137
10138 @safe unittest
10139 {
10140 import std.datetime.systime : SysTime;
10141
10142 // Test A.D.
10143 assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon);
10144 assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue);
10145 assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed);
10146 assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu);
10147 assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri);
10148 assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat);
10149 assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun);
10150 assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon);
10151 assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue);
10152 assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue);
10153 assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed);
10154 assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu);
10155 assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
10156 assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
10157 assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun);
10158 assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon);
10159 assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue);
10160 assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed);
10161 assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu);
10162 assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri);
10163 assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat);
10164 assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun);
10165
10166 // Test B.C.
10167 assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun);
10168 assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat);
10169 assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri);
10170 assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu);
10171 assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed);
10172 assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue);
10173 assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon);
10174 assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun);
10175 assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat);
10176 }
10177
10178
10179 private:
10180
10181 enum daysInYear = 365; // The number of days in a non-leap year.
10182 enum daysInLeapYear = 366; // The numbef or days in a leap year.
10183 enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years.
10184 enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years.
10185 enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years.
10186
10187 /+
10188 Array of integers representing the last days of each month in a year.
10189 +/
10190 immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
10191
10192 /+
10193 Array of integers representing the last days of each month in a leap year.
10194 +/
10195 immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];
10196
10197
10198 /+
10199 Returns the string representation of the given month.
10200 +/
10201 string monthToString(Month month) @safe pure
10202 {
10203 import std.format : format;
10204 assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month));
10205 return _monthNames[month - Month.jan];
10206 }
10207
10208 @safe unittest
10209 {
10210 assert(monthToString(Month.jan) == "Jan");
10211 assert(monthToString(Month.feb) == "Feb");
10212 assert(monthToString(Month.mar) == "Mar");
10213 assert(monthToString(Month.apr) == "Apr");
10214 assert(monthToString(Month.may) == "May");
10215 assert(monthToString(Month.jun) == "Jun");
10216 assert(monthToString(Month.jul) == "Jul");
10217 assert(monthToString(Month.aug) == "Aug");
10218 assert(monthToString(Month.sep) == "Sep");
10219 assert(monthToString(Month.oct) == "Oct");
10220 assert(monthToString(Month.nov) == "Nov");
10221 assert(monthToString(Month.dec) == "Dec");
10222 }
10223
10224
10225 /+
10226 Returns the Month corresponding to the given string.
10227
10228 Params:
10229 monthStr = The string representation of the month to get the Month for.
10230
10231 Throws:
10232 $(REF DateTimeException,std,datetime,date) if the given month is not a
10233 valid month string.
10234 +/
10235 Month monthFromString(string monthStr) @safe pure
10236 {
10237 import std.format : format;
10238 switch (monthStr)
10239 {
10240 case "Jan":
10241 return Month.jan;
10242 case "Feb":
10243 return Month.feb;
10244 case "Mar":
10245 return Month.mar;
10246 case "Apr":
10247 return Month.apr;
10248 case "May":
10249 return Month.may;
10250 case "Jun":
10251 return Month.jun;
10252 case "Jul":
10253 return Month.jul;
10254 case "Aug":
10255 return Month.aug;
10256 case "Sep":
10257 return Month.sep;
10258 case "Oct":
10259 return Month.oct;
10260 case "Nov":
10261 return Month.nov;
10262 case "Dec":
10263 return Month.dec;
10264 default:
10265 throw new DateTimeException(format("Invalid month %s", monthStr));
10266 }
10267 }
10268
10269 @safe unittest
10270 {
10271 import std.stdio : writeln;
10272 import std.traits : EnumMembers;
10273 foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY",
10274 "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"])
10275 {
10276 scope(failure) writeln(badStr);
10277 assertThrown!DateTimeException(monthFromString(badStr));
10278 }
10279
10280 foreach (month; EnumMembers!Month)
10281 {
10282 scope(failure) writeln(month);
10283 assert(monthFromString(monthToString(month)) == month);
10284 }
10285 }
10286
10287
10288 version (unittest)
10289 {
10290 // All of these helper arrays are sorted in ascending order.
10291 auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
10292 auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
10293
10294 // I'd use a Tuple, but I get forward reference errors if I try.
10295 struct MonthDay
10296 {
10297 Month month;
10298 short day;
10299
10300 this(int m, short d)
10301 {
10302 month = cast(Month) m;
10303 day = d;
10304 }
10305 }
10306
10307 MonthDay[] testMonthDays = [MonthDay(1, 1),
10308 MonthDay(1, 2),
10309 MonthDay(3, 17),
10310 MonthDay(7, 4),
10311 MonthDay(10, 27),
10312 MonthDay(12, 30),
10313 MonthDay(12, 31)];
10314
10315 auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
10316
10317 auto testTODs = [TimeOfDay(0, 0, 0),
10318 TimeOfDay(0, 0, 1),
10319 TimeOfDay(0, 1, 0),
10320 TimeOfDay(1, 0, 0),
10321 TimeOfDay(13, 13, 13),
10322 TimeOfDay(23, 59, 59)];
10323
10324 auto testHours = [0, 1, 12, 22, 23];
10325 auto testMinSecs = [0, 1, 30, 58, 59];
10326
10327 // Throwing exceptions is incredibly expensive, so we want to use a smaller
10328 // set of values for tests using assertThrown.
10329 auto testTODsThrown = [TimeOfDay(0, 0, 0),
10330 TimeOfDay(13, 13, 13),
10331 TimeOfDay(23, 59, 59)];
10332
10333 Date[] testDatesBC;
10334 Date[] testDatesAD;
10335
10336 DateTime[] testDateTimesBC;
10337 DateTime[] testDateTimesAD;
10338
10339 // I'd use a Tuple, but I get forward reference errors if I try.
10340 struct GregDay { int day; Date date; }
10341 auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
10342 GregDay(-735_233, Date(-2012, 1, 1)),
10343 GregDay(-735_202, Date(-2012, 2, 1)),
10344 GregDay(-735_175, Date(-2012, 2, 28)),
10345 GregDay(-735_174, Date(-2012, 2, 29)),
10346 GregDay(-735_173, Date(-2012, 3, 1)),
10347 GregDay(-734_502, Date(-2010, 1, 1)),
10348 GregDay(-734_472, Date(-2010, 1, 31)),
10349 GregDay(-734_471, Date(-2010, 2, 1)),
10350 GregDay(-734_444, Date(-2010, 2, 28)),
10351 GregDay(-734_443, Date(-2010, 3, 1)),
10352 GregDay(-734_413, Date(-2010, 3, 31)),
10353 GregDay(-734_412, Date(-2010, 4, 1)),
10354 GregDay(-734_383, Date(-2010, 4, 30)),
10355 GregDay(-734_382, Date(-2010, 5, 1)),
10356 GregDay(-734_352, Date(-2010, 5, 31)),
10357 GregDay(-734_351, Date(-2010, 6, 1)),
10358 GregDay(-734_322, Date(-2010, 6, 30)),
10359 GregDay(-734_321, Date(-2010, 7, 1)),
10360 GregDay(-734_291, Date(-2010, 7, 31)),
10361 GregDay(-734_290, Date(-2010, 8, 1)),
10362 GregDay(-734_260, Date(-2010, 8, 31)),
10363 GregDay(-734_259, Date(-2010, 9, 1)),
10364 GregDay(-734_230, Date(-2010, 9, 30)),
10365 GregDay(-734_229, Date(-2010, 10, 1)),
10366 GregDay(-734_199, Date(-2010, 10, 31)),
10367 GregDay(-734_198, Date(-2010, 11, 1)),
10368 GregDay(-734_169, Date(-2010, 11, 30)),
10369 GregDay(-734_168, Date(-2010, 12, 1)),
10370 GregDay(-734_139, Date(-2010, 12, 30)),
10371 GregDay(-734_138, Date(-2010, 12, 31)),
10372 GregDay(-731_215, Date(-2001, 1, 1)),
10373 GregDay(-730_850, Date(-2000, 1, 1)),
10374 GregDay(-730_849, Date(-2000, 1, 2)),
10375 GregDay(-730_486, Date(-2000, 12, 30)),
10376 GregDay(-730_485, Date(-2000, 12, 31)),
10377 GregDay(-730_484, Date(-1999, 1, 1)),
10378 GregDay(-694_690, Date(-1901, 1, 1)),
10379 GregDay(-694_325, Date(-1900, 1, 1)),
10380 GregDay(-585_118, Date(-1601, 1, 1)),
10381 GregDay(-584_753, Date(-1600, 1, 1)),
10382 GregDay(-584_388, Date(-1600, 12, 31)),
10383 GregDay(-584_387, Date(-1599, 1, 1)),
10384 GregDay(-365_972, Date(-1001, 1, 1)),
10385 GregDay(-365_607, Date(-1000, 1, 1)),
10386 GregDay(-183_351, Date(-501, 1, 1)),
10387 GregDay(-182_986, Date(-500, 1, 1)),
10388 GregDay(-182_621, Date(-499, 1, 1)),
10389 GregDay(-146_827, Date(-401, 1, 1)),
10390 GregDay(-146_462, Date(-400, 1, 1)),
10391 GregDay(-146_097, Date(-400, 12, 31)),
10392 GregDay(-110_302, Date(-301, 1, 1)),
10393 GregDay(-109_937, Date(-300, 1, 1)),
10394 GregDay(-73_778, Date(-201, 1, 1)),
10395 GregDay(-73_413, Date(-200, 1, 1)),
10396 GregDay(-38_715, Date(-105, 1, 1)),
10397 GregDay(-37_254, Date(-101, 1, 1)),
10398 GregDay(-36_889, Date(-100, 1, 1)),
10399 GregDay(-36_524, Date(-99, 1, 1)),
10400 GregDay(-36_160, Date(-99, 12, 31)),
10401 GregDay(-35_794, Date(-97, 1, 1)),
10402 GregDay(-18_627, Date(-50, 1, 1)),
10403 GregDay(-18_262, Date(-49, 1, 1)),
10404 GregDay(-3652, Date(-9, 1, 1)),
10405 GregDay(-2191, Date(-5, 1, 1)),
10406 GregDay(-1827, Date(-5, 12, 31)),
10407 GregDay(-1826, Date(-4, 1, 1)),
10408 GregDay(-1825, Date(-4, 1, 2)),
10409 GregDay(-1462, Date(-4, 12, 30)),
10410 GregDay(-1461, Date(-4, 12, 31)),
10411 GregDay(-1460, Date(-3, 1, 1)),
10412 GregDay(-1096, Date(-3, 12, 31)),
10413 GregDay(-1095, Date(-2, 1, 1)),
10414 GregDay(-731, Date(-2, 12, 31)),
10415 GregDay(-730, Date(-1, 1, 1)),
10416 GregDay(-367, Date(-1, 12, 30)),
10417 GregDay(-366, Date(-1, 12, 31)),
10418 GregDay(-365, Date(0, 1, 1)),
10419 GregDay(-31, Date(0, 11, 30)),
10420 GregDay(-30, Date(0, 12, 1)),
10421 GregDay(-1, Date(0, 12, 30)),
10422 GregDay(0, Date(0, 12, 31))];
10423
10424 auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)),
10425 GregDay(2, Date(1, 1, 2)),
10426 GregDay(32, Date(1, 2, 1)),
10427 GregDay(365, Date(1, 12, 31)),
10428 GregDay(366, Date(2, 1, 1)),
10429 GregDay(731, Date(3, 1, 1)),
10430 GregDay(1096, Date(4, 1, 1)),
10431 GregDay(1097, Date(4, 1, 2)),
10432 GregDay(1460, Date(4, 12, 30)),
10433 GregDay(1461, Date(4, 12, 31)),
10434 GregDay(1462, Date(5, 1, 1)),
10435 GregDay(17_898, Date(50, 1, 1)),
10436 GregDay(35_065, Date(97, 1, 1)),
10437 GregDay(36_160, Date(100, 1, 1)),
10438 GregDay(36_525, Date(101, 1, 1)),
10439 GregDay(37_986, Date(105, 1, 1)),
10440 GregDay(72_684, Date(200, 1, 1)),
10441 GregDay(73_049, Date(201, 1, 1)),
10442 GregDay(109_208, Date(300, 1, 1)),
10443 GregDay(109_573, Date(301, 1, 1)),
10444 GregDay(145_732, Date(400, 1, 1)),
10445 GregDay(146_098, Date(401, 1, 1)),
10446 GregDay(182_257, Date(500, 1, 1)),
10447 GregDay(182_622, Date(501, 1, 1)),
10448 GregDay(364_878, Date(1000, 1, 1)),
10449 GregDay(365_243, Date(1001, 1, 1)),
10450 GregDay(584_023, Date(1600, 1, 1)),
10451 GregDay(584_389, Date(1601, 1, 1)),
10452 GregDay(693_596, Date(1900, 1, 1)),
10453 GregDay(693_961, Date(1901, 1, 1)),
10454 GregDay(729_755, Date(1999, 1, 1)),
10455 GregDay(730_120, Date(2000, 1, 1)),
10456 GregDay(730_121, Date(2000, 1, 2)),
10457 GregDay(730_484, Date(2000, 12, 30)),
10458 GregDay(730_485, Date(2000, 12, 31)),
10459 GregDay(730_486, Date(2001, 1, 1)),
10460 GregDay(733_773, Date(2010, 1, 1)),
10461 GregDay(733_774, Date(2010, 1, 2)),
10462 GregDay(733_803, Date(2010, 1, 31)),
10463 GregDay(733_804, Date(2010, 2, 1)),
10464 GregDay(733_831, Date(2010, 2, 28)),
10465 GregDay(733_832, Date(2010, 3, 1)),
10466 GregDay(733_862, Date(2010, 3, 31)),
10467 GregDay(733_863, Date(2010, 4, 1)),
10468 GregDay(733_892, Date(2010, 4, 30)),
10469 GregDay(733_893, Date(2010, 5, 1)),
10470 GregDay(733_923, Date(2010, 5, 31)),
10471 GregDay(733_924, Date(2010, 6, 1)),
10472 GregDay(733_953, Date(2010, 6, 30)),
10473 GregDay(733_954, Date(2010, 7, 1)),
10474 GregDay(733_984, Date(2010, 7, 31)),
10475 GregDay(733_985, Date(2010, 8, 1)),
10476 GregDay(734_015, Date(2010, 8, 31)),
10477 GregDay(734_016, Date(2010, 9, 1)),
10478 GregDay(734_045, Date(2010, 9, 30)),
10479 GregDay(734_046, Date(2010, 10, 1)),
10480 GregDay(734_076, Date(2010, 10, 31)),
10481 GregDay(734_077, Date(2010, 11, 1)),
10482 GregDay(734_106, Date(2010, 11, 30)),
10483 GregDay(734_107, Date(2010, 12, 1)),
10484 GregDay(734_136, Date(2010, 12, 30)),
10485 GregDay(734_137, Date(2010, 12, 31)),
10486 GregDay(734_503, Date(2012, 1, 1)),
10487 GregDay(734_534, Date(2012, 2, 1)),
10488 GregDay(734_561, Date(2012, 2, 28)),
10489 GregDay(734_562, Date(2012, 2, 29)),
10490 GregDay(734_563, Date(2012, 3, 1)),
10491 GregDay(734_858, Date(2012, 12, 21))];
10492
10493 // I'd use a Tuple, but I get forward reference errors if I try.
10494 struct DayOfYear { int day; MonthDay md; }
10495 auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)),
10496 DayOfYear(2, MonthDay(1, 2)),
10497 DayOfYear(3, MonthDay(1, 3)),
10498 DayOfYear(31, MonthDay(1, 31)),
10499 DayOfYear(32, MonthDay(2, 1)),
10500 DayOfYear(59, MonthDay(2, 28)),
10501 DayOfYear(60, MonthDay(3, 1)),
10502 DayOfYear(90, MonthDay(3, 31)),
10503 DayOfYear(91, MonthDay(4, 1)),
10504 DayOfYear(120, MonthDay(4, 30)),
10505 DayOfYear(121, MonthDay(5, 1)),
10506 DayOfYear(151, MonthDay(5, 31)),
10507 DayOfYear(152, MonthDay(6, 1)),
10508 DayOfYear(181, MonthDay(6, 30)),
10509 DayOfYear(182, MonthDay(7, 1)),
10510 DayOfYear(212, MonthDay(7, 31)),
10511 DayOfYear(213, MonthDay(8, 1)),
10512 DayOfYear(243, MonthDay(8, 31)),
10513 DayOfYear(244, MonthDay(9, 1)),
10514 DayOfYear(273, MonthDay(9, 30)),
10515 DayOfYear(274, MonthDay(10, 1)),
10516 DayOfYear(304, MonthDay(10, 31)),
10517 DayOfYear(305, MonthDay(11, 1)),
10518 DayOfYear(334, MonthDay(11, 30)),
10519 DayOfYear(335, MonthDay(12, 1)),
10520 DayOfYear(363, MonthDay(12, 29)),
10521 DayOfYear(364, MonthDay(12, 30)),
10522 DayOfYear(365, MonthDay(12, 31))];
10523
10524 auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)),
10525 DayOfYear(2, MonthDay(1, 2)),
10526 DayOfYear(3, MonthDay(1, 3)),
10527 DayOfYear(31, MonthDay(1, 31)),
10528 DayOfYear(32, MonthDay(2, 1)),
10529 DayOfYear(59, MonthDay(2, 28)),
10530 DayOfYear(60, MonthDay(2, 29)),
10531 DayOfYear(61, MonthDay(3, 1)),
10532 DayOfYear(91, MonthDay(3, 31)),
10533 DayOfYear(92, MonthDay(4, 1)),
10534 DayOfYear(121, MonthDay(4, 30)),
10535 DayOfYear(122, MonthDay(5, 1)),
10536 DayOfYear(152, MonthDay(5, 31)),
10537 DayOfYear(153, MonthDay(6, 1)),
10538 DayOfYear(182, MonthDay(6, 30)),
10539 DayOfYear(183, MonthDay(7, 1)),
10540 DayOfYear(213, MonthDay(7, 31)),
10541 DayOfYear(214, MonthDay(8, 1)),
10542 DayOfYear(244, MonthDay(8, 31)),
10543 DayOfYear(245, MonthDay(9, 1)),
10544 DayOfYear(274, MonthDay(9, 30)),
10545 DayOfYear(275, MonthDay(10, 1)),
10546 DayOfYear(305, MonthDay(10, 31)),
10547 DayOfYear(306, MonthDay(11, 1)),
10548 DayOfYear(335, MonthDay(11, 30)),
10549 DayOfYear(336, MonthDay(12, 1)),
10550 DayOfYear(364, MonthDay(12, 29)),
10551 DayOfYear(365, MonthDay(12, 30)),
10552 DayOfYear(366, MonthDay(12, 31))];
10553
10554 void initializeTests() @safe
10555 {
10556 foreach (year; testYearsBC)
10557 {
10558 foreach (md; testMonthDays)
10559 testDatesBC ~= Date(year, md.month, md.day);
10560 }
10561
10562 foreach (year; testYearsAD)
10563 {
10564 foreach (md; testMonthDays)
10565 testDatesAD ~= Date(year, md.month, md.day);
10566 }
10567
10568 foreach (dt; testDatesBC)
10569 {
10570 foreach (tod; testTODs)
10571 testDateTimesBC ~= DateTime(dt, tod);
10572 }
10573
10574 foreach (dt; testDatesAD)
10575 {
10576 foreach (tod; testTODs)
10577 testDateTimesAD ~= DateTime(dt, tod);
10578 }
10579 }
10580 }