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 +/
opCmpDateTime187 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 +/
timeOfDayDateTime449 @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 +/
timeOfDayDateTime480 @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 +/
yearBCDateTime576 @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 +/
yearBCDateTime613 @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 +/
dayDateTime716 @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
testDateTime734 static void test(DateTime dateTime, int expected)
735 {
736 assert(dateTime.day == expected, format("Value given: %s", dateTime));
737 }
738
foreachDateTime739 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 +/
dayDateTime765 @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 +/
minuteDateTime909 @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 +/
minuteDateTime936 @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
2158 /++
2159 Gives the result of adding or subtracting a duration from this
2160 $(LREF DateTime), as well as assigning the result to this
2161 $(LREF DateTime).
2162
2163 The legal types of arithmetic for $(LREF DateTime) using this operator
2164 are
2165
2166 $(BOOKTABLE,
2167 $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime))
2168 $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime))
2169 )
2170
2171 Params:
2172 duration = The duration to add to or subtract from this
2173 $(LREF DateTime).
2174 +/
2175 ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
2176 if (op == "+" || op == "-")
2177 {
2178 import core.time : convert;
2179 import std.format : format;
2180
2181 DateTime retval = this;
2182 immutable hnsecs = duration.total!"hnsecs";
2183
2184 mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op));
2185 }
2186
2187 @safe unittest
2188 {
2189 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) ==
2190 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2191 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) ==
2192 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2193 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) ==
2194 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2195 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) ==
2196 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2197
2198 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) ==
2199 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2200 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) ==
2201 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2202 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) ==
2203 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2204 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) ==
2205 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2206 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) ==
2207 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2208 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) ==
2209 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2210 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) ==
2211 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2212 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) ==
2213 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2214 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) ==
2215 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2216 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) ==
2217 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2218 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) ==
2219 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2220 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) ==
2221 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2222
2223 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) ==
2224 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33)));
2225 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) ==
2226 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33)));
2227 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) ==
2228 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33)));
2229 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) ==
2230 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33)));
2231
2232 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) ==
2233 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33)));
2234 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) ==
2235 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33)));
2236 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) ==
2237 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33)));
2238 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) ==
2239 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33)));
2240 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) ==
2241 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2242 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) ==
2243 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2244 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) ==
2245 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2246 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) ==
2247 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2248 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) ==
2249 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2250 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) ==
2251 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2252 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) ==
2253 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40)));
2254 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) ==
2255 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26)));
2256
2257 auto dt = DateTime(2000, 1, 31, 9, 7, 6);
2258 (dt += dur!"seconds"(92)) -= dur!"days"(-500);
2259 assert(dt == DateTime(2001, 6, 14, 9, 8, 38));
2260
2261 auto duration = dur!"seconds"(12);
2262 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2263 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2264 static assert(!__traits(compiles, cdt += duration));
2265 static assert(!__traits(compiles, idt += duration));
2266 static assert(!__traits(compiles, cdt -= duration));
2267 static assert(!__traits(compiles, idt -= duration));
2268 }
2269
2270
2271 /++
2272 Gives the difference between two $(LREF DateTime)s.
2273
2274 The legal types of arithmetic for $(LREF DateTime) using this operator are
2275
2276 $(BOOKTABLE,
2277 $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration))
2278 )
2279 +/
2280 Duration opBinary(string op)(in DateTime rhs) const @safe pure nothrow @nogc
2281 if (op == "-")
2282 {
2283 immutable dateResult = _date - rhs.date;
2284 immutable todResult = _tod - rhs._tod;
2285
2286 return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs");
2287 }
2288
2289 @safe unittest
2290 {
2291 auto dt = DateTime(1999, 7, 6, 12, 30, 33);
2292
2293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) ==
2294 dur!"seconds"(31_536_000));
2295 assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2296 dur!"seconds"(-31_536_000));
2297
2298 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2299 dur!"seconds"(26_78_400));
2300 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) ==
2301 dur!"seconds"(-26_78_400));
2302
2303 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) ==
2304 dur!"seconds"(86_400));
2305 assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2306 dur!"seconds"(-86_400));
2307
2308 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) ==
2309 dur!"seconds"(3600));
2310 assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2311 dur!"seconds"(-3600));
2312
2313 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2314 dur!"seconds"(60));
2315 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) ==
2316 dur!"seconds"(-60));
2317
2318 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) ==
2319 dur!"seconds"(1));
2320 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) ==
2321 dur!"seconds"(-1));
2322
2323 assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033));
2324 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033));
2325 assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367));
2326 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367));
2327
2328 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2329 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2330 assert(dt - dt == Duration.zero);
2331 assert(cdt - dt == Duration.zero);
2332 assert(idt - dt == Duration.zero);
2333
2334 assert(dt - cdt == Duration.zero);
2335 assert(cdt - cdt == Duration.zero);
2336 assert(idt - cdt == Duration.zero);
2337
2338 assert(dt - idt == Duration.zero);
2339 assert(cdt - idt == Duration.zero);
2340 assert(idt - idt == Duration.zero);
2341 }
2342
2343
2344 /++
2345 Returns the difference between the two $(LREF DateTime)s in months.
2346
2347 To get the difference in years, subtract the year property
2348 of two $(LREF DateTime)s. To get the difference in days or weeks,
2349 subtract the $(LREF DateTime)s themselves and use the
2350 $(REF Duration, core,time) that results. Because converting between
2351 months and smaller units requires a specific date (which
2352 $(REF Duration, core,time)s don't have), getting the difference in
2353 months requires some math using both the year and month properties, so
2354 this is a convenience function for getting the difference in months.
2355
2356 Note that the number of days in the months or how far into the month
2357 either date is is irrelevant. It is the difference in the month property
2358 combined with the difference in years * 12. So, for instance,
2359 December 31st and January 1st are one month apart just as December 1st
2360 and January 31st are one month apart.
2361
2362 Params:
2363 rhs = The $(LREF DateTime) to subtract from this one.
2364 +/
diffMonthsDateTime2365 int diffMonths(in DateTime rhs) const @safe pure nothrow @nogc
2366 {
2367 return _date.diffMonths(rhs._date);
2368 }
2369
2370 ///
2371 @safe unittest
2372 {
2373 assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths(
2374 DateTime(1999, 1, 31, 23, 59, 59)) == 1);
2375
2376 assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths(
2377 DateTime(1999, 2, 1, 12, 3, 42)) == -1);
2378
2379 assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths(
2380 DateTime(1999, 1, 1, 2, 4, 7)) == 2);
2381
2382 assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths(
2383 DateTime(1999, 3, 31, 0, 30, 58)) == -2);
2384 }
2385
2386 @safe unittest
2387 {
2388 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2389 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2390 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2391 assert(dt.diffMonths(dt) == 0);
2392 assert(cdt.diffMonths(dt) == 0);
2393 assert(idt.diffMonths(dt) == 0);
2394
2395 assert(dt.diffMonths(cdt) == 0);
2396 assert(cdt.diffMonths(cdt) == 0);
2397 assert(idt.diffMonths(cdt) == 0);
2398
2399 assert(dt.diffMonths(idt) == 0);
2400 assert(cdt.diffMonths(idt) == 0);
2401 assert(idt.diffMonths(idt) == 0);
2402 }
2403
2404
2405 /++
2406 Whether this $(LREF DateTime) is in a leap year.
2407 +/
isLeapYearDateTime2408 @property bool isLeapYear() const @safe pure nothrow @nogc
2409 {
2410 return _date.isLeapYear;
2411 }
2412
2413 @safe unittest
2414 {
2415 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2416 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2417 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2418 assert(!dt.isLeapYear);
2419 assert(!cdt.isLeapYear);
2420 assert(!idt.isLeapYear);
2421 }
2422
2423
2424 /++
2425 Day of the week this $(LREF DateTime) is on.
2426 +/
dayOfWeekDateTime2427 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc
2428 {
2429 return _date.dayOfWeek;
2430 }
2431
2432 @safe unittest
2433 {
2434 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2435 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2436 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2437 assert(dt.dayOfWeek == DayOfWeek.tue);
2438 assert(cdt.dayOfWeek == DayOfWeek.tue);
2439 assert(idt.dayOfWeek == DayOfWeek.tue);
2440 }
2441
2442
2443 /++
2444 Day of the year this $(LREF DateTime) is on.
2445 +/
dayOfYearDateTime2446 @property ushort dayOfYear() const @safe pure nothrow @nogc
2447 {
2448 return _date.dayOfYear;
2449 }
2450
2451 ///
2452 @safe unittest
2453 {
2454 assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1);
2455 assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365);
2456 assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366);
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.dayOfYear == 187);
2465 assert(cdt.dayOfYear == 187);
2466 assert(idt.dayOfYear == 187);
2467 }
2468
2469
2470 /++
2471 Day of the year.
2472
2473 Params:
2474 day = The day of the year to set which day of the year this
2475 $(LREF DateTime) is on.
2476 +/
dayOfYearDateTime2477 @property void dayOfYear(int day) @safe pure
2478 {
2479 _date.dayOfYear = day;
2480 }
2481
2482 @safe unittest
2483 {
2484 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2485 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2486 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2487 dt.dayOfYear = 12;
2488 assert(dt.dayOfYear == 12);
2489 static assert(!__traits(compiles, cdt.dayOfYear = 12));
2490 static assert(!__traits(compiles, idt.dayOfYear = 12));
2491 }
2492
2493
2494 /++
2495 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on.
2496 +/
dayOfGregorianCalDateTime2497 @property int dayOfGregorianCal() const @safe pure nothrow @nogc
2498 {
2499 return _date.dayOfGregorianCal;
2500 }
2501
2502 ///
2503 @safe unittest
2504 {
2505 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1);
2506 assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365);
2507 assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366);
2508
2509 assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0);
2510 assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365);
2511 assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366);
2512
2513 assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120);
2514 assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137);
2515 }
2516
2517 @safe unittest
2518 {
2519 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2520 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2521 assert(cdt.dayOfGregorianCal == 729_941);
2522 assert(idt.dayOfGregorianCal == 729_941);
2523 }
2524
2525
2526 /++
2527 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on.
2528 Setting this property does not affect the time portion of
2529 $(LREF DateTime).
2530
2531 Params:
2532 days = The day of the Gregorian Calendar to set this $(LREF DateTime)
2533 to.
2534 +/
dayOfGregorianCalDateTime2535 @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc
2536 {
2537 _date.dayOfGregorianCal = days;
2538 }
2539
2540 ///
2541 @safe unittest
2542 {
2543 auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0));
2544 dt.dayOfGregorianCal = 1;
2545 assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)));
2546
2547 dt.dayOfGregorianCal = 365;
2548 assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0)));
2549
2550 dt.dayOfGregorianCal = 366;
2551 assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0)));
2552
2553 dt.dayOfGregorianCal = 0;
2554 assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)));
2555
2556 dt.dayOfGregorianCal = -365;
2557 assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0)));
2558
2559 dt.dayOfGregorianCal = -366;
2560 assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0)));
2561
2562 dt.dayOfGregorianCal = 730_120;
2563 assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0)));
2564
2565 dt.dayOfGregorianCal = 734_137;
2566 assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0)));
2567 }
2568
2569 @safe unittest
2570 {
2571 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2572 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2573 static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7));
2574 static assert(!__traits(compiles, idt.dayOfGregorianCal = 7));
2575 }
2576
2577
2578 /++
2579 The ISO 8601 week of the year that this $(LREF DateTime) is in.
2580
2581 See_Also:
2582 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
2583 +/
isoWeekDateTime2584 @property ubyte isoWeek() const @safe pure nothrow
2585 {
2586 return _date.isoWeek;
2587 }
2588
2589 @safe unittest
2590 {
2591 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
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(dt.isoWeek == 27);
2595 assert(cdt.isoWeek == 27);
2596 assert(idt.isoWeek == 27);
2597 }
2598
2599
2600 /++
2601 $(LREF DateTime) for the last day in the month that this
2602 $(LREF DateTime) is in. The time portion of endOfMonth is always
2603 23:59:59.
2604 +/
endOfMonthDateTime2605 @property DateTime endOfMonth() const @safe pure nothrow
2606 {
2607 try
2608 return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59));
2609 catch (Exception e)
2610 assert(0, "DateTime constructor threw.");
2611 }
2612
2613 ///
2614 @safe unittest
2615 {
2616 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth ==
2617 DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59)));
2618
2619 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth ==
2620 DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59)));
2621
2622 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth ==
2623 DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59)));
2624
2625 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth ==
2626 DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59)));
2627 }
2628
2629 @safe unittest
2630 {
2631 // Test A.D.
2632 assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59));
2633 assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59));
2634 assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59));
2635 assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59));
2636 assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59));
2637 assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59));
2638 assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59));
2639 assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2640 assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59));
2641 assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59));
2642 assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59));
2643 assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59));
2644 assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59));
2645
2646 // Test B.C.
2647 assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59));
2648 assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59));
2649 assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59));
2650 assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59));
2651 assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59));
2652 assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59));
2653 assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59));
2654 assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59));
2655 assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59));
2656 assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59));
2657 assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59));
2658 assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59));
2659 assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59));
2660
2661 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2662 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2663 assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2664 assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59));
2665 }
2666
2667
2668 /++
2669 The last day in the month that this $(LREF DateTime) is in.
2670 +/
daysInMonthDateTime2671 @property ubyte daysInMonth() const @safe pure nothrow @nogc
2672 {
2673 return _date.daysInMonth;
2674 }
2675
2676 ///
2677 @safe unittest
2678 {
2679 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31);
2680 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28);
2681 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29);
2682 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30);
2683 }
2684
2685 @safe unittest
2686 {
2687 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2688 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2689 assert(cdt.daysInMonth == 31);
2690 assert(idt.daysInMonth == 31);
2691 }
2692
2693
2694 /++
2695 Whether the current year is a date in A.D.
2696 +/
isADDateTime2697 @property bool isAD() const @safe pure nothrow @nogc
2698 {
2699 return _date.isAD;
2700 }
2701
2702 ///
2703 @safe unittest
2704 {
2705 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD);
2706 assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD);
2707 assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD);
2708 assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD);
2709 }
2710
2711 @safe unittest
2712 {
2713 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2714 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2715 assert(cdt.isAD);
2716 assert(idt.isAD);
2717 }
2718
2719
2720 /++
2721 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this
2722 $(LREF DateTime) at the given time. For example, prior to noon,
2723 1996-03-31 would be the Julian day number 2_450_173, so this function
2724 returns 2_450_173, while from noon onward, the julian day number would
2725 be 2_450_174, so this function returns 2_450_174.
2726 +/
julianDayDateTime2727 @property long julianDay() const @safe pure nothrow @nogc
2728 {
2729 if (_tod._hour < 12)
2730 return _date.julianDay - 1;
2731 else
2732 return _date.julianDay;
2733 }
2734
2735 @safe unittest
2736 {
2737 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1);
2738 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0);
2739
2740 assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424);
2741 assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425);
2742
2743 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425);
2744 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426);
2745
2746 assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160);
2747 assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161);
2748
2749 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000);
2750 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001);
2751
2752 assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973);
2753 assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974);
2754
2755 assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173);
2756 assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174);
2757
2758 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432);
2759 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433);
2760
2761 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2762 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2763 assert(cdt.julianDay == 2_451_366);
2764 assert(idt.julianDay == 2_451_366);
2765 }
2766
2767
2768 /++
2769 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any
2770 time on this date (since, the modified Julian day changes at midnight).
2771 +/
modJulianDayDateTime2772 @property long modJulianDay() const @safe pure nothrow @nogc
2773 {
2774 return _date.modJulianDay;
2775 }
2776
2777 @safe unittest
2778 {
2779 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0);
2780 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0);
2781
2782 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432);
2783 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432);
2784
2785 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2786 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
2787 assert(cdt.modJulianDay == 51_365);
2788 assert(idt.modJulianDay == 51_365);
2789 }
2790
2791
2792 /++
2793 Converts this $(LREF DateTime) to a string with the format YYYYMMDDTHHMMSS.
2794 +/
toISOStringDateTime2795 string toISOString() const @safe pure nothrow
2796 {
2797 import std.format : format;
2798 try
2799 {
2800 return format!("%sT%02d%02d%02d")(
2801 _date.toISOString(),
2802 _tod._hour,
2803 _tod._minute,
2804 _tod._second
2805 );
2806 }
2807 catch (Exception e)
2808 {
2809 assert(0, "format() threw.");
2810 }
2811 }
2812
2813 ///
2814 @safe unittest
2815 {
2816 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() ==
2817 "20100704T070612");
2818
2819 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() ==
2820 "19981225T021500");
2821
2822 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() ==
2823 "00000105T230959");
2824
2825 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() ==
2826 "-00040105T000002");
2827 }
2828
2829 @safe unittest
2830 {
2831 // Test A.D.
2832 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000");
2833 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612");
2834 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459");
2835 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959");
2836 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101");
2837
2838 // Test B.C.
2839 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204");
2840 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000");
2841 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612");
2842 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459");
2843 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959");
2844 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101");
2845
2846 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2847 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2848 assert(cdt.toISOString() == "19990706T123033");
2849 assert(idt.toISOString() == "19990706T123033");
2850 }
2851
2852
2853 /++
2854 Converts this $(LREF DateTime) to a string with the format
2855 YYYY-MM-DDTHH:MM:SS.
2856 +/
toISOExtStringDateTime2857 string toISOExtString() const @safe pure nothrow
2858 {
2859 import std.format : format;
2860 try
2861 {
2862 return format!("%sT%02d:%02d:%02d")(
2863 _date.toISOExtString(),
2864 _tod._hour,
2865 _tod._minute,
2866 _tod._second
2867 );
2868 }
2869 catch (Exception e)
2870 {
2871 assert(0, "format() threw.");
2872 }
2873 }
2874
2875 ///
2876 @safe unittest
2877 {
2878 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() ==
2879 "2010-07-04T07:06:12");
2880
2881 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() ==
2882 "1998-12-25T02:15:00");
2883
2884 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() ==
2885 "0000-01-05T23:09:59");
2886
2887 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() ==
2888 "-0004-01-05T00:00:02");
2889 }
2890
2891 @safe unittest
2892 {
2893 // Test A.D.
2894 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00");
2895 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12");
2896 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59");
2897 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59");
2898 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01");
2899
2900 // Test B.C.
2901 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04");
2902 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00");
2903 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12");
2904 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59");
2905 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59");
2906 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01");
2907
2908 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2909 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2910 assert(cdt.toISOExtString() == "1999-07-06T12:30:33");
2911 assert(idt.toISOExtString() == "1999-07-06T12:30:33");
2912 }
2913
2914 /++
2915 Converts this $(LREF DateTime) to a string with the format
2916 YYYY-Mon-DD HH:MM:SS.
2917 +/
toSimpleStringDateTime2918 string toSimpleString() const @safe pure nothrow
2919 {
2920 import std.format : format;
2921 try
2922 {
2923 return format!("%s %02d:%02d:%02d")(
2924 _date.toSimpleString(),
2925 _tod._hour,
2926 _tod._minute,
2927 _tod._second
2928 );
2929 }
2930 catch (Exception e)
2931 {
2932 assert(0, "format() threw.");
2933 }
2934 }
2935
2936 ///
2937 @safe unittest
2938 {
2939 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() ==
2940 "2010-Jul-04 07:06:12");
2941
2942 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() ==
2943 "1998-Dec-25 02:15:00");
2944
2945 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() ==
2946 "0000-Jan-05 23:09:59");
2947
2948 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() ==
2949 "-0004-Jan-05 00:00:02");
2950 }
2951
2952 @safe unittest
2953 {
2954 // Test A.D.
2955 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00");
2956 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12");
2957 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59");
2958 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59");
2959 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01");
2960
2961 // Test B.C.
2962 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04");
2963 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00");
2964 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12");
2965 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59");
2966 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59");
2967 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01");
2968
2969 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
2970 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
2971 assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33");
2972 assert(idt.toSimpleString() == "1999-Jul-06 12:30:33");
2973 }
2974
2975
2976 /++
2977 Converts this $(LREF DateTime) to a string.
2978
2979 This function exists to make it easy to convert a $(LREF DateTime) to a
2980 string for code that does not care what the exact format is - just that
2981 it presents the information in a clear manner. It also makes it easy to
2982 simply convert a $(LREF DateTime) to a string when using functions such
2983 as `to!string`, `format`, or `writeln` which use toString to convert
2984 user-defined types. So, it is unlikely that much code will call
2985 toString directly.
2986
2987 The format of the string is purposefully unspecified, and code that
2988 cares about the format of the string should use `toISOString`,
2989 `toISOExtString`, `toSimpleString`, or some other custom formatting
2990 function that explicitly generates the format that the code needs. The
2991 reason is that the code is then clear about what format it's using,
2992 making it less error-prone to maintain the code and interact with other
2993 software that consumes the generated strings. It's for this same reason
2994 that $(LREF DateTime) has no `fromString` function, whereas it does have
2995 `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
2996
2997 The format returned by toString may or may not change in the future.
2998 +/
toStringDateTime2999 string toString() const @safe pure nothrow
3000 {
3001 return toSimpleString();
3002 }
3003
3004 @safe unittest
3005 {
3006 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3007 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3008 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33));
3009 assert(dt.toString());
3010 assert(cdt.toString());
3011 assert(idt.toString());
3012 }
3013
3014
3015
3016 /++
3017 Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS.
3018 Whitespace is stripped from the given string.
3019
3020 Params:
3021 isoString = A string formatted in the ISO format for dates and times.
3022
3023 Throws:
3024 $(REF DateTimeException,std,datetime,date) if the given string is
3025 not in the ISO format or if the resulting $(LREF DateTime) would not
3026 be valid.
3027 +/
3028 static DateTime fromISOString(S)(in S isoString) @safe pure
3029 if (isSomeString!S)
3030 {
3031 import std.algorithm.searching : countUntil;
3032 import std.exception : enforce;
3033 import std.format : format;
3034 import std.string : strip;
3035
3036 auto str = strip(isoString);
3037
3038 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString)));
3039 auto t = str.countUntil('T');
3040
3041 enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString)));
3042
3043 immutable date = Date.fromISOString(str[0 .. t]);
3044 immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]);
3045
3046 return DateTime(date, tod);
3047 }
3048
3049 ///
3050 @safe unittest
3051 {
3052 assert(DateTime.fromISOString("20100704T070612") ==
3053 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3054
3055 assert(DateTime.fromISOString("19981225T021500") ==
3056 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3057
3058 assert(DateTime.fromISOString("00000105T230959") ==
3059 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3060
3061 assert(DateTime.fromISOString("-00040105T000002") ==
3062 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3063
3064 assert(DateTime.fromISOString(" 20100704T070612 ") ==
3065 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3066 }
3067
3068 @safe unittest
3069 {
3070 assertThrown!DateTimeException(DateTime.fromISOString(""));
3071 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
3072 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
3073 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
3074 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
3075 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
3076
3077 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
3078 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
3079 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
3080 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
3081 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
3082
3083 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
3084 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
3085 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
3086 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
3087 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
3088 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
3089
3090 assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201"));
3091 assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01"));
3092
3093 assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3094 assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3095 assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3096 assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3097 assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3098 assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3099 assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3100 }
3101
3102 // bug# 17801
3103 @safe unittest
3104 {
3105 import std.conv : to;
3106 import std.meta : AliasSeq;
3107 foreach (C; AliasSeq!(char, wchar, dchar))
3108 {
3109 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3110 assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16));
3111 }
3112 }
3113
3114
3115 /++
3116 Creates a $(LREF DateTime) from a string with the format
3117 YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string.
3118
3119 Params:
3120 isoExtString = A string formatted in the ISO Extended format for dates
3121 and times.
3122
3123 Throws:
3124 $(REF DateTimeException,std,datetime,date) if the given string is
3125 not in the ISO Extended format or if the resulting $(LREF DateTime)
3126 would not be valid.
3127 +/
3128 static DateTime fromISOExtString(S)(in S isoExtString) @safe pure
3129 if (isSomeString!(S))
3130 {
3131 import std.algorithm.searching : countUntil;
3132 import std.exception : enforce;
3133 import std.format : format;
3134 import std.string : strip;
3135
3136 auto str = strip(isoExtString);
3137
3138 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
3139 auto t = str.countUntil('T');
3140
3141 enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
3142
3143 immutable date = Date.fromISOExtString(str[0 .. t]);
3144 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
3145
3146 return DateTime(date, tod);
3147 }
3148
3149 ///
3150 @safe unittest
3151 {
3152 assert(DateTime.fromISOExtString("2010-07-04T07:06:12") ==
3153 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3154
3155 assert(DateTime.fromISOExtString("1998-12-25T02:15:00") ==
3156 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3157
3158 assert(DateTime.fromISOExtString("0000-01-05T23:09:59") ==
3159 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3160
3161 assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") ==
3162 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3163
3164 assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") ==
3165 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3166 }
3167
3168 @safe unittest
3169 {
3170 assertThrown!DateTimeException(DateTime.fromISOExtString(""));
3171 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000"));
3172 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000"));
3173 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000"));
3174 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000."));
3175 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0"));
3176
3177 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00"));
3178 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
3179 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00"));
3180 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00"));
3181 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00."));
3182 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0"));
3183
3184 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00"));
3185 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00"));
3186 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00."));
3187 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0"));
3188
3189 assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201"));
3190 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01"));
3191
3192 assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3193 assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3194 assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3195 assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3196 assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3197 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3198 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3199 }
3200
3201 // bug# 17801
3202 @safe unittest
3203 {
3204 import std.conv : to;
3205 import std.meta : AliasSeq;
3206 foreach (C; AliasSeq!(char, wchar, dchar))
3207 {
3208 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3209 assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
3210 }
3211 }
3212
3213
3214 /++
3215 Creates a $(LREF DateTime) from a string with the format
3216 YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string.
3217
3218 Params:
3219 simpleString = A string formatted in the way that toSimpleString
3220 formats dates and times.
3221
3222 Throws:
3223 $(REF DateTimeException,std,datetime,date) if the given string is
3224 not in the correct format or if the resulting $(LREF DateTime)
3225 would not be valid.
3226 +/
3227 static DateTime fromSimpleString(S)(in S simpleString) @safe pure
3228 if (isSomeString!(S))
3229 {
3230 import std.algorithm.searching : countUntil;
3231 import std.exception : enforce;
3232 import std.format : format;
3233 import std.string : strip;
3234
3235 auto str = strip(simpleString);
3236
3237 enforce(str.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString)));
3238 auto t = str.countUntil(' ');
3239
3240 enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString)));
3241
3242 immutable date = Date.fromSimpleString(str[0 .. t]);
3243 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]);
3244
3245 return DateTime(date, tod);
3246 }
3247
3248 ///
3249 @safe unittest
3250 {
3251 assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") ==
3252 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3253 assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") ==
3254 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)));
3255 assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") ==
3256 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)));
3257 assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") ==
3258 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)));
3259 assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") ==
3260 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)));
3261 }
3262
3263 @safe unittest
3264 {
3265 assertThrown!DateTimeException(DateTime.fromISOString(""));
3266 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000"));
3267 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000"));
3268 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000"));
3269 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000."));
3270 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0"));
3271
3272 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00"));
3273 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00"));
3274 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00"));
3275 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00."));
3276 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0"));
3277
3278 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00"));
3279 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00"));
3280 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00"));
3281 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00"));
3282 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00."));
3283 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0"));
3284
3285 assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201"));
3286 assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201"));
3287
3288 assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") ==
3289 DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
3290 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") ==
3291 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3292 assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") ==
3293 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
3294 assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") ==
3295 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3296 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") ==
3297 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3298 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") ==
3299 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3300 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") ==
3301 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
3302 }
3303
3304 // bug# 17801
3305 @safe unittest
3306 {
3307 import std.conv : to;
3308 import std.meta : AliasSeq;
3309 foreach (C; AliasSeq!(char, wchar, dchar))
3310 {
3311 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
3312 assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16));
3313 }
3314 }
3315
3316
3317 /++
3318 Returns the $(LREF DateTime) farthest in the past which is representable
3319 by $(LREF DateTime).
3320 +/
minDateTime3321 @property static DateTime min() @safe pure nothrow @nogc
3322 out(result)
3323 {
3324 assert(result._date == Date.min);
3325 assert(result._tod == TimeOfDay.min);
3326 }
3327 body
3328 {
3329 auto dt = DateTime.init;
3330 dt._date._year = short.min;
3331 dt._date._month = Month.jan;
3332 dt._date._day = 1;
3333
3334 return dt;
3335 }
3336
3337 @safe unittest
3338 {
3339 assert(DateTime.min.year < 0);
3340 assert(DateTime.min < DateTime.max);
3341 }
3342
3343
3344 /++
3345 Returns the $(LREF DateTime) farthest in the future which is
3346 representable by $(LREF DateTime).
3347 +/
maxDateTime3348 @property static DateTime max() @safe pure nothrow @nogc
3349 out(result)
3350 {
3351 assert(result._date == Date.max);
3352 assert(result._tod == TimeOfDay.max);
3353 }
3354 body
3355 {
3356 auto dt = DateTime.init;
3357 dt._date._year = short.max;
3358 dt._date._month = Month.dec;
3359 dt._date._day = 31;
3360 dt._tod._hour = TimeOfDay.maxHour;
3361 dt._tod._minute = TimeOfDay.maxMinute;
3362 dt._tod._second = TimeOfDay.maxSecond;
3363
3364 return dt;
3365 }
3366
3367 @safe unittest
3368 {
3369 assert(DateTime.max.year > 0);
3370 assert(DateTime.max > DateTime.min);
3371 }
3372
3373
3374 private:
3375
3376 /+
3377 Add seconds to the time of day. Negative values will subtract. If the
3378 number of seconds overflows (or underflows), then the seconds will wrap,
3379 increasing (or decreasing) the number of minutes accordingly. The
3380 same goes for any larger units.
3381
3382 Params:
3383 seconds = The number of seconds to add to this $(LREF DateTime).
3384 +/
3385 ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc
3386 {
3387 long hnsecs = convert!("seconds", "hnsecs")(seconds);
3388 hnsecs += convert!("hours", "hnsecs")(_tod._hour);
3389 hnsecs += convert!("minutes", "hnsecs")(_tod._minute);
3390 hnsecs += convert!("seconds", "hnsecs")(_tod._second);
3391
3392 auto days = splitUnitsFromHNSecs!"days"(hnsecs);
3393
3394 if (hnsecs < 0)
3395 {
3396 hnsecs += convert!("days", "hnsecs")(1);
3397 --days;
3398 }
3399
3400 _date._addDays(days);
3401
3402 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
3403 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
3404 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
3405
3406 _tod._hour = cast(ubyte) newHours;
3407 _tod._minute = cast(ubyte) newMinutes;
3408 _tod._second = cast(ubyte) newSeconds;
3409
3410 return this;
3411 }
3412
3413 @safe unittest
3414 {
3415 static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__)
3416 {
3417 orig._addSeconds(seconds);
3418 assert(orig == expected);
3419 }
3420
3421 // Test A.D.
3422 testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33));
3423 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34));
3424 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35));
3425 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36));
3426 testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37));
3427 testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38));
3428 testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43));
3429 testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48));
3430 testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59));
3431 testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0));
3432 testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3));
3433 testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32));
3434 testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33));
3435 testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34));
3436
3437 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59));
3438 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0));
3439 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1));
3440 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0));
3441 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32));
3442 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33));
3443 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34));
3444 testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33));
3445 testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3));
3446
3447 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32));
3448 testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31));
3449 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30));
3450 testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29));
3451 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28));
3452 testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23));
3453 testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18));
3454 testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0));
3455 testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59));
3456 testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58));
3457 testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34));
3458 testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33));
3459 testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32));
3460
3461 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0));
3462 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59));
3463 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33));
3464 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32));
3465 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59));
3466 testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57));
3467
3468 testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1));
3469 testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0));
3470 testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59));
3471
3472 testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1));
3473 testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0));
3474 testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59));
3475
3476 testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1));
3477 testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0));
3478 testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59));
3479
3480 testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0));
3481 testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59));
3482 testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58));
3483
3484 testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0));
3485 testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59));
3486 testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58));
3487
3488 testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1));
3489 testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0));
3490 testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59));
3491
3492 // Test B.C.
3493 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33));
3494 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34));
3495 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35));
3496 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36));
3497 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37));
3498 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38));
3499 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43));
3500 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48));
3501 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59));
3502 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0));
3503 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3));
3504 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32));
3505 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33));
3506 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34));
3507
3508 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59));
3509 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0));
3510 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1));
3511 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0));
3512 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32));
3513 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33));
3514 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34));
3515 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33));
3516 testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3));
3517
3518 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32));
3519 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31));
3520 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30));
3521 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29));
3522 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28));
3523 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23));
3524 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18));
3525 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0));
3526 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59));
3527 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58));
3528 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34));
3529 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33));
3530 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32));
3531
3532 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0));
3533 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59));
3534 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33));
3535 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32));
3536 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59));
3537 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33));
3538 testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57));
3539
3540 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1));
3541 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0));
3542 testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59));
3543
3544 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1));
3545 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0));
3546 testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59));
3547
3548 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1));
3549 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0));
3550 testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59));
3551
3552 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0));
3553 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59));
3554 testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58));
3555
3556 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0));
3557 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59));
3558 testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58));
3559
3560 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1));
3561 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0));
3562 testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59));
3563
3564 // Test Both
3565 testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59));
3566 testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0));
3567
3568 testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59));
3569 testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0));
3570
3571 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33));
3572 testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33));
3573
3574 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50));
3575 testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33));
3576
3577 const cdt = DateTime(1999, 7, 6, 12, 30, 33);
3578 immutable idt = DateTime(1999, 7, 6, 12, 30, 33);
3579 static assert(!__traits(compiles, cdt._addSeconds(4)));
3580 static assert(!__traits(compiles, idt._addSeconds(4)));
3581 }
3582
3583
3584 Date _date;
3585 TimeOfDay _tod;
3586 }
3587
3588
3589 /++
3590 Represents a date in the
3591 $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic
3592 Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years
3593 are A.D. Non-positive years are B.C.
3594
3595 Year, month, and day are kept separately internally so that $(D Date) is
3596 optimized for calendar-based operations.
3597
3598 $(D Date) uses the Proleptic Gregorian Calendar, so it assumes the Gregorian
3599 leap year calculations for its entire length. As per
3600 $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as
3601 year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C.
3602 as a positive integer with 1 B.C. being the year prior to 1 A.D.
3603
3604 Year 0 is a leap year.
3605 +/
3606 struct Date
3607 {
3608 public:
3609
3610 /++
3611 Throws:
3612 $(REF DateTimeException,std,datetime,date) if the resulting
3613 $(LREF Date) would not be valid.
3614
3615 Params:
3616 year = Year of the Gregorian Calendar. Positive values are A.D.
3617 Non-positive values are B.C. with year 0 being the year
3618 prior to 1 A.D.
3619 month = Month of the year (January is 1).
3620 day = Day of the month.
3621 +/
this(int year,int month,int day)3622 this(int year, int month, int day) @safe pure
3623 {
3624 enforceValid!"months"(cast(Month) month);
3625 enforceValid!"days"(year, cast(Month) month, day);
3626
3627 _year = cast(short) year;
3628 _month = cast(Month) month;
3629 _day = cast(ubyte) day;
3630 }
3631
3632 @safe unittest
3633 {
3634 import std.exception : assertNotThrown;
3635 assert(Date(1, 1, 1) == Date.init);
3636
testDate(in Date date,int year,int month,int day)3637 static void testDate(in Date date, int year, int month, int day)
3638 {
3639 assert(date._year == year);
3640 assert(date._month == month);
3641 assert(date._day == day);
3642 }
3643
3644 testDate(Date(1999, 1 , 1), 1999, Month.jan, 1);
3645 testDate(Date(1999, 7 , 1), 1999, Month.jul, 1);
3646 testDate(Date(1999, 7 , 6), 1999, Month.jul, 6);
3647
3648 // Test A.D.
3649 assertThrown!DateTimeException(Date(1, 0, 1));
3650 assertThrown!DateTimeException(Date(1, 1, 0));
3651 assertThrown!DateTimeException(Date(1999, 13, 1));
3652 assertThrown!DateTimeException(Date(1999, 1, 32));
3653 assertThrown!DateTimeException(Date(1999, 2, 29));
3654 assertThrown!DateTimeException(Date(2000, 2, 30));
3655 assertThrown!DateTimeException(Date(1999, 3, 32));
3656 assertThrown!DateTimeException(Date(1999, 4, 31));
3657 assertThrown!DateTimeException(Date(1999, 5, 32));
3658 assertThrown!DateTimeException(Date(1999, 6, 31));
3659 assertThrown!DateTimeException(Date(1999, 7, 32));
3660 assertThrown!DateTimeException(Date(1999, 8, 32));
3661 assertThrown!DateTimeException(Date(1999, 9, 31));
3662 assertThrown!DateTimeException(Date(1999, 10, 32));
3663 assertThrown!DateTimeException(Date(1999, 11, 31));
3664 assertThrown!DateTimeException(Date(1999, 12, 32));
3665
3666 assertNotThrown!DateTimeException(Date(1999, 1, 31));
3667 assertNotThrown!DateTimeException(Date(1999, 2, 28));
3668 assertNotThrown!DateTimeException(Date(2000, 2, 29));
3669 assertNotThrown!DateTimeException(Date(1999, 3, 31));
3670 assertNotThrown!DateTimeException(Date(1999, 4, 30));
3671 assertNotThrown!DateTimeException(Date(1999, 5, 31));
3672 assertNotThrown!DateTimeException(Date(1999, 6, 30));
3673 assertNotThrown!DateTimeException(Date(1999, 7, 31));
3674 assertNotThrown!DateTimeException(Date(1999, 8, 31));
3675 assertNotThrown!DateTimeException(Date(1999, 9, 30));
3676 assertNotThrown!DateTimeException(Date(1999, 10, 31));
3677 assertNotThrown!DateTimeException(Date(1999, 11, 30));
3678 assertNotThrown!DateTimeException(Date(1999, 12, 31));
3679
3680 // Test B.C.
3681 assertNotThrown!DateTimeException(Date(0, 1, 1));
3682 assertNotThrown!DateTimeException(Date(-1, 1, 1));
3683 assertNotThrown!DateTimeException(Date(-1, 12, 31));
3684 assertNotThrown!DateTimeException(Date(-1, 2, 28));
3685 assertNotThrown!DateTimeException(Date(-4, 2, 29));
3686
3687 assertThrown!DateTimeException(Date(-1, 2, 29));
3688 assertThrown!DateTimeException(Date(-2, 2, 29));
3689 assertThrown!DateTimeException(Date(-3, 2, 29));
3690 }
3691
3692
3693 /++
3694 Params:
3695 day = The Xth day of the Gregorian Calendar that the constructed
3696 $(LREF Date) will be for.
3697 +/
this(int day)3698 this(int day) @safe pure nothrow @nogc
3699 {
3700 if (day > 0)
3701 {
3702 int years = (day / daysIn400Years) * 400 + 1;
3703 day %= daysIn400Years;
3704
3705 {
3706 immutable tempYears = day / daysIn100Years;
3707
3708 if (tempYears == 4)
3709 {
3710 years += 300;
3711 day -= daysIn100Years * 3;
3712 }
3713 else
3714 {
3715 years += tempYears * 100;
3716 day %= daysIn100Years;
3717 }
3718 }
3719
3720 years += (day / daysIn4Years) * 4;
3721 day %= daysIn4Years;
3722
3723 {
3724 immutable tempYears = day / daysInYear;
3725
3726 if (tempYears == 4)
3727 {
3728 years += 3;
3729 day -= daysInYear * 3;
3730 }
3731 else
3732 {
3733 years += tempYears;
3734 day %= daysInYear;
3735 }
3736 }
3737
3738 if (day == 0)
3739 {
3740 _year = cast(short)(years - 1);
3741 _month = Month.dec;
3742 _day = 31;
3743 }
3744 else
3745 {
3746 _year = cast(short) years;
3747
3748 setDayOfYear(day);
3749 }
3750 }
3751 else if (day <= 0 && -day < daysInLeapYear)
3752 {
3753 _year = 0;
3754
3755 setDayOfYear(daysInLeapYear + day);
3756 }
3757 else
3758 {
3759 day += daysInLeapYear - 1;
3760 int years = (day / daysIn400Years) * 400 - 1;
3761 day %= daysIn400Years;
3762
3763 {
3764 immutable tempYears = day / daysIn100Years;
3765
3766 if (tempYears == -4)
3767 {
3768 years -= 300;
3769 day += daysIn100Years * 3;
3770 }
3771 else
3772 {
3773 years += tempYears * 100;
3774 day %= daysIn100Years;
3775 }
3776 }
3777
3778 years += (day / daysIn4Years) * 4;
3779 day %= daysIn4Years;
3780
3781 {
3782 immutable tempYears = day / daysInYear;
3783
3784 if (tempYears == -4)
3785 {
3786 years -= 3;
3787 day += daysInYear * 3;
3788 }
3789 else
3790 {
3791 years += tempYears;
3792 day %= daysInYear;
3793 }
3794 }
3795
3796 if (day == 0)
3797 {
3798 _year = cast(short)(years + 1);
3799 _month = Month.jan;
3800 _day = 1;
3801 }
3802 else
3803 {
3804 _year = cast(short) years;
3805 immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1;
3806
3807 setDayOfYear(newDoY);
3808 }
3809 }
3810 }
3811
3812 @safe unittest
3813 {
3814 import std.range : chain;
3815
3816 // Test A.D.
3817 foreach (gd; chain(testGregDaysBC, testGregDaysAD))
3818 assert(Date(gd.day) == gd.date);
3819 }
3820
3821
3822 /++
3823 Compares this $(LREF Date) with the given $(LREF Date).
3824
3825 Returns:
3826 $(BOOKTABLE,
3827 $(TR $(TD this < rhs) $(TD < 0))
3828 $(TR $(TD this == rhs) $(TD 0))
3829 $(TR $(TD this > rhs) $(TD > 0))
3830 )
3831 +/
opCmp(in Date rhs)3832 int opCmp(in Date rhs) const @safe pure nothrow @nogc
3833 {
3834 if (_year < rhs._year)
3835 return -1;
3836 if (_year > rhs._year)
3837 return 1;
3838
3839 if (_month < rhs._month)
3840 return -1;
3841 if (_month > rhs._month)
3842 return 1;
3843
3844 if (_day < rhs._day)
3845 return -1;
3846 if (_day > rhs._day)
3847 return 1;
3848
3849 return 0;
3850 }
3851
3852 @safe unittest
3853 {
3854 // Test A.D.
3855 assert(Date(1, 1, 1).opCmp(Date.init) == 0);
3856
3857 assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0);
3858 assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0);
3859 assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0);
3860
3861 assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0);
3862 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0);
3863
3864 assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0);
3865
3866 assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0);
3867 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0);
3868 assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0);
3869 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0);
3870 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0);
3871 assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0);
3872
3873 assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0);
3874 assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
3875 assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0);
3876 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0);
3877 assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0);
3878 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0);
3879
3880 // Test B.C.
3881 assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0);
3882 assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0);
3883 assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0);
3884 assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0);
3885
3886 assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0);
3887 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0);
3888
3889 assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0);
3890
3891 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0);
3892 assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0);
3893 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0);
3894 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0);
3895 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
3896 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0);
3897
3898 assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0);
3899 assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0);
3900 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0);
3901 assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0);
3902 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0);
3903 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0);
3904
3905 // Test Both
3906 assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0);
3907 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0);
3908
3909 assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0);
3910 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0);
3911
3912 assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0);
3913 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0);
3914
3915 assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0);
3916 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0);
3917
3918 assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0);
3919 assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0);
3920
3921 auto date = Date(1999, 7, 6);
3922 const cdate = Date(1999, 7, 6);
3923 immutable idate = Date(1999, 7, 6);
3924 assert(date.opCmp(date) == 0);
3925 assert(date.opCmp(cdate) == 0);
3926 assert(date.opCmp(idate) == 0);
3927 assert(cdate.opCmp(date) == 0);
3928 assert(cdate.opCmp(cdate) == 0);
3929 assert(cdate.opCmp(idate) == 0);
3930 assert(idate.opCmp(date) == 0);
3931 assert(idate.opCmp(cdate) == 0);
3932 assert(idate.opCmp(idate) == 0);
3933 }
3934
3935
3936 /++
3937 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
3938 are B.C.
3939 +/
year()3940 @property short year() const @safe pure nothrow @nogc
3941 {
3942 return _year;
3943 }
3944
3945 ///
3946 @safe unittest
3947 {
3948 assert(Date(1999, 7, 6).year == 1999);
3949 assert(Date(2010, 10, 4).year == 2010);
3950 assert(Date(-7, 4, 5).year == -7);
3951 }
3952
3953 @safe unittest
3954 {
3955 assert(Date.init.year == 1);
3956 assert(Date(1999, 7, 6).year == 1999);
3957 assert(Date(-1999, 7, 6).year == -1999);
3958
3959 const cdate = Date(1999, 7, 6);
3960 immutable idate = Date(1999, 7, 6);
3961 assert(cdate.year == 1999);
3962 assert(idate.year == 1999);
3963 }
3964
3965 /++
3966 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive
3967 are B.C.
3968
3969 Params:
3970 year = The year to set this Date's year to.
3971
3972 Throws:
3973 $(REF DateTimeException,std,datetime,date) if the new year is not
3974 a leap year and the resulting date would be on February 29th.
3975 +/
year(int year)3976 @property void year(int year) @safe pure
3977 {
3978 enforceValid!"days"(year, _month, _day);
3979 _year = cast(short) year;
3980 }
3981
3982 ///
3983 @safe unittest
3984 {
3985 assert(Date(1999, 7, 6).year == 1999);
3986 assert(Date(2010, 10, 4).year == 2010);
3987 assert(Date(-7, 4, 5).year == -7);
3988 }
3989
3990 @safe unittest
3991 {
3992 static void testDateInvalid(Date date, int year)
3993 {
3994 date.year = year;
3995 }
3996
3997 static void testDate(Date date, int year, in Date expected)
3998 {
3999 date.year = year;
4000 assert(date == expected);
4001 }
4002
4003 assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1));
4004
4005 testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1));
4006 testDate(Date(1, 1, 1), 0, Date(0, 1, 1));
4007 testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1));
4008
4009 const cdate = Date(1999, 7, 6);
4010 immutable idate = Date(1999, 7, 6);
4011 static assert(!__traits(compiles, cdate.year = 1999));
4012 static assert(!__traits(compiles, idate.year = 1999));
4013 }
4014
4015
4016 /++
4017 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
4018
4019 Throws:
4020 $(REF DateTimeException,std,datetime,date) if $(D isAD) is true.
4021 +/
4022 @property ushort yearBC() const @safe pure
4023 {
4024 import std.format : format;
4025
4026 if (isAD)
4027 throw new DateTimeException(format("Year %s is A.D.", _year));
4028 return cast(ushort)((_year * -1) + 1);
4029 }
4030
4031 ///
4032 @safe unittest
4033 {
4034 assert(Date(0, 1, 1).yearBC == 1);
4035 assert(Date(-1, 1, 1).yearBC == 2);
4036 assert(Date(-100, 1, 1).yearBC == 101);
4037 }
4038
4039 @safe unittest
4040 {
4041 assertThrown!DateTimeException((in Date date){date.yearBC;}(Date(1, 1, 1)));
4042
4043 auto date = Date(0, 7, 6);
4044 const cdate = Date(0, 7, 6);
4045 immutable idate = Date(0, 7, 6);
4046 assert(date.yearBC == 1);
4047 assert(cdate.yearBC == 1);
4048 assert(idate.yearBC == 1);
4049 }
4050
4051
4052 /++
4053 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C.
4054
4055 Params:
4056 year = The year B.C. to set this $(LREF Date)'s year to.
4057
4058 Throws:
4059 $(REF DateTimeException,std,datetime,date) if a non-positive value
4060 is given.
4061 +/
4062 @property void yearBC(int year) @safe pure
4063 {
4064 if (year <= 0)
4065 throw new DateTimeException("The given year is not a year B.C.");
4066 _year = cast(short)((year - 1) * -1);
4067 }
4068
4069 ///
4070 @safe unittest
4071 {
4072 auto date = Date(2010, 1, 1);
4073 date.yearBC = 1;
4074 assert(date == Date(0, 1, 1));
4075
4076 date.yearBC = 10;
4077 assert(date == Date(-9, 1, 1));
4078 }
4079
4080 @safe unittest
4081 {
4082 assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1)));
4083
4084 auto date = Date(0, 7, 6);
4085 const cdate = Date(0, 7, 6);
4086 immutable idate = Date(0, 7, 6);
4087 date.yearBC = 7;
4088 assert(date.yearBC == 7);
4089 static assert(!__traits(compiles, cdate.yearBC = 7));
4090 static assert(!__traits(compiles, idate.yearBC = 7));
4091 }
4092
4093
4094 /++
4095 Month of a Gregorian Year.
4096 +/
month()4097 @property Month month() const @safe pure nothrow @nogc
4098 {
4099 return _month;
4100 }
4101
4102 ///
4103 @safe unittest
4104 {
4105 assert(Date(1999, 7, 6).month == 7);
4106 assert(Date(2010, 10, 4).month == 10);
4107 assert(Date(-7, 4, 5).month == 4);
4108 }
4109
4110 @safe unittest
4111 {
4112 assert(Date.init.month == 1);
4113 assert(Date(1999, 7, 6).month == 7);
4114 assert(Date(-1999, 7, 6).month == 7);
4115
4116 const cdate = Date(1999, 7, 6);
4117 immutable idate = Date(1999, 7, 6);
4118 assert(cdate.month == 7);
4119 assert(idate.month == 7);
4120 }
4121
4122 /++
4123 Month of a Gregorian Year.
4124
4125 Params:
4126 month = The month to set this $(LREF Date)'s month to.
4127
4128 Throws:
4129 $(REF DateTimeException,std,datetime,date) if the given month is
4130 not a valid month or if the current day would not be valid in the
4131 given month.
4132 +/
month(Month month)4133 @property void month(Month month) @safe pure
4134 {
4135 enforceValid!"months"(month);
4136 enforceValid!"days"(_year, month, _day);
4137 _month = cast(Month) month;
4138 }
4139
4140 @safe unittest
4141 {
4142 static void testDate(Date date, Month month, in Date expected = Date.init)
4143 {
4144 date.month = month;
4145 assert(expected != Date.init);
4146 assert(date == expected);
4147 }
4148
4149 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0));
4150 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13));
4151 assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2));
4152 assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2));
4153
4154 testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1));
4155 testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1));
4156
4157 const cdate = Date(1999, 7, 6);
4158 immutable idate = Date(1999, 7, 6);
4159 static assert(!__traits(compiles, cdate.month = 7));
4160 static assert(!__traits(compiles, idate.month = 7));
4161 }
4162
4163
4164 /++
4165 Day of a Gregorian Month.
4166 +/
4167 @property ubyte day() const @safe pure nothrow @nogc
4168 {
4169 return _day;
4170 }
4171
4172 ///
4173 @safe unittest
4174 {
4175 assert(Date(1999, 7, 6).day == 6);
4176 assert(Date(2010, 10, 4).day == 4);
4177 assert(Date(-7, 4, 5).day == 5);
4178 }
4179
4180 @safe unittest
4181 {
4182 import std.format : format;
4183 import std.range : chain;
4184
4185 static void test(Date date, int expected)
4186 {
4187 assert(date.day == expected, format("Value given: %s", date));
4188 }
4189
4190 foreach (year; chain(testYearsBC, testYearsAD))
4191 {
4192 foreach (md; testMonthDays)
4193 test(Date(year, md.month, md.day), md.day);
4194 }
4195
4196 const cdate = Date(1999, 7, 6);
4197 immutable idate = Date(1999, 7, 6);
4198 assert(cdate.day == 6);
4199 assert(idate.day == 6);
4200 }
4201
4202 /++
4203 Day of a Gregorian Month.
4204
4205 Params:
4206 day = The day of the month to set this $(LREF Date)'s day to.
4207
4208 Throws:
4209 $(REF DateTimeException,std,datetime,date) if the given day is not
4210 a valid day of the current month.
4211 +/
4212 @property void day(int day) @safe pure
4213 {
4214 enforceValid!"days"(_year, _month, day);
4215 _day = cast(ubyte) day;
4216 }
4217
4218 @safe unittest
4219 {
4220 import std.exception : assertNotThrown;
4221
testDate(Date date,int day)4222 static void testDate(Date date, int day)
4223 {
4224 date.day = day;
4225 }
4226
4227 // Test A.D.
4228 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0));
4229 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32));
4230 assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29));
4231 assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30));
4232 assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32));
4233 assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31));
4234 assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32));
4235 assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31));
4236 assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32));
4237 assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32));
4238 assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31));
4239 assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32));
4240 assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31));
4241 assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32));
4242
4243 assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31));
4244 assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28));
4245 assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29));
4246 assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31));
4247 assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30));
4248 assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31));
4249 assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30));
4250 assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31));
4251 assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31));
4252 assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30));
4253 assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31));
4254 assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30));
4255 assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31));
4256
4257 {
4258 auto date = Date(1, 1, 1);
4259 date.day = 6;
4260 assert(date == Date(1, 1, 6));
4261 }
4262
4263 // Test B.C.
4264 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0));
4265 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32));
4266 assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29));
4267 assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30));
4268 assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32));
4269 assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31));
4270 assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32));
4271 assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31));
4272 assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32));
4273 assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32));
4274 assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31));
4275 assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32));
4276 assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31));
4277 assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32));
4278
4279 assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31));
4280 assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28));
4281 assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29));
4282 assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31));
4283 assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30));
4284 assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31));
4285 assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30));
4286 assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31));
4287 assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31));
4288 assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30));
4289 assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31));
4290 assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30));
4291 assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31));
4292
4293 {
4294 auto date = Date(-1, 1, 1);
4295 date.day = 6;
4296 assert(date == Date(-1, 1, 6));
4297 }
4298
4299 const cdate = Date(1999, 7, 6);
4300 immutable idate = Date(1999, 7, 6);
4301 static assert(!__traits(compiles, cdate.day = 6));
4302 static assert(!__traits(compiles, idate.day = 6));
4303 }
4304
4305
4306 /++
4307 Adds the given number of years or months to this $(LREF Date). A
4308 negative number will subtract.
4309
4310 Note that if day overflow is allowed, and the date with the adjusted
4311 year/month overflows the number of days in the new month, then the month
4312 will be incremented by one, and the day set to the number of days
4313 overflowed. (e.g. if the day were 31 and the new month were June, then
4314 the month would be incremented to July, and the new day would be 1). If
4315 day overflow is not allowed, then the day will be set to the last valid
4316 day in the month (e.g. June 31st would become June 30th).
4317
4318 Params:
4319 units = The type of units to add ("years" or "months").
4320 value = The number of months or years to add to this
4321 $(LREF Date).
4322 allowOverflow = Whether the day should be allowed to overflow,
4323 causing the month to increment.
4324 +/
4325 @safe pure nothrow @nogc
4326 ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
4327 if (units == "years")
4328 {
4329 _year += value;
4330
4331 if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year))
4332 {
4333 if (allowOverflow == AllowDayOverflow.yes)
4334 {
4335 _month = Month.mar;
4336 _day = 1;
4337 }
4338 else
4339 _day = 28;
4340 }
4341
4342 return this;
4343 }
4344
4345 ///
4346 @safe unittest
4347 {
4348 auto d1 = Date(2010, 1, 1);
4349 d1.add!"months"(11);
4350 assert(d1 == Date(2010, 12, 1));
4351
4352 auto d2 = Date(2010, 1, 1);
4353 d2.add!"months"(-11);
4354 assert(d2 == Date(2009, 2, 1));
4355
4356 auto d3 = Date(2000, 2, 29);
4357 d3.add!"years"(1);
4358 assert(d3 == Date(2001, 3, 1));
4359
4360 auto d4 = Date(2000, 2, 29);
4361 d4.add!"years"(1, AllowDayOverflow.no);
4362 assert(d4 == Date(2001, 2, 28));
4363 }
4364
4365 // Test add!"years"() with AllowDayOverflow.yes
4366 @safe unittest
4367 {
4368 // Test A.D.
4369 {
4370 auto date = Date(1999, 7, 6);
4371 date.add!"years"(7);
4372 assert(date == Date(2006, 7, 6));
4373 date.add!"years"(-9);
4374 assert(date == Date(1997, 7, 6));
4375 }
4376
4377 {
4378 auto date = Date(1999, 2, 28);
4379 date.add!"years"(1);
4380 assert(date == Date(2000, 2, 28));
4381 }
4382
4383 {
4384 auto date = Date(2000, 2, 29);
4385 date.add!"years"(-1);
4386 assert(date == Date(1999, 3, 1));
4387 }
4388
4389 // Test B.C.
4390 {
4391 auto date = Date(-1999, 7, 6);
4392 date.add!"years"(-7);
4393 assert(date == Date(-2006, 7, 6));
4394 date.add!"years"(9);
4395 assert(date == Date(-1997, 7, 6));
4396 }
4397
4398 {
4399 auto date = Date(-1999, 2, 28);
4400 date.add!"years"(-1);
4401 assert(date == Date(-2000, 2, 28));
4402 }
4403
4404 {
4405 auto date = Date(-2000, 2, 29);
4406 date.add!"years"(1);
4407 assert(date == Date(-1999, 3, 1));
4408 }
4409
4410 // Test Both
4411 {
4412 auto date = Date(4, 7, 6);
4413 date.add!"years"(-5);
4414 assert(date == Date(-1, 7, 6));
4415 date.add!"years"(5);
4416 assert(date == Date(4, 7, 6));
4417 }
4418
4419 {
4420 auto date = Date(-4, 7, 6);
4421 date.add!"years"(5);
4422 assert(date == Date(1, 7, 6));
4423 date.add!"years"(-5);
4424 assert(date == Date(-4, 7, 6));
4425 }
4426
4427 {
4428 auto date = Date(4, 7, 6);
4429 date.add!"years"(-8);
4430 assert(date == Date(-4, 7, 6));
4431 date.add!"years"(8);
4432 assert(date == Date(4, 7, 6));
4433 }
4434
4435 {
4436 auto date = Date(-4, 7, 6);
4437 date.add!"years"(8);
4438 assert(date == Date(4, 7, 6));
4439 date.add!"years"(-8);
4440 assert(date == Date(-4, 7, 6));
4441 }
4442
4443 {
4444 auto date = Date(-4, 2, 29);
4445 date.add!"years"(5);
4446 assert(date == Date(1, 3, 1));
4447 }
4448
4449 {
4450 auto date = Date(4, 2, 29);
4451 date.add!"years"(-5);
4452 assert(date == Date(-1, 3, 1));
4453 }
4454
4455 {
4456 auto date = Date(4, 2, 29);
4457 date.add!"years"(-5).add!"years"(7);
4458 assert(date == Date(6, 3, 1));
4459 }
4460
4461 const cdate = Date(1999, 7, 6);
4462 immutable idate = Date(1999, 7, 6);
4463 static assert(!__traits(compiles, cdate.add!"years"(7)));
4464 static assert(!__traits(compiles, idate.add!"years"(7)));
4465 }
4466
4467 // Test add!"years"() with AllowDayOverflow.no
4468 @safe unittest
4469 {
4470 // Test A.D.
4471 {
4472 auto date = Date(1999, 7, 6);
4473 date.add!"years"(7, AllowDayOverflow.no);
4474 assert(date == Date(2006, 7, 6));
4475 date.add!"years"(-9, AllowDayOverflow.no);
4476 assert(date == Date(1997, 7, 6));
4477 }
4478
4479 {
4480 auto date = Date(1999, 2, 28);
4481 date.add!"years"(1, AllowDayOverflow.no);
4482 assert(date == Date(2000, 2, 28));
4483 }
4484
4485 {
4486 auto date = Date(2000, 2, 29);
4487 date.add!"years"(-1, AllowDayOverflow.no);
4488 assert(date == Date(1999, 2, 28));
4489 }
4490
4491 // Test B.C.
4492 {
4493 auto date = Date(-1999, 7, 6);
4494 date.add!"years"(-7, AllowDayOverflow.no);
4495 assert(date == Date(-2006, 7, 6));
4496 date.add!"years"(9, AllowDayOverflow.no);
4497 assert(date == Date(-1997, 7, 6));
4498 }
4499
4500 {
4501 auto date = Date(-1999, 2, 28);
4502 date.add!"years"(-1, AllowDayOverflow.no);
4503 assert(date == Date(-2000, 2, 28));
4504 }
4505
4506 {
4507 auto date = Date(-2000, 2, 29);
4508 date.add!"years"(1, AllowDayOverflow.no);
4509 assert(date == Date(-1999, 2, 28));
4510 }
4511
4512 // Test Both
4513 {
4514 auto date = Date(4, 7, 6);
4515 date.add!"years"(-5, AllowDayOverflow.no);
4516 assert(date == Date(-1, 7, 6));
4517 date.add!"years"(5, AllowDayOverflow.no);
4518 assert(date == Date(4, 7, 6));
4519 }
4520
4521 {
4522 auto date = Date(-4, 7, 6);
4523 date.add!"years"(5, AllowDayOverflow.no);
4524 assert(date == Date(1, 7, 6));
4525 date.add!"years"(-5, AllowDayOverflow.no);
4526 assert(date == Date(-4, 7, 6));
4527 }
4528
4529 {
4530 auto date = Date(4, 7, 6);
4531 date.add!"years"(-8, AllowDayOverflow.no);
4532 assert(date == Date(-4, 7, 6));
4533 date.add!"years"(8, AllowDayOverflow.no);
4534 assert(date == Date(4, 7, 6));
4535 }
4536
4537 {
4538 auto date = Date(-4, 7, 6);
4539 date.add!"years"(8, AllowDayOverflow.no);
4540 assert(date == Date(4, 7, 6));
4541 date.add!"years"(-8, AllowDayOverflow.no);
4542 assert(date == Date(-4, 7, 6));
4543 }
4544
4545 {
4546 auto date = Date(-4, 2, 29);
4547 date.add!"years"(5, AllowDayOverflow.no);
4548 assert(date == Date(1, 2, 28));
4549 }
4550
4551 {
4552 auto date = Date(4, 2, 29);
4553 date.add!"years"(-5, AllowDayOverflow.no);
4554 assert(date == Date(-1, 2, 28));
4555 }
4556
4557 {
4558 auto date = Date(4, 2, 29);
4559 date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no);
4560 assert(date == Date(6, 2, 28));
4561 }
4562 }
4563
4564
4565 // Shares documentation with "years" version.
4566 @safe pure nothrow @nogc
4567 ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
4568 if (units == "months")
4569 {
4570 auto years = months / 12;
4571 months %= 12;
4572 auto newMonth = _month + months;
4573
4574 if (months < 0)
4575 {
4576 if (newMonth < 1)
4577 {
4578 newMonth += 12;
4579 --years;
4580 }
4581 }
4582 else if (newMonth > 12)
4583 {
4584 newMonth -= 12;
4585 ++years;
4586 }
4587
4588 _year += years;
4589 _month = cast(Month) newMonth;
4590
4591 immutable currMaxDay = maxDay(_year, _month);
4592 immutable overflow = _day - currMaxDay;
4593
4594 if (overflow > 0)
4595 {
4596 if (allowOverflow == AllowDayOverflow.yes)
4597 {
4598 ++_month;
4599 _day = cast(ubyte) overflow;
4600 }
4601 else
4602 _day = cast(ubyte) currMaxDay;
4603 }
4604
4605 return this;
4606 }
4607
4608 // Test add!"months"() with AllowDayOverflow.yes
4609 @safe unittest
4610 {
4611 // Test A.D.
4612 {
4613 auto date = Date(1999, 7, 6);
4614 date.add!"months"(3);
4615 assert(date == Date(1999, 10, 6));
4616 date.add!"months"(-4);
4617 assert(date == Date(1999, 6, 6));
4618 }
4619
4620 {
4621 auto date = Date(1999, 7, 6);
4622 date.add!"months"(6);
4623 assert(date == Date(2000, 1, 6));
4624 date.add!"months"(-6);
4625 assert(date == Date(1999, 7, 6));
4626 }
4627
4628 {
4629 auto date = Date(1999, 7, 6);
4630 date.add!"months"(27);
4631 assert(date == Date(2001, 10, 6));
4632 date.add!"months"(-28);
4633 assert(date == Date(1999, 6, 6));
4634 }
4635
4636 {
4637 auto date = Date(1999, 5, 31);
4638 date.add!"months"(1);
4639 assert(date == Date(1999, 7, 1));
4640 }
4641
4642 {
4643 auto date = Date(1999, 5, 31);
4644 date.add!"months"(-1);
4645 assert(date == Date(1999, 5, 1));
4646 }
4647
4648 {
4649 auto date = Date(1999, 2, 28);
4650 date.add!"months"(12);
4651 assert(date == Date(2000, 2, 28));
4652 }
4653
4654 {
4655 auto date = Date(2000, 2, 29);
4656 date.add!"months"(12);
4657 assert(date == Date(2001, 3, 1));
4658 }
4659
4660 {
4661 auto date = Date(1999, 7, 31);
4662 date.add!"months"(1);
4663 assert(date == Date(1999, 8, 31));
4664 date.add!"months"(1);
4665 assert(date == Date(1999, 10, 1));
4666 }
4667
4668 {
4669 auto date = Date(1998, 8, 31);
4670 date.add!"months"(13);
4671 assert(date == Date(1999, 10, 1));
4672 date.add!"months"(-13);
4673 assert(date == Date(1998, 9, 1));
4674 }
4675
4676 {
4677 auto date = Date(1997, 12, 31);
4678 date.add!"months"(13);
4679 assert(date == Date(1999, 1, 31));
4680 date.add!"months"(-13);
4681 assert(date == Date(1997, 12, 31));
4682 }
4683
4684 {
4685 auto date = Date(1997, 12, 31);
4686 date.add!"months"(14);
4687 assert(date == Date(1999, 3, 3));
4688 date.add!"months"(-14);
4689 assert(date == Date(1998, 1, 3));
4690 }
4691
4692 {
4693 auto date = Date(1998, 12, 31);
4694 date.add!"months"(14);
4695 assert(date == Date(2000, 3, 2));
4696 date.add!"months"(-14);
4697 assert(date == Date(1999, 1, 2));
4698 }
4699
4700 {
4701 auto date = Date(1999, 12, 31);
4702 date.add!"months"(14);
4703 assert(date == Date(2001, 3, 3));
4704 date.add!"months"(-14);
4705 assert(date == Date(2000, 1, 3));
4706 }
4707
4708 // Test B.C.
4709 {
4710 auto date = Date(-1999, 7, 6);
4711 date.add!"months"(3);
4712 assert(date == Date(-1999, 10, 6));
4713 date.add!"months"(-4);
4714 assert(date == Date(-1999, 6, 6));
4715 }
4716
4717 {
4718 auto date = Date(-1999, 7, 6);
4719 date.add!"months"(6);
4720 assert(date == Date(-1998, 1, 6));
4721 date.add!"months"(-6);
4722 assert(date == Date(-1999, 7, 6));
4723 }
4724
4725 {
4726 auto date = Date(-1999, 7, 6);
4727 date.add!"months"(-27);
4728 assert(date == Date(-2001, 4, 6));
4729 date.add!"months"(28);
4730 assert(date == Date(-1999, 8, 6));
4731 }
4732
4733 {
4734 auto date = Date(-1999, 5, 31);
4735 date.add!"months"(1);
4736 assert(date == Date(-1999, 7, 1));
4737 }
4738
4739 {
4740 auto date = Date(-1999, 5, 31);
4741 date.add!"months"(-1);
4742 assert(date == Date(-1999, 5, 1));
4743 }
4744
4745 {
4746 auto date = Date(-1999, 2, 28);
4747 date.add!"months"(-12);
4748 assert(date == Date(-2000, 2, 28));
4749 }
4750
4751 {
4752 auto date = Date(-2000, 2, 29);
4753 date.add!"months"(-12);
4754 assert(date == Date(-2001, 3, 1));
4755 }
4756
4757 {
4758 auto date = Date(-1999, 7, 31);
4759 date.add!"months"(1);
4760 assert(date == Date(-1999, 8, 31));
4761 date.add!"months"(1);
4762 assert(date == Date(-1999, 10, 1));
4763 }
4764
4765 {
4766 auto date = Date(-1998, 8, 31);
4767 date.add!"months"(13);
4768 assert(date == Date(-1997, 10, 1));
4769 date.add!"months"(-13);
4770 assert(date == Date(-1998, 9, 1));
4771 }
4772
4773 {
4774 auto date = Date(-1997, 12, 31);
4775 date.add!"months"(13);
4776 assert(date == Date(-1995, 1, 31));
4777 date.add!"months"(-13);
4778 assert(date == Date(-1997, 12, 31));
4779 }
4780
4781 {
4782 auto date = Date(-1997, 12, 31);
4783 date.add!"months"(14);
4784 assert(date == Date(-1995, 3, 3));
4785 date.add!"months"(-14);
4786 assert(date == Date(-1996, 1, 3));
4787 }
4788
4789 {
4790 auto date = Date(-2002, 12, 31);
4791 date.add!"months"(14);
4792 assert(date == Date(-2000, 3, 2));
4793 date.add!"months"(-14);
4794 assert(date == Date(-2001, 1, 2));
4795 }
4796
4797 {
4798 auto date = Date(-2001, 12, 31);
4799 date.add!"months"(14);
4800 assert(date == Date(-1999, 3, 3));
4801 date.add!"months"(-14);
4802 assert(date == Date(-2000, 1, 3));
4803 }
4804
4805 // Test Both
4806 {
4807 auto date = Date(1, 1, 1);
4808 date.add!"months"(-1);
4809 assert(date == Date(0, 12, 1));
4810 date.add!"months"(1);
4811 assert(date == Date(1, 1, 1));
4812 }
4813
4814 {
4815 auto date = Date(4, 1, 1);
4816 date.add!"months"(-48);
4817 assert(date == Date(0, 1, 1));
4818 date.add!"months"(48);
4819 assert(date == Date(4, 1, 1));
4820 }
4821
4822 {
4823 auto date = Date(4, 3, 31);
4824 date.add!"months"(-49);
4825 assert(date == Date(0, 3, 2));
4826 date.add!"months"(49);
4827 assert(date == Date(4, 4, 2));
4828 }
4829
4830 {
4831 auto date = Date(4, 3, 31);
4832 date.add!"months"(-85);
4833 assert(date == Date(-3, 3, 3));
4834 date.add!"months"(85);
4835 assert(date == Date(4, 4, 3));
4836 }
4837
4838 {
4839 auto date = Date(-3, 3, 31);
4840 date.add!"months"(85).add!"months"(-83);
4841 assert(date == Date(-3, 6, 1));
4842 }
4843
4844 const cdate = Date(1999, 7, 6);
4845 immutable idate = Date(1999, 7, 6);
4846 static assert(!__traits(compiles, cdate.add!"months"(3)));
4847 static assert(!__traits(compiles, idate.add!"months"(3)));
4848 }
4849
4850 // Test add!"months"() with AllowDayOverflow.no
4851 @safe unittest
4852 {
4853 // Test A.D.
4854 {
4855 auto date = Date(1999, 7, 6);
4856 date.add!"months"(3, AllowDayOverflow.no);
4857 assert(date == Date(1999, 10, 6));
4858 date.add!"months"(-4, AllowDayOverflow.no);
4859 assert(date == Date(1999, 6, 6));
4860 }
4861
4862 {
4863 auto date = Date(1999, 7, 6);
4864 date.add!"months"(6, AllowDayOverflow.no);
4865 assert(date == Date(2000, 1, 6));
4866 date.add!"months"(-6, AllowDayOverflow.no);
4867 assert(date == Date(1999, 7, 6));
4868 }
4869
4870 {
4871 auto date = Date(1999, 7, 6);
4872 date.add!"months"(27, AllowDayOverflow.no);
4873 assert(date == Date(2001, 10, 6));
4874 date.add!"months"(-28, AllowDayOverflow.no);
4875 assert(date == Date(1999, 6, 6));
4876 }
4877
4878 {
4879 auto date = Date(1999, 5, 31);
4880 date.add!"months"(1, AllowDayOverflow.no);
4881 assert(date == Date(1999, 6, 30));
4882 }
4883
4884 {
4885 auto date = Date(1999, 5, 31);
4886 date.add!"months"(-1, AllowDayOverflow.no);
4887 assert(date == Date(1999, 4, 30));
4888 }
4889
4890 {
4891 auto date = Date(1999, 2, 28);
4892 date.add!"months"(12, AllowDayOverflow.no);
4893 assert(date == Date(2000, 2, 28));
4894 }
4895
4896 {
4897 auto date = Date(2000, 2, 29);
4898 date.add!"months"(12, AllowDayOverflow.no);
4899 assert(date == Date(2001, 2, 28));
4900 }
4901
4902 {
4903 auto date = Date(1999, 7, 31);
4904 date.add!"months"(1, AllowDayOverflow.no);
4905 assert(date == Date(1999, 8, 31));
4906 date.add!"months"(1, AllowDayOverflow.no);
4907 assert(date == Date(1999, 9, 30));
4908 }
4909
4910 {
4911 auto date = Date(1998, 8, 31);
4912 date.add!"months"(13, AllowDayOverflow.no);
4913 assert(date == Date(1999, 9, 30));
4914 date.add!"months"(-13, AllowDayOverflow.no);
4915 assert(date == Date(1998, 8, 30));
4916 }
4917
4918 {
4919 auto date = Date(1997, 12, 31);
4920 date.add!"months"(13, AllowDayOverflow.no);
4921 assert(date == Date(1999, 1, 31));
4922 date.add!"months"(-13, AllowDayOverflow.no);
4923 assert(date == Date(1997, 12, 31));
4924 }
4925
4926 {
4927 auto date = Date(1997, 12, 31);
4928 date.add!"months"(14, AllowDayOverflow.no);
4929 assert(date == Date(1999, 2, 28));
4930 date.add!"months"(-14, AllowDayOverflow.no);
4931 assert(date == Date(1997, 12, 28));
4932 }
4933
4934 {
4935 auto date = Date(1998, 12, 31);
4936 date.add!"months"(14, AllowDayOverflow.no);
4937 assert(date == Date(2000, 2, 29));
4938 date.add!"months"(-14, AllowDayOverflow.no);
4939 assert(date == Date(1998, 12, 29));
4940 }
4941
4942 {
4943 auto date = Date(1999, 12, 31);
4944 date.add!"months"(14, AllowDayOverflow.no);
4945 assert(date == Date(2001, 2, 28));
4946 date.add!"months"(-14, AllowDayOverflow.no);
4947 assert(date == Date(1999, 12, 28));
4948 }
4949
4950 // Test B.C.
4951 {
4952 auto date = Date(-1999, 7, 6);
4953 date.add!"months"(3, AllowDayOverflow.no);
4954 assert(date == Date(-1999, 10, 6));
4955 date.add!"months"(-4, AllowDayOverflow.no);
4956 assert(date == Date(-1999, 6, 6));
4957 }
4958
4959 {
4960 auto date = Date(-1999, 7, 6);
4961 date.add!"months"(6, AllowDayOverflow.no);
4962 assert(date == Date(-1998, 1, 6));
4963 date.add!"months"(-6, AllowDayOverflow.no);
4964 assert(date == Date(-1999, 7, 6));
4965 }
4966
4967 {
4968 auto date = Date(-1999, 7, 6);
4969 date.add!"months"(-27, AllowDayOverflow.no);
4970 assert(date == Date(-2001, 4, 6));
4971 date.add!"months"(28, AllowDayOverflow.no);
4972 assert(date == Date(-1999, 8, 6));
4973 }
4974
4975 {
4976 auto date = Date(-1999, 5, 31);
4977 date.add!"months"(1, AllowDayOverflow.no);
4978 assert(date == Date(-1999, 6, 30));
4979 }
4980
4981 {
4982 auto date = Date(-1999, 5, 31);
4983 date.add!"months"(-1, AllowDayOverflow.no);
4984 assert(date == Date(-1999, 4, 30));
4985 }
4986
4987 {
4988 auto date = Date(-1999, 2, 28);
4989 date.add!"months"(-12, AllowDayOverflow.no);
4990 assert(date == Date(-2000, 2, 28));
4991 }
4992
4993 {
4994 auto date = Date(-2000, 2, 29);
4995 date.add!"months"(-12, AllowDayOverflow.no);
4996 assert(date == Date(-2001, 2, 28));
4997 }
4998
4999 {
5000 auto date = Date(-1999, 7, 31);
5001 date.add!"months"(1, AllowDayOverflow.no);
5002 assert(date == Date(-1999, 8, 31));
5003 date.add!"months"(1, AllowDayOverflow.no);
5004 assert(date == Date(-1999, 9, 30));
5005 }
5006
5007 {
5008 auto date = Date(-1998, 8, 31);
5009 date.add!"months"(13, AllowDayOverflow.no);
5010 assert(date == Date(-1997, 9, 30));
5011 date.add!"months"(-13, AllowDayOverflow.no);
5012 assert(date == Date(-1998, 8, 30));
5013 }
5014
5015 {
5016 auto date = Date(-1997, 12, 31);
5017 date.add!"months"(13, AllowDayOverflow.no);
5018 assert(date == Date(-1995, 1, 31));
5019 date.add!"months"(-13, AllowDayOverflow.no);
5020 assert(date == Date(-1997, 12, 31));
5021 }
5022
5023 {
5024 auto date = Date(-1997, 12, 31);
5025 date.add!"months"(14, AllowDayOverflow.no);
5026 assert(date == Date(-1995, 2, 28));
5027 date.add!"months"(-14, AllowDayOverflow.no);
5028 assert(date == Date(-1997, 12, 28));
5029 }
5030
5031 {
5032 auto date = Date(-2002, 12, 31);
5033 date.add!"months"(14, AllowDayOverflow.no);
5034 assert(date == Date(-2000, 2, 29));
5035 date.add!"months"(-14, AllowDayOverflow.no);
5036 assert(date == Date(-2002, 12, 29));
5037 }
5038
5039 {
5040 auto date = Date(-2001, 12, 31);
5041 date.add!"months"(14, AllowDayOverflow.no);
5042 assert(date == Date(-1999, 2, 28));
5043 date.add!"months"(-14, AllowDayOverflow.no);
5044 assert(date == Date(-2001, 12, 28));
5045 }
5046
5047 // Test Both
5048 {
5049 auto date = Date(1, 1, 1);
5050 date.add!"months"(-1, AllowDayOverflow.no);
5051 assert(date == Date(0, 12, 1));
5052 date.add!"months"(1, AllowDayOverflow.no);
5053 assert(date == Date(1, 1, 1));
5054 }
5055
5056 {
5057 auto date = Date(4, 1, 1);
5058 date.add!"months"(-48, AllowDayOverflow.no);
5059 assert(date == Date(0, 1, 1));
5060 date.add!"months"(48, AllowDayOverflow.no);
5061 assert(date == Date(4, 1, 1));
5062 }
5063
5064 {
5065 auto date = Date(4, 3, 31);
5066 date.add!"months"(-49, AllowDayOverflow.no);
5067 assert(date == Date(0, 2, 29));
5068 date.add!"months"(49, AllowDayOverflow.no);
5069 assert(date == Date(4, 3, 29));
5070 }
5071
5072 {
5073 auto date = Date(4, 3, 31);
5074 date.add!"months"(-85, AllowDayOverflow.no);
5075 assert(date == Date(-3, 2, 28));
5076 date.add!"months"(85, AllowDayOverflow.no);
5077 assert(date == Date(4, 3, 28));
5078 }
5079
5080 {
5081 auto date = Date(-3, 3, 31);
5082 date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no);
5083 assert(date == Date(-3, 5, 30));
5084 }
5085 }
5086
5087
5088 /++
5089 Adds the given number of years or months to this $(LREF Date). A negative
5090 number will subtract.
5091
5092 The difference between rolling and adding is that rolling does not
5093 affect larger units. Rolling a $(LREF Date) 12 months gets
5094 the exact same $(LREF Date). However, the days can still be affected due
5095 to the differing number of days in each month.
5096
5097 Because there are no units larger than years, there is no difference
5098 between adding and rolling years.
5099
5100 Params:
5101 units = The type of units to add ("years" or "months").
5102 value = The number of months or years to add to this
5103 $(LREF Date).
5104 allowOverflow = Whether the day should be allowed to overflow,
5105 causing the month to increment.
5106 +/
5107 @safe pure nothrow @nogc
5108 ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
5109 if (units == "years")
5110 {
5111 return add!"years"(value, allowOverflow);
5112 }
5113
5114 ///
5115 @safe unittest
5116 {
5117 auto d1 = Date(2010, 1, 1);
5118 d1.roll!"months"(1);
5119 assert(d1 == Date(2010, 2, 1));
5120
5121 auto d2 = Date(2010, 1, 1);
5122 d2.roll!"months"(-1);
5123 assert(d2 == Date(2010, 12, 1));
5124
5125 auto d3 = Date(1999, 1, 29);
5126 d3.roll!"months"(1);
5127 assert(d3 == Date(1999, 3, 1));
5128
5129 auto d4 = Date(1999, 1, 29);
5130 d4.roll!"months"(1, AllowDayOverflow.no);
5131 assert(d4 == Date(1999, 2, 28));
5132
5133 auto d5 = Date(2000, 2, 29);
5134 d5.roll!"years"(1);
5135 assert(d5 == Date(2001, 3, 1));
5136
5137 auto d6 = Date(2000, 2, 29);
5138 d6.roll!"years"(1, AllowDayOverflow.no);
5139 assert(d6 == Date(2001, 2, 28));
5140 }
5141
5142 @safe unittest
5143 {
5144 const cdate = Date(1999, 7, 6);
5145 immutable idate = Date(1999, 7, 6);
5146 static assert(!__traits(compiles, cdate.roll!"years"(3)));
5147 static assert(!__traits(compiles, idate.rolYears(3)));
5148 }
5149
5150
5151 // Shares documentation with "years" version.
5152 @safe pure nothrow @nogc
5153 ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
5154 if (units == "months")
5155 {
5156 months %= 12;
5157 auto newMonth = _month + months;
5158
5159 if (months < 0)
5160 {
5161 if (newMonth < 1)
5162 newMonth += 12;
5163 }
5164 else
5165 {
5166 if (newMonth > 12)
5167 newMonth -= 12;
5168 }
5169
5170 _month = cast(Month) newMonth;
5171
5172 immutable currMaxDay = maxDay(_year, _month);
5173 immutable overflow = _day - currMaxDay;
5174
5175 if (overflow > 0)
5176 {
5177 if (allowOverflow == AllowDayOverflow.yes)
5178 {
5179 ++_month;
5180 _day = cast(ubyte) overflow;
5181 }
5182 else
5183 _day = cast(ubyte) currMaxDay;
5184 }
5185
5186 return this;
5187 }
5188
5189 // Test roll!"months"() with AllowDayOverflow.yes
5190 @safe unittest
5191 {
5192 // Test A.D.
5193 {
5194 auto date = Date(1999, 7, 6);
5195 date.roll!"months"(3);
5196 assert(date == Date(1999, 10, 6));
5197 date.roll!"months"(-4);
5198 assert(date == Date(1999, 6, 6));
5199 }
5200
5201 {
5202 auto date = Date(1999, 7, 6);
5203 date.roll!"months"(6);
5204 assert(date == Date(1999, 1, 6));
5205 date.roll!"months"(-6);
5206 assert(date == Date(1999, 7, 6));
5207 }
5208
5209 {
5210 auto date = Date(1999, 7, 6);
5211 date.roll!"months"(27);
5212 assert(date == Date(1999, 10, 6));
5213 date.roll!"months"(-28);
5214 assert(date == Date(1999, 6, 6));
5215 }
5216
5217 {
5218 auto date = Date(1999, 5, 31);
5219 date.roll!"months"(1);
5220 assert(date == Date(1999, 7, 1));
5221 }
5222
5223 {
5224 auto date = Date(1999, 5, 31);
5225 date.roll!"months"(-1);
5226 assert(date == Date(1999, 5, 1));
5227 }
5228
5229 {
5230 auto date = Date(1999, 2, 28);
5231 date.roll!"months"(12);
5232 assert(date == Date(1999, 2, 28));
5233 }
5234
5235 {
5236 auto date = Date(2000, 2, 29);
5237 date.roll!"months"(12);
5238 assert(date == Date(2000, 2, 29));
5239 }
5240
5241 {
5242 auto date = Date(1999, 7, 31);
5243 date.roll!"months"(1);
5244 assert(date == Date(1999, 8, 31));
5245 date.roll!"months"(1);
5246 assert(date == Date(1999, 10, 1));
5247 }
5248
5249 {
5250 auto date = Date(1998, 8, 31);
5251 date.roll!"months"(13);
5252 assert(date == Date(1998, 10, 1));
5253 date.roll!"months"(-13);
5254 assert(date == Date(1998, 9, 1));
5255 }
5256
5257 {
5258 auto date = Date(1997, 12, 31);
5259 date.roll!"months"(13);
5260 assert(date == Date(1997, 1, 31));
5261 date.roll!"months"(-13);
5262 assert(date == Date(1997, 12, 31));
5263 }
5264
5265 {
5266 auto date = Date(1997, 12, 31);
5267 date.roll!"months"(14);
5268 assert(date == Date(1997, 3, 3));
5269 date.roll!"months"(-14);
5270 assert(date == Date(1997, 1, 3));
5271 }
5272
5273 {
5274 auto date = Date(1998, 12, 31);
5275 date.roll!"months"(14);
5276 assert(date == Date(1998, 3, 3));
5277 date.roll!"months"(-14);
5278 assert(date == Date(1998, 1, 3));
5279 }
5280
5281 {
5282 auto date = Date(1999, 12, 31);
5283 date.roll!"months"(14);
5284 assert(date == Date(1999, 3, 3));
5285 date.roll!"months"(-14);
5286 assert(date == Date(1999, 1, 3));
5287 }
5288
5289 // Test B.C.
5290 {
5291 auto date = Date(-1999, 7, 6);
5292 date.roll!"months"(3);
5293 assert(date == Date(-1999, 10, 6));
5294 date.roll!"months"(-4);
5295 assert(date == Date(-1999, 6, 6));
5296 }
5297
5298 {
5299 auto date = Date(-1999, 7, 6);
5300 date.roll!"months"(6);
5301 assert(date == Date(-1999, 1, 6));
5302 date.roll!"months"(-6);
5303 assert(date == Date(-1999, 7, 6));
5304 }
5305
5306 {
5307 auto date = Date(-1999, 7, 6);
5308 date.roll!"months"(-27);
5309 assert(date == Date(-1999, 4, 6));
5310 date.roll!"months"(28);
5311 assert(date == Date(-1999, 8, 6));
5312 }
5313
5314 {
5315 auto date = Date(-1999, 5, 31);
5316 date.roll!"months"(1);
5317 assert(date == Date(-1999, 7, 1));
5318 }
5319
5320 {
5321 auto date = Date(-1999, 5, 31);
5322 date.roll!"months"(-1);
5323 assert(date == Date(-1999, 5, 1));
5324 }
5325
5326 {
5327 auto date = Date(-1999, 2, 28);
5328 date.roll!"months"(-12);
5329 assert(date == Date(-1999, 2, 28));
5330 }
5331
5332 {
5333 auto date = Date(-2000, 2, 29);
5334 date.roll!"months"(-12);
5335 assert(date == Date(-2000, 2, 29));
5336 }
5337
5338 {
5339 auto date = Date(-1999, 7, 31);
5340 date.roll!"months"(1);
5341 assert(date == Date(-1999, 8, 31));
5342 date.roll!"months"(1);
5343 assert(date == Date(-1999, 10, 1));
5344 }
5345
5346 {
5347 auto date = Date(-1998, 8, 31);
5348 date.roll!"months"(13);
5349 assert(date == Date(-1998, 10, 1));
5350 date.roll!"months"(-13);
5351 assert(date == Date(-1998, 9, 1));
5352 }
5353
5354 {
5355 auto date = Date(-1997, 12, 31);
5356 date.roll!"months"(13);
5357 assert(date == Date(-1997, 1, 31));
5358 date.roll!"months"(-13);
5359 assert(date == Date(-1997, 12, 31));
5360 }
5361
5362 {
5363 auto date = Date(-1997, 12, 31);
5364 date.roll!"months"(14);
5365 assert(date == Date(-1997, 3, 3));
5366 date.roll!"months"(-14);
5367 assert(date == Date(-1997, 1, 3));
5368 }
5369
5370 {
5371 auto date = Date(-2002, 12, 31);
5372 date.roll!"months"(14);
5373 assert(date == Date(-2002, 3, 3));
5374 date.roll!"months"(-14);
5375 assert(date == Date(-2002, 1, 3));
5376 }
5377
5378 {
5379 auto date = Date(-2001, 12, 31);
5380 date.roll!"months"(14);
5381 assert(date == Date(-2001, 3, 3));
5382 date.roll!"months"(-14);
5383 assert(date == Date(-2001, 1, 3));
5384 }
5385
5386 // Test Both
5387 {
5388 auto date = Date(1, 1, 1);
5389 date.roll!"months"(-1);
5390 assert(date == Date(1, 12, 1));
5391 date.roll!"months"(1);
5392 assert(date == Date(1, 1, 1));
5393 }
5394
5395 {
5396 auto date = Date(4, 1, 1);
5397 date.roll!"months"(-48);
5398 assert(date == Date(4, 1, 1));
5399 date.roll!"months"(48);
5400 assert(date == Date(4, 1, 1));
5401 }
5402
5403 {
5404 auto date = Date(4, 3, 31);
5405 date.roll!"months"(-49);
5406 assert(date == Date(4, 3, 2));
5407 date.roll!"months"(49);
5408 assert(date == Date(4, 4, 2));
5409 }
5410
5411 {
5412 auto date = Date(4, 3, 31);
5413 date.roll!"months"(-85);
5414 assert(date == Date(4, 3, 2));
5415 date.roll!"months"(85);
5416 assert(date == Date(4, 4, 2));
5417 }
5418
5419 {
5420 auto date = Date(-1, 1, 1);
5421 date.roll!"months"(-1);
5422 assert(date == Date(-1, 12, 1));
5423 date.roll!"months"(1);
5424 assert(date == Date(-1, 1, 1));
5425 }
5426
5427 {
5428 auto date = Date(-4, 1, 1);
5429 date.roll!"months"(-48);
5430 assert(date == Date(-4, 1, 1));
5431 date.roll!"months"(48);
5432 assert(date == Date(-4, 1, 1));
5433 }
5434
5435 {
5436 auto date = Date(-4, 3, 31);
5437 date.roll!"months"(-49);
5438 assert(date == Date(-4, 3, 2));
5439 date.roll!"months"(49);
5440 assert(date == Date(-4, 4, 2));
5441 }
5442
5443 {
5444 auto date = Date(-4, 3, 31);
5445 date.roll!"months"(-85);
5446 assert(date == Date(-4, 3, 2));
5447 date.roll!"months"(85);
5448 assert(date == Date(-4, 4, 2));
5449 }
5450
5451 {
5452 auto date = Date(-3, 3, 31);
5453 date.roll!"months"(85).roll!"months"(-83);
5454 assert(date == Date(-3, 6, 1));
5455 }
5456
5457 const cdate = Date(1999, 7, 6);
5458 immutable idate = Date(1999, 7, 6);
5459 static assert(!__traits(compiles, cdate.roll!"months"(3)));
5460 static assert(!__traits(compiles, idate.roll!"months"(3)));
5461 }
5462
5463 // Test roll!"months"() with AllowDayOverflow.no
5464 @safe unittest
5465 {
5466 // Test A.D.
5467 {
5468 auto date = Date(1999, 7, 6);
5469 date.roll!"months"(3, AllowDayOverflow.no);
5470 assert(date == Date(1999, 10, 6));
5471 date.roll!"months"(-4, AllowDayOverflow.no);
5472 assert(date == Date(1999, 6, 6));
5473 }
5474
5475 {
5476 auto date = Date(1999, 7, 6);
5477 date.roll!"months"(6, AllowDayOverflow.no);
5478 assert(date == Date(1999, 1, 6));
5479 date.roll!"months"(-6, AllowDayOverflow.no);
5480 assert(date == Date(1999, 7, 6));
5481 }
5482
5483 {
5484 auto date = Date(1999, 7, 6);
5485 date.roll!"months"(27, AllowDayOverflow.no);
5486 assert(date == Date(1999, 10, 6));
5487 date.roll!"months"(-28, AllowDayOverflow.no);
5488 assert(date == Date(1999, 6, 6));
5489 }
5490
5491 {
5492 auto date = Date(1999, 5, 31);
5493 date.roll!"months"(1, AllowDayOverflow.no);
5494 assert(date == Date(1999, 6, 30));
5495 }
5496
5497 {
5498 auto date = Date(1999, 5, 31);
5499 date.roll!"months"(-1, AllowDayOverflow.no);
5500 assert(date == Date(1999, 4, 30));
5501 }
5502
5503 {
5504 auto date = Date(1999, 2, 28);
5505 date.roll!"months"(12, AllowDayOverflow.no);
5506 assert(date == Date(1999, 2, 28));
5507 }
5508
5509 {
5510 auto date = Date(2000, 2, 29);
5511 date.roll!"months"(12, AllowDayOverflow.no);
5512 assert(date == Date(2000, 2, 29));
5513 }
5514
5515 {
5516 auto date = Date(1999, 7, 31);
5517 date.roll!"months"(1, AllowDayOverflow.no);
5518 assert(date == Date(1999, 8, 31));
5519 date.roll!"months"(1, AllowDayOverflow.no);
5520 assert(date == Date(1999, 9, 30));
5521 }
5522
5523 {
5524 auto date = Date(1998, 8, 31);
5525 date.roll!"months"(13, AllowDayOverflow.no);
5526 assert(date == Date(1998, 9, 30));
5527 date.roll!"months"(-13, AllowDayOverflow.no);
5528 assert(date == Date(1998, 8, 30));
5529 }
5530
5531 {
5532 auto date = Date(1997, 12, 31);
5533 date.roll!"months"(13, AllowDayOverflow.no);
5534 assert(date == Date(1997, 1, 31));
5535 date.roll!"months"(-13, AllowDayOverflow.no);
5536 assert(date == Date(1997, 12, 31));
5537 }
5538
5539 {
5540 auto date = Date(1997, 12, 31);
5541 date.roll!"months"(14, AllowDayOverflow.no);
5542 assert(date == Date(1997, 2, 28));
5543 date.roll!"months"(-14, AllowDayOverflow.no);
5544 assert(date == Date(1997, 12, 28));
5545 }
5546
5547 {
5548 auto date = Date(1998, 12, 31);
5549 date.roll!"months"(14, AllowDayOverflow.no);
5550 assert(date == Date(1998, 2, 28));
5551 date.roll!"months"(-14, AllowDayOverflow.no);
5552 assert(date == Date(1998, 12, 28));
5553 }
5554
5555 {
5556 auto date = Date(1999, 12, 31);
5557 date.roll!"months"(14, AllowDayOverflow.no);
5558 assert(date == Date(1999, 2, 28));
5559 date.roll!"months"(-14, AllowDayOverflow.no);
5560 assert(date == Date(1999, 12, 28));
5561 }
5562
5563 // Test B.C.
5564 {
5565 auto date = Date(-1999, 7, 6);
5566 date.roll!"months"(3, AllowDayOverflow.no);
5567 assert(date == Date(-1999, 10, 6));
5568 date.roll!"months"(-4, AllowDayOverflow.no);
5569 assert(date == Date(-1999, 6, 6));
5570 }
5571
5572 {
5573 auto date = Date(-1999, 7, 6);
5574 date.roll!"months"(6, AllowDayOverflow.no);
5575 assert(date == Date(-1999, 1, 6));
5576 date.roll!"months"(-6, AllowDayOverflow.no);
5577 assert(date == Date(-1999, 7, 6));
5578 }
5579
5580 {
5581 auto date = Date(-1999, 7, 6);
5582 date.roll!"months"(-27, AllowDayOverflow.no);
5583 assert(date == Date(-1999, 4, 6));
5584 date.roll!"months"(28, AllowDayOverflow.no);
5585 assert(date == Date(-1999, 8, 6));
5586 }
5587
5588 {
5589 auto date = Date(-1999, 5, 31);
5590 date.roll!"months"(1, AllowDayOverflow.no);
5591 assert(date == Date(-1999, 6, 30));
5592 }
5593
5594 {
5595 auto date = Date(-1999, 5, 31);
5596 date.roll!"months"(-1, AllowDayOverflow.no);
5597 assert(date == Date(-1999, 4, 30));
5598 }
5599
5600 {
5601 auto date = Date(-1999, 2, 28);
5602 date.roll!"months"(-12, AllowDayOverflow.no);
5603 assert(date == Date(-1999, 2, 28));
5604 }
5605
5606 {
5607 auto date = Date(-2000, 2, 29);
5608 date.roll!"months"(-12, AllowDayOverflow.no);
5609 assert(date == Date(-2000, 2, 29));
5610 }
5611
5612 {
5613 auto date = Date(-1999, 7, 31);
5614 date.roll!"months"(1, AllowDayOverflow.no);
5615 assert(date == Date(-1999, 8, 31));
5616 date.roll!"months"(1, AllowDayOverflow.no);
5617 assert(date == Date(-1999, 9, 30));
5618 }
5619
5620 {
5621 auto date = Date(-1998, 8, 31);
5622 date.roll!"months"(13, AllowDayOverflow.no);
5623 assert(date == Date(-1998, 9, 30));
5624 date.roll!"months"(-13, AllowDayOverflow.no);
5625 assert(date == Date(-1998, 8, 30));
5626 }
5627
5628 {
5629 auto date = Date(-1997, 12, 31);
5630 date.roll!"months"(13, AllowDayOverflow.no);
5631 assert(date == Date(-1997, 1, 31));
5632 date.roll!"months"(-13, AllowDayOverflow.no);
5633 assert(date == Date(-1997, 12, 31));
5634 }
5635
5636 {
5637 auto date = Date(-1997, 12, 31);
5638 date.roll!"months"(14, AllowDayOverflow.no);
5639 assert(date == Date(-1997, 2, 28));
5640 date.roll!"months"(-14, AllowDayOverflow.no);
5641 assert(date == Date(-1997, 12, 28));
5642 }
5643
5644 {
5645 auto date = Date(-2002, 12, 31);
5646 date.roll!"months"(14, AllowDayOverflow.no);
5647 assert(date == Date(-2002, 2, 28));
5648 date.roll!"months"(-14, AllowDayOverflow.no);
5649 assert(date == Date(-2002, 12, 28));
5650 }
5651
5652 {
5653 auto date = Date(-2001, 12, 31);
5654 date.roll!"months"(14, AllowDayOverflow.no);
5655 assert(date == Date(-2001, 2, 28));
5656 date.roll!"months"(-14, AllowDayOverflow.no);
5657 assert(date == Date(-2001, 12, 28));
5658 }
5659
5660 // Test Both
5661 {
5662 auto date = Date(1, 1, 1);
5663 date.roll!"months"(-1, AllowDayOverflow.no);
5664 assert(date == Date(1, 12, 1));
5665 date.roll!"months"(1, AllowDayOverflow.no);
5666 assert(date == Date(1, 1, 1));
5667 }
5668
5669 {
5670 auto date = Date(4, 1, 1);
5671 date.roll!"months"(-48, AllowDayOverflow.no);
5672 assert(date == Date(4, 1, 1));
5673 date.roll!"months"(48, AllowDayOverflow.no);
5674 assert(date == Date(4, 1, 1));
5675 }
5676
5677 {
5678 auto date = Date(4, 3, 31);
5679 date.roll!"months"(-49, AllowDayOverflow.no);
5680 assert(date == Date(4, 2, 29));
5681 date.roll!"months"(49, AllowDayOverflow.no);
5682 assert(date == Date(4, 3, 29));
5683 }
5684
5685 {
5686 auto date = Date(4, 3, 31);
5687 date.roll!"months"(-85, AllowDayOverflow.no);
5688 assert(date == Date(4, 2, 29));
5689 date.roll!"months"(85, AllowDayOverflow.no);
5690 assert(date == Date(4, 3, 29));
5691 }
5692
5693 {
5694 auto date = Date(-1, 1, 1);
5695 date.roll!"months"(-1, AllowDayOverflow.no);
5696 assert(date == Date(-1, 12, 1));
5697 date.roll!"months"(1, AllowDayOverflow.no);
5698 assert(date == Date(-1, 1, 1));
5699 }
5700
5701 {
5702 auto date = Date(-4, 1, 1);
5703 date.roll!"months"(-48, AllowDayOverflow.no);
5704 assert(date == Date(-4, 1, 1));
5705 date.roll!"months"(48, AllowDayOverflow.no);
5706 assert(date == Date(-4, 1, 1));
5707 }
5708
5709 {
5710 auto date = Date(-4, 3, 31);
5711 date.roll!"months"(-49, AllowDayOverflow.no);
5712 assert(date == Date(-4, 2, 29));
5713 date.roll!"months"(49, AllowDayOverflow.no);
5714 assert(date == Date(-4, 3, 29));
5715 }
5716
5717 {
5718 auto date = Date(-4, 3, 31);
5719 date.roll!"months"(-85, AllowDayOverflow.no);
5720 assert(date == Date(-4, 2, 29));
5721 date.roll!"months"(85, AllowDayOverflow.no);
5722 assert(date == Date(-4, 3, 29));
5723 }
5724
5725 {
5726 auto date = Date(-3, 3, 31);
5727 date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no);
5728 assert(date == Date(-3, 5, 30));
5729 }
5730 }
5731
5732
5733 /++
5734 Adds the given number of units to this $(LREF Date). A negative number
5735 will subtract.
5736
5737 The difference between rolling and adding is that rolling does not
5738 affect larger units. For instance, rolling a $(LREF Date) one
5739 year's worth of days gets the exact same $(LREF Date).
5740
5741 The only accepted units are $(D "days").
5742
5743 Params:
5744 units = The units to add. Must be $(D "days").
5745 days = The number of days to add to this $(LREF Date).
5746 +/
5747 ref Date roll(string units)(long days) @safe pure nothrow @nogc
5748 if (units == "days")
5749 {
5750 immutable limit = maxDay(_year, _month);
5751 days %= limit;
5752 auto newDay = _day + days;
5753
5754 if (days < 0)
5755 {
5756 if (newDay < 1)
5757 newDay += limit;
5758 }
5759 else if (newDay > limit)
5760 newDay -= limit;
5761
5762 _day = cast(ubyte) newDay;
5763 return this;
5764 }
5765
5766 ///
5767 @safe unittest
5768 {
5769 auto d = Date(2010, 1, 1);
5770 d.roll!"days"(1);
5771 assert(d == Date(2010, 1, 2));
5772 d.roll!"days"(365);
5773 assert(d == Date(2010, 1, 26));
5774 d.roll!"days"(-32);
5775 assert(d == Date(2010, 1, 25));
5776 }
5777
5778 @safe unittest
5779 {
5780 // Test A.D.
5781 {
5782 auto date = Date(1999, 2, 28);
5783 date.roll!"days"(1);
5784 assert(date == Date(1999, 2, 1));
5785 date.roll!"days"(-1);
5786 assert(date == Date(1999, 2, 28));
5787 }
5788
5789 {
5790 auto date = Date(2000, 2, 28);
5791 date.roll!"days"(1);
5792 assert(date == Date(2000, 2, 29));
5793 date.roll!"days"(1);
5794 assert(date == Date(2000, 2, 1));
5795 date.roll!"days"(-1);
5796 assert(date == Date(2000, 2, 29));
5797 }
5798
5799 {
5800 auto date = Date(1999, 6, 30);
5801 date.roll!"days"(1);
5802 assert(date == Date(1999, 6, 1));
5803 date.roll!"days"(-1);
5804 assert(date == Date(1999, 6, 30));
5805 }
5806
5807 {
5808 auto date = Date(1999, 7, 31);
5809 date.roll!"days"(1);
5810 assert(date == Date(1999, 7, 1));
5811 date.roll!"days"(-1);
5812 assert(date == Date(1999, 7, 31));
5813 }
5814
5815 {
5816 auto date = Date(1999, 1, 1);
5817 date.roll!"days"(-1);
5818 assert(date == Date(1999, 1, 31));
5819 date.roll!"days"(1);
5820 assert(date == Date(1999, 1, 1));
5821 }
5822
5823 {
5824 auto date = Date(1999, 7, 6);
5825 date.roll!"days"(9);
5826 assert(date == Date(1999, 7, 15));
5827 date.roll!"days"(-11);
5828 assert(date == Date(1999, 7, 4));
5829 date.roll!"days"(30);
5830 assert(date == Date(1999, 7, 3));
5831 date.roll!"days"(-3);
5832 assert(date == Date(1999, 7, 31));
5833 }
5834
5835 {
5836 auto date = Date(1999, 7, 6);
5837 date.roll!"days"(365);
5838 assert(date == Date(1999, 7, 30));
5839 date.roll!"days"(-365);
5840 assert(date == Date(1999, 7, 6));
5841 date.roll!"days"(366);
5842 assert(date == Date(1999, 7, 31));
5843 date.roll!"days"(730);
5844 assert(date == Date(1999, 7, 17));
5845 date.roll!"days"(-1096);
5846 assert(date == Date(1999, 7, 6));
5847 }
5848
5849 {
5850 auto date = Date(1999, 2, 6);
5851 date.roll!"days"(365);
5852 assert(date == Date(1999, 2, 7));
5853 date.roll!"days"(-365);
5854 assert(date == Date(1999, 2, 6));
5855 date.roll!"days"(366);
5856 assert(date == Date(1999, 2, 8));
5857 date.roll!"days"(730);
5858 assert(date == Date(1999, 2, 10));
5859 date.roll!"days"(-1096);
5860 assert(date == Date(1999, 2, 6));
5861 }
5862
5863 // Test B.C.
5864 {
5865 auto date = Date(-1999, 2, 28);
5866 date.roll!"days"(1);
5867 assert(date == Date(-1999, 2, 1));
5868 date.roll!"days"(-1);
5869 assert(date == Date(-1999, 2, 28));
5870 }
5871
5872 {
5873 auto date = Date(-2000, 2, 28);
5874 date.roll!"days"(1);
5875 assert(date == Date(-2000, 2, 29));
5876 date.roll!"days"(1);
5877 assert(date == Date(-2000, 2, 1));
5878 date.roll!"days"(-1);
5879 assert(date == Date(-2000, 2, 29));
5880 }
5881
5882 {
5883 auto date = Date(-1999, 6, 30);
5884 date.roll!"days"(1);
5885 assert(date == Date(-1999, 6, 1));
5886 date.roll!"days"(-1);
5887 assert(date == Date(-1999, 6, 30));
5888 }
5889
5890 {
5891 auto date = Date(-1999, 7, 31);
5892 date.roll!"days"(1);
5893 assert(date == Date(-1999, 7, 1));
5894 date.roll!"days"(-1);
5895 assert(date == Date(-1999, 7, 31));
5896 }
5897
5898 {
5899 auto date = Date(-1999, 1, 1);
5900 date.roll!"days"(-1);
5901 assert(date == Date(-1999, 1, 31));
5902 date.roll!"days"(1);
5903 assert(date == Date(-1999, 1, 1));
5904 }
5905
5906 {
5907 auto date = Date(-1999, 7, 6);
5908 date.roll!"days"(9);
5909 assert(date == Date(-1999, 7, 15));
5910 date.roll!"days"(-11);
5911 assert(date == Date(-1999, 7, 4));
5912 date.roll!"days"(30);
5913 assert(date == Date(-1999, 7, 3));
5914 date.roll!"days"(-3);
5915 assert(date == Date(-1999, 7, 31));
5916 }
5917
5918 {
5919 auto date = Date(-1999, 7, 6);
5920 date.roll!"days"(365);
5921 assert(date == Date(-1999, 7, 30));
5922 date.roll!"days"(-365);
5923 assert(date == Date(-1999, 7, 6));
5924 date.roll!"days"(366);
5925 assert(date == Date(-1999, 7, 31));
5926 date.roll!"days"(730);
5927 assert(date == Date(-1999, 7, 17));
5928 date.roll!"days"(-1096);
5929 assert(date == Date(-1999, 7, 6));
5930 }
5931
5932 // Test Both
5933 {
5934 auto date = Date(1, 7, 6);
5935 date.roll!"days"(-365);
5936 assert(date == Date(1, 7, 13));
5937 date.roll!"days"(365);
5938 assert(date == Date(1, 7, 6));
5939 date.roll!"days"(-731);
5940 assert(date == Date(1, 7, 19));
5941 date.roll!"days"(730);
5942 assert(date == Date(1, 7, 5));
5943 }
5944
5945 {
5946 auto date = Date(0, 7, 6);
5947 date.roll!"days"(-365);
5948 assert(date == Date(0, 7, 13));
5949 date.roll!"days"(365);
5950 assert(date == Date(0, 7, 6));
5951 date.roll!"days"(-731);
5952 assert(date == Date(0, 7, 19));
5953 date.roll!"days"(730);
5954 assert(date == Date(0, 7, 5));
5955 }
5956
5957 {
5958 auto date = Date(0, 7, 6);
5959 date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730);
5960 assert(date == Date(0, 7, 8));
5961 }
5962
5963 const cdate = Date(1999, 7, 6);
5964 immutable idate = Date(1999, 7, 6);
5965 static assert(!__traits(compiles, cdate.roll!"days"(12)));
5966 static assert(!__traits(compiles, idate.roll!"days"(12)));
5967 }
5968
5969
5970 /++
5971 Gives the result of adding or subtracting a $(REF Duration, core,time)
5972 from
5973
5974 The legal types of arithmetic for $(LREF Date) using this operator are
5975
5976 $(BOOKTABLE,
5977 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date))
5978 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date))
5979 )
5980
5981 Params:
5982 duration = The $(REF Duration, core,time) to add to or subtract from
5983 this $(LREF Date).
5984 +/
5985 Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
5986 if (op == "+" || op == "-")
5987 {
5988 Date retval = this;
5989 immutable days = duration.total!"days";
5990 mixin("return retval._addDays(" ~ op ~ "days);");
5991 }
5992
5993 ///
5994 @safe unittest
5995 {
5996 import core.time : days;
5997
5998 assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1));
5999 assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1));
6000
6001 assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31));
6002 assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26));
6003 }
6004
6005 @safe unittest
6006 {
6007 auto date = Date(1999, 7, 6);
6008
6009 assert(date + dur!"weeks"(7) == Date(1999, 8, 24));
6010 assert(date + dur!"weeks"(-7) == Date(1999, 5, 18));
6011 assert(date + dur!"days"(7) == Date(1999, 7, 13));
6012 assert(date + dur!"days"(-7) == Date(1999, 6, 29));
6013
6014 assert(date + dur!"hours"(24) == Date(1999, 7, 7));
6015 assert(date + dur!"hours"(-24) == Date(1999, 7, 5));
6016 assert(date + dur!"minutes"(1440) == Date(1999, 7, 7));
6017 assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5));
6018 assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7));
6019 assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5));
6020 assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
6021 assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
6022 assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
6023 assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
6024 assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
6025 assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5));
6026
6027 assert(date - dur!"weeks"(-7) == Date(1999, 8, 24));
6028 assert(date - dur!"weeks"(7) == Date(1999, 5, 18));
6029 assert(date - dur!"days"(-7) == Date(1999, 7, 13));
6030 assert(date - dur!"days"(7) == Date(1999, 6, 29));
6031
6032 assert(date - dur!"hours"(-24) == Date(1999, 7, 7));
6033 assert(date - dur!"hours"(24) == Date(1999, 7, 5));
6034 assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7));
6035 assert(date - dur!"minutes"(1440) == Date(1999, 7, 5));
6036 assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7));
6037 assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5));
6038 assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
6039 assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
6040 assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
6041 assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
6042 assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
6043 assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5));
6044
6045 auto duration = dur!"days"(12);
6046 const cdate = Date(1999, 7, 6);
6047 immutable idate = Date(1999, 7, 6);
6048 assert(date + duration == Date(1999, 7, 18));
6049 assert(cdate + duration == Date(1999, 7, 18));
6050 assert(idate + duration == Date(1999, 7, 18));
6051
6052 assert(date - duration == Date(1999, 6, 24));
6053 assert(cdate - duration == Date(1999, 6, 24));
6054 assert(idate - duration == Date(1999, 6, 24));
6055 }
6056
6057
6058 /++
6059 Gives the result of adding or subtracting a $(REF Duration, core,time)
6060 from this $(LREF Date), as well as assigning the result to this
6061 $(LREF Date).
6062
6063 The legal types of arithmetic for $(LREF Date) using this operator are
6064
6065 $(BOOKTABLE,
6066 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date))
6067 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date))
6068 )
6069
6070 Params:
6071 duration = The $(REF Duration, core,time) to add to or subtract from
6072 this $(LREF Date).
6073 +/
6074 ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
6075 if (op == "+" || op == "-")
6076 {
6077 immutable days = duration.total!"days";
6078 mixin("return _addDays(" ~ op ~ "days);");
6079 }
6080
6081 @safe unittest
6082 {
6083 assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24));
6084 assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18));
6085 assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13));
6086 assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29));
6087
6088 assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7));
6089 assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5));
6090 assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7));
6091 assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5));
6092 assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7));
6093 assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5));
6094 assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7));
6095 assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5));
6096 assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7));
6097 assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5));
6098 assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7));
6099 assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5));
6100
6101 assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24));
6102 assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18));
6103 assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13));
6104 assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29));
6105
6106 assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7));
6107 assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5));
6108 assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7));
6109 assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5));
6110 assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7));
6111 assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5));
6112 assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7));
6113 assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5));
6114 assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7));
6115 assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5));
6116 assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7));
6117 assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5));
6118
6119 {
6120 auto date = Date(0, 1, 31);
6121 (date += dur!"days"(507)) += dur!"days"(-2);
6122 assert(date == Date(1, 6, 19));
6123 }
6124
6125 auto duration = dur!"days"(12);
6126 auto date = Date(1999, 7, 6);
6127 const cdate = Date(1999, 7, 6);
6128 immutable idate = Date(1999, 7, 6);
6129 date += duration;
6130 static assert(!__traits(compiles, cdate += duration));
6131 static assert(!__traits(compiles, idate += duration));
6132
6133 date -= duration;
6134 static assert(!__traits(compiles, cdate -= duration));
6135 static assert(!__traits(compiles, idate -= duration));
6136 }
6137
6138
6139 /++
6140 Gives the difference between two $(LREF Date)s.
6141
6142 The legal types of arithmetic for $(LREF Date) using this operator are
6143
6144 $(BOOKTABLE,
6145 $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration))
6146 )
6147 +/
6148 Duration opBinary(string op)(in Date rhs) const @safe pure nothrow @nogc
6149 if (op == "-")
6150 {
6151 return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
6152 }
6153
6154 @safe unittest
6155 {
6156 auto date = Date(1999, 7, 6);
6157
6158 assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365));
6159 assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365));
6160 assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31));
6161 assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31));
6162 assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1));
6163 assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1));
6164
6165 const cdate = Date(1999, 7, 6);
6166 immutable idate = Date(1999, 7, 6);
6167 assert(date - date == Duration.zero);
6168 assert(cdate - date == Duration.zero);
6169 assert(idate - date == Duration.zero);
6170
6171 assert(date - cdate == Duration.zero);
6172 assert(cdate - cdate == Duration.zero);
6173 assert(idate - cdate == Duration.zero);
6174
6175 assert(date - idate == Duration.zero);
6176 assert(cdate - idate == Duration.zero);
6177 assert(idate - idate == Duration.zero);
6178 }
6179
6180
6181 /++
6182 Returns the difference between the two $(LREF Date)s in months.
6183
6184 To get the difference in years, subtract the year property
6185 of two $(LREF Date)s. To get the difference in days or weeks,
6186 subtract the $(LREF Date)s themselves and use the
6187 $(REF Duration, core,time) that results. Because converting between
6188 months and smaller units requires a specific date (which
6189 $(REF Duration, core,time)s don't have), getting the difference in
6190 months requires some math using both the year and month properties, so
6191 this is a convenience function for getting the difference in months.
6192
6193 Note that the number of days in the months or how far into the month
6194 either $(LREF Date) is is irrelevant. It is the difference in the month
6195 property combined with the difference in years * 12. So, for instance,
6196 December 31st and January 1st are one month apart just as December 1st
6197 and January 31st are one month apart.
6198
6199 Params:
6200 rhs = The $(LREF Date) to subtract from this one.
6201 +/
diffMonths(in Date rhs)6202 int diffMonths(in Date rhs) const @safe pure nothrow @nogc
6203 {
6204 immutable yearDiff = _year - rhs._year;
6205 immutable monthDiff = _month - rhs._month;
6206
6207 return yearDiff * 12 + monthDiff;
6208 }
6209
6210 ///
6211 @safe unittest
6212 {
6213 assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1);
6214 assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1);
6215 assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2);
6216 assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2);
6217 }
6218
6219 @safe unittest
6220 {
6221 auto date = Date(1999, 7, 6);
6222
6223 // Test A.D.
6224 assert(date.diffMonths(Date(1998, 6, 5)) == 13);
6225 assert(date.diffMonths(Date(1998, 7, 5)) == 12);
6226 assert(date.diffMonths(Date(1998, 8, 5)) == 11);
6227 assert(date.diffMonths(Date(1998, 9, 5)) == 10);
6228 assert(date.diffMonths(Date(1998, 10, 5)) == 9);
6229 assert(date.diffMonths(Date(1998, 11, 5)) == 8);
6230 assert(date.diffMonths(Date(1998, 12, 5)) == 7);
6231 assert(date.diffMonths(Date(1999, 1, 5)) == 6);
6232 assert(date.diffMonths(Date(1999, 2, 6)) == 5);
6233 assert(date.diffMonths(Date(1999, 3, 6)) == 4);
6234 assert(date.diffMonths(Date(1999, 4, 6)) == 3);
6235 assert(date.diffMonths(Date(1999, 5, 6)) == 2);
6236 assert(date.diffMonths(Date(1999, 6, 6)) == 1);
6237 assert(date.diffMonths(date) == 0);
6238 assert(date.diffMonths(Date(1999, 8, 6)) == -1);
6239 assert(date.diffMonths(Date(1999, 9, 6)) == -2);
6240 assert(date.diffMonths(Date(1999, 10, 6)) == -3);
6241 assert(date.diffMonths(Date(1999, 11, 6)) == -4);
6242 assert(date.diffMonths(Date(1999, 12, 6)) == -5);
6243 assert(date.diffMonths(Date(2000, 1, 6)) == -6);
6244 assert(date.diffMonths(Date(2000, 2, 6)) == -7);
6245 assert(date.diffMonths(Date(2000, 3, 6)) == -8);
6246 assert(date.diffMonths(Date(2000, 4, 6)) == -9);
6247 assert(date.diffMonths(Date(2000, 5, 6)) == -10);
6248 assert(date.diffMonths(Date(2000, 6, 6)) == -11);
6249 assert(date.diffMonths(Date(2000, 7, 6)) == -12);
6250 assert(date.diffMonths(Date(2000, 8, 6)) == -13);
6251
6252 assert(Date(1998, 6, 5).diffMonths(date) == -13);
6253 assert(Date(1998, 7, 5).diffMonths(date) == -12);
6254 assert(Date(1998, 8, 5).diffMonths(date) == -11);
6255 assert(Date(1998, 9, 5).diffMonths(date) == -10);
6256 assert(Date(1998, 10, 5).diffMonths(date) == -9);
6257 assert(Date(1998, 11, 5).diffMonths(date) == -8);
6258 assert(Date(1998, 12, 5).diffMonths(date) == -7);
6259 assert(Date(1999, 1, 5).diffMonths(date) == -6);
6260 assert(Date(1999, 2, 6).diffMonths(date) == -5);
6261 assert(Date(1999, 3, 6).diffMonths(date) == -4);
6262 assert(Date(1999, 4, 6).diffMonths(date) == -3);
6263 assert(Date(1999, 5, 6).diffMonths(date) == -2);
6264 assert(Date(1999, 6, 6).diffMonths(date) == -1);
6265 assert(Date(1999, 8, 6).diffMonths(date) == 1);
6266 assert(Date(1999, 9, 6).diffMonths(date) == 2);
6267 assert(Date(1999, 10, 6).diffMonths(date) == 3);
6268 assert(Date(1999, 11, 6).diffMonths(date) == 4);
6269 assert(Date(1999, 12, 6).diffMonths(date) == 5);
6270 assert(Date(2000, 1, 6).diffMonths(date) == 6);
6271 assert(Date(2000, 2, 6).diffMonths(date) == 7);
6272 assert(Date(2000, 3, 6).diffMonths(date) == 8);
6273 assert(Date(2000, 4, 6).diffMonths(date) == 9);
6274 assert(Date(2000, 5, 6).diffMonths(date) == 10);
6275 assert(Date(2000, 6, 6).diffMonths(date) == 11);
6276 assert(Date(2000, 7, 6).diffMonths(date) == 12);
6277 assert(Date(2000, 8, 6).diffMonths(date) == 13);
6278
6279 assert(date.diffMonths(Date(1999, 6, 30)) == 1);
6280 assert(date.diffMonths(Date(1999, 7, 1)) == 0);
6281 assert(date.diffMonths(Date(1999, 7, 6)) == 0);
6282 assert(date.diffMonths(Date(1999, 7, 11)) == 0);
6283 assert(date.diffMonths(Date(1999, 7, 16)) == 0);
6284 assert(date.diffMonths(Date(1999, 7, 21)) == 0);
6285 assert(date.diffMonths(Date(1999, 7, 26)) == 0);
6286 assert(date.diffMonths(Date(1999, 7, 31)) == 0);
6287 assert(date.diffMonths(Date(1999, 8, 1)) == -1);
6288
6289 assert(date.diffMonths(Date(1990, 6, 30)) == 109);
6290 assert(date.diffMonths(Date(1990, 7, 1)) == 108);
6291 assert(date.diffMonths(Date(1990, 7, 6)) == 108);
6292 assert(date.diffMonths(Date(1990, 7, 11)) == 108);
6293 assert(date.diffMonths(Date(1990, 7, 16)) == 108);
6294 assert(date.diffMonths(Date(1990, 7, 21)) == 108);
6295 assert(date.diffMonths(Date(1990, 7, 26)) == 108);
6296 assert(date.diffMonths(Date(1990, 7, 31)) == 108);
6297 assert(date.diffMonths(Date(1990, 8, 1)) == 107);
6298
6299 assert(Date(1999, 6, 30).diffMonths(date) == -1);
6300 assert(Date(1999, 7, 1).diffMonths(date) == 0);
6301 assert(Date(1999, 7, 6).diffMonths(date) == 0);
6302 assert(Date(1999, 7, 11).diffMonths(date) == 0);
6303 assert(Date(1999, 7, 16).diffMonths(date) == 0);
6304 assert(Date(1999, 7, 21).diffMonths(date) == 0);
6305 assert(Date(1999, 7, 26).diffMonths(date) == 0);
6306 assert(Date(1999, 7, 31).diffMonths(date) == 0);
6307 assert(Date(1999, 8, 1).diffMonths(date) == 1);
6308
6309 assert(Date(1990, 6, 30).diffMonths(date) == -109);
6310 assert(Date(1990, 7, 1).diffMonths(date) == -108);
6311 assert(Date(1990, 7, 6).diffMonths(date) == -108);
6312 assert(Date(1990, 7, 11).diffMonths(date) == -108);
6313 assert(Date(1990, 7, 16).diffMonths(date) == -108);
6314 assert(Date(1990, 7, 21).diffMonths(date) == -108);
6315 assert(Date(1990, 7, 26).diffMonths(date) == -108);
6316 assert(Date(1990, 7, 31).diffMonths(date) == -108);
6317 assert(Date(1990, 8, 1).diffMonths(date) == -107);
6318
6319 // Test B.C.
6320 auto dateBC = Date(-1999, 7, 6);
6321
6322 assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13);
6323 assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12);
6324 assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11);
6325 assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10);
6326 assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9);
6327 assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8);
6328 assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7);
6329 assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6);
6330 assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5);
6331 assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4);
6332 assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3);
6333 assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2);
6334 assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1);
6335 assert(dateBC.diffMonths(dateBC) == 0);
6336 assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1);
6337 assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2);
6338 assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3);
6339 assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4);
6340 assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5);
6341 assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6);
6342 assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7);
6343 assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8);
6344 assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9);
6345 assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10);
6346 assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11);
6347 assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12);
6348 assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13);
6349
6350 assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13);
6351 assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12);
6352 assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11);
6353 assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10);
6354 assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9);
6355 assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8);
6356 assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7);
6357 assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6);
6358 assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5);
6359 assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4);
6360 assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3);
6361 assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2);
6362 assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1);
6363 assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1);
6364 assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2);
6365 assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3);
6366 assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4);
6367 assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5);
6368 assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6);
6369 assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7);
6370 assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8);
6371 assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9);
6372 assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10);
6373 assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11);
6374 assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12);
6375 assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13);
6376
6377 assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1);
6378 assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0);
6379 assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0);
6380 assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0);
6381 assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0);
6382 assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0);
6383 assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0);
6384 assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0);
6385 assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1);
6386
6387 assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109);
6388 assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108);
6389 assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108);
6390 assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108);
6391 assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108);
6392 assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108);
6393 assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108);
6394 assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108);
6395 assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107);
6396
6397 assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1);
6398 assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0);
6399 assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0);
6400 assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0);
6401 assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0);
6402 assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0);
6403 assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0);
6404 assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0);
6405 assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1);
6406
6407 assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109);
6408 assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108);
6409 assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108);
6410 assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108);
6411 assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108);
6412 assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108);
6413 assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108);
6414 assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108);
6415 assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107);
6416
6417 // Test Both
6418 assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94);
6419 assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94);
6420
6421 const cdate = Date(1999, 7, 6);
6422 immutable idate = Date(1999, 7, 6);
6423 assert(date.diffMonths(date) == 0);
6424 assert(cdate.diffMonths(date) == 0);
6425 assert(idate.diffMonths(date) == 0);
6426
6427 assert(date.diffMonths(cdate) == 0);
6428 assert(cdate.diffMonths(cdate) == 0);
6429 assert(idate.diffMonths(cdate) == 0);
6430
6431 assert(date.diffMonths(idate) == 0);
6432 assert(cdate.diffMonths(idate) == 0);
6433 assert(idate.diffMonths(idate) == 0);
6434 }
6435
6436
6437 /++
6438 Whether this $(LREF Date) is in a leap year.
6439 +/
isLeapYear()6440 @property bool isLeapYear() const @safe pure nothrow @nogc
6441 {
6442 return yearIsLeapYear(_year);
6443 }
6444
6445 @safe unittest
6446 {
6447 auto date = Date(1999, 7, 6);
6448 const cdate = Date(1999, 7, 6);
6449 immutable idate = Date(1999, 7, 6);
6450 static assert(!__traits(compiles, date.isLeapYear = true));
6451 static assert(!__traits(compiles, cdate.isLeapYear = true));
6452 static assert(!__traits(compiles, idate.isLeapYear = true));
6453 }
6454
6455
6456 /++
6457 Day of the week this $(LREF Date) is on.
6458 +/
dayOfWeek()6459 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc
6460 {
6461 return getDayOfWeek(dayOfGregorianCal);
6462 }
6463
6464 @safe unittest
6465 {
6466 const cdate = Date(1999, 7, 6);
6467 immutable idate = Date(1999, 7, 6);
6468 assert(cdate.dayOfWeek == DayOfWeek.tue);
6469 static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun));
6470 assert(idate.dayOfWeek == DayOfWeek.tue);
6471 static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun));
6472 }
6473
6474
6475 /++
6476 Day of the year this $(LREF Date) is on.
6477 +/
dayOfYear()6478 @property ushort dayOfYear() const @safe pure nothrow @nogc
6479 {
6480 if (_month >= Month.jan && _month <= Month.dec)
6481 {
6482 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
6483 auto monthIndex = _month - Month.jan;
6484
6485 return cast(ushort)(lastDay[monthIndex] + _day);
6486 }
6487 assert(0, "Invalid month.");
6488 }
6489
6490 ///
6491 @safe unittest
6492 {
6493 assert(Date(1999, 1, 1).dayOfYear == 1);
6494 assert(Date(1999, 12, 31).dayOfYear == 365);
6495 assert(Date(2000, 12, 31).dayOfYear == 366);
6496 }
6497
6498 @safe unittest
6499 {
6500 import std.algorithm.iteration : filter;
6501 import std.range : chain;
6502
6503 foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD)))
6504 {
6505 foreach (doy; testDaysOfYear)
6506 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day);
6507 }
6508
6509 foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD)))
6510 {
6511 foreach (doy; testDaysOfLeapYear)
6512 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day);
6513 }
6514
6515 const cdate = Date(1999, 7, 6);
6516 immutable idate = Date(1999, 7, 6);
6517 assert(cdate.dayOfYear == 187);
6518 assert(idate.dayOfYear == 187);
6519 }
6520
6521 /++
6522 Day of the year.
6523
6524 Params:
6525 day = The day of the year to set which day of the year this
6526 $(LREF Date) is on.
6527
6528 Throws:
6529 $(REF DateTimeException,std,datetime,date) if the given day is an
6530 invalid day of the year.
6531 +/
dayOfYear(int day)6532 @property void dayOfYear(int day) @safe pure
6533 {
6534 setDayOfYear!true(day);
6535 }
6536
6537 private void setDayOfYear(bool useExceptions = false)(int day)
6538 {
6539 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap;
6540
6541 bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear);
6542 enum errorMsg = "Invalid day of the year.";
6543
6544 static if (useExceptions)
6545 {
6546 if (dayOutOfRange) throw new DateTimeException(errorMsg);
6547 }
6548 else
6549 {
6550 assert(!dayOutOfRange, errorMsg);
6551 }
6552
6553 foreach (i; 1 .. lastDay.length)
6554 {
6555 if (day <= lastDay[i])
6556 {
6557 _month = cast(Month)(cast(int) Month.jan + i - 1);
6558 _day = cast(ubyte)(day - lastDay[i - 1]);
6559 return;
6560 }
6561 }
6562 assert(0, "Invalid day of the year.");
6563 }
6564
6565 @safe unittest
6566 {
6567 static void test(Date date, int day, MonthDay expected, size_t line = __LINE__)
6568 {
6569 date.dayOfYear = day;
6570 assert(date.month == expected.month);
6571 assert(date.day == expected.day);
6572 }
6573
foreach(doy;testDaysOfYear)6574 foreach (doy; testDaysOfYear)
6575 {
6576 test(Date(1999, 1, 1), doy.day, doy.md);
6577 test(Date(-1, 1, 1), doy.day, doy.md);
6578 }
6579
foreach(doy;testDaysOfLeapYear)6580 foreach (doy; testDaysOfLeapYear)
6581 {
6582 test(Date(2000, 1, 1), doy.day, doy.md);
6583 test(Date(-4, 1, 1), doy.day, doy.md);
6584 }
6585
6586 const cdate = Date(1999, 7, 6);
6587 immutable idate = Date(1999, 7, 6);
6588 static assert(!__traits(compiles, cdate.dayOfYear = 187));
6589 static assert(!__traits(compiles, idate.dayOfYear = 187));
6590 }
6591
6592
6593 /++
6594 The Xth day of the Gregorian Calendar that this $(LREF Date) is on.
6595 +/
dayOfGregorianCal()6596 @property int dayOfGregorianCal() const @safe pure nothrow @nogc
6597 {
6598 if (isAD)
6599 {
6600 if (_year == 1)
6601 return dayOfYear;
6602
6603 int years = _year - 1;
6604 auto days = (years / 400) * daysIn400Years;
6605 years %= 400;
6606
6607 days += (years / 100) * daysIn100Years;
6608 years %= 100;
6609
6610 days += (years / 4) * daysIn4Years;
6611 years %= 4;
6612
6613 days += years * daysInYear;
6614
6615 days += dayOfYear;
6616
6617 return days;
6618 }
6619 else if (_year == 0)
6620 return dayOfYear - daysInLeapYear;
6621 else
6622 {
6623 int years = _year;
6624 auto days = (years / 400) * daysIn400Years;
6625 years %= 400;
6626
6627 days += (years / 100) * daysIn100Years;
6628 years %= 100;
6629
6630 days += (years / 4) * daysIn4Years;
6631 years %= 4;
6632
6633 if (years < 0)
6634 {
6635 days -= daysInLeapYear;
6636 ++years;
6637
6638 days += years * daysInYear;
6639
6640 days -= daysInYear - dayOfYear;
6641 }
6642 else
6643 days -= daysInLeapYear - dayOfYear;
6644
6645 return days;
6646 }
6647 }
6648
6649 ///
6650 @safe unittest
6651 {
6652 assert(Date(1, 1, 1).dayOfGregorianCal == 1);
6653 assert(Date(1, 12, 31).dayOfGregorianCal == 365);
6654 assert(Date(2, 1, 1).dayOfGregorianCal == 366);
6655
6656 assert(Date(0, 12, 31).dayOfGregorianCal == 0);
6657 assert(Date(0, 1, 1).dayOfGregorianCal == -365);
6658 assert(Date(-1, 12, 31).dayOfGregorianCal == -366);
6659
6660 assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120);
6661 assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137);
6662 }
6663
6664 @safe unittest
6665 {
6666 import std.range : chain;
6667
6668 foreach (gd; chain(testGregDaysBC, testGregDaysAD))
6669 assert(gd.date.dayOfGregorianCal == gd.day);
6670
6671 auto date = Date(1999, 7, 6);
6672 const cdate = Date(1999, 7, 6);
6673 immutable idate = Date(1999, 7, 6);
6674 assert(date.dayOfGregorianCal == 729_941);
6675 assert(cdate.dayOfGregorianCal == 729_941);
6676 assert(idate.dayOfGregorianCal == 729_941);
6677 }
6678
6679 /++
6680 The Xth day of the Gregorian Calendar that this $(LREF Date) is on.
6681
6682 Params:
6683 day = The day of the Gregorian Calendar to set this $(LREF Date) to.
6684 +/
dayOfGregorianCal(int day)6685 @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc
6686 {
6687 this = Date(day);
6688 }
6689
6690 ///
6691 @safe unittest
6692 {
6693 auto date = Date.init;
6694 date.dayOfGregorianCal = 1;
6695 assert(date == Date(1, 1, 1));
6696
6697 date.dayOfGregorianCal = 365;
6698 assert(date == Date(1, 12, 31));
6699
6700 date.dayOfGregorianCal = 366;
6701 assert(date == Date(2, 1, 1));
6702
6703 date.dayOfGregorianCal = 0;
6704 assert(date == Date(0, 12, 31));
6705
6706 date.dayOfGregorianCal = -365;
6707 assert(date == Date(-0, 1, 1));
6708
6709 date.dayOfGregorianCal = -366;
6710 assert(date == Date(-1, 12, 31));
6711
6712 date.dayOfGregorianCal = 730_120;
6713 assert(date == Date(2000, 1, 1));
6714
6715 date.dayOfGregorianCal = 734_137;
6716 assert(date == Date(2010, 12, 31));
6717 }
6718
6719 @safe unittest
6720 {
6721 auto date = Date(1999, 7, 6);
6722 const cdate = Date(1999, 7, 6);
6723 immutable idate = Date(1999, 7, 6);
6724 date.dayOfGregorianCal = 187;
6725 assert(date.dayOfGregorianCal == 187);
6726 static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187));
6727 static assert(!__traits(compiles, idate.dayOfGregorianCal = 187));
6728 }
6729
6730
6731 /++
6732 The ISO 8601 week of the year that this $(LREF Date) is in.
6733
6734 See_Also:
6735 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date)
6736 +/
isoWeek()6737 @property ubyte isoWeek() const @safe pure nothrow
6738 {
6739 immutable weekday = dayOfWeek;
6740 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday;
6741 immutable week = (dayOfYear - adjustedWeekday + 10) / 7;
6742
6743 try
6744 {
6745 if (week == 53)
6746 {
6747 switch (Date(_year + 1, 1, 1).dayOfWeek)
6748 {
6749 case DayOfWeek.mon:
6750 case DayOfWeek.tue:
6751 case DayOfWeek.wed:
6752 case DayOfWeek.thu:
6753 return 1;
6754 case DayOfWeek.fri:
6755 case DayOfWeek.sat:
6756 case DayOfWeek.sun:
6757 return 53;
6758 default:
6759 assert(0, "Invalid ISO Week");
6760 }
6761 }
6762 else if (week > 0)
6763 return cast(ubyte) week;
6764 else
6765 return Date(_year - 1, 12, 31).isoWeek;
6766 }
6767 catch (Exception e)
6768 assert(0, "Date's constructor threw.");
6769 }
6770
6771 @safe unittest
6772 {
6773 // Test A.D.
6774 assert(Date(2009, 12, 28).isoWeek == 53);
6775 assert(Date(2009, 12, 29).isoWeek == 53);
6776 assert(Date(2009, 12, 30).isoWeek == 53);
6777 assert(Date(2009, 12, 31).isoWeek == 53);
6778 assert(Date(2010, 1, 1).isoWeek == 53);
6779 assert(Date(2010, 1, 2).isoWeek == 53);
6780 assert(Date(2010, 1, 3).isoWeek == 53);
6781 assert(Date(2010, 1, 4).isoWeek == 1);
6782 assert(Date(2010, 1, 5).isoWeek == 1);
6783 assert(Date(2010, 1, 6).isoWeek == 1);
6784 assert(Date(2010, 1, 7).isoWeek == 1);
6785 assert(Date(2010, 1, 8).isoWeek == 1);
6786 assert(Date(2010, 1, 9).isoWeek == 1);
6787 assert(Date(2010, 1, 10).isoWeek == 1);
6788 assert(Date(2010, 1, 11).isoWeek == 2);
6789 assert(Date(2010, 12, 31).isoWeek == 52);
6790
6791 assert(Date(2004, 12, 26).isoWeek == 52);
6792 assert(Date(2004, 12, 27).isoWeek == 53);
6793 assert(Date(2004, 12, 28).isoWeek == 53);
6794 assert(Date(2004, 12, 29).isoWeek == 53);
6795 assert(Date(2004, 12, 30).isoWeek == 53);
6796 assert(Date(2004, 12, 31).isoWeek == 53);
6797 assert(Date(2005, 1, 1).isoWeek == 53);
6798 assert(Date(2005, 1, 2).isoWeek == 53);
6799
6800 assert(Date(2005, 12, 31).isoWeek == 52);
6801 assert(Date(2007, 1, 1).isoWeek == 1);
6802
6803 assert(Date(2007, 12, 30).isoWeek == 52);
6804 assert(Date(2007, 12, 31).isoWeek == 1);
6805 assert(Date(2008, 1, 1).isoWeek == 1);
6806
6807 assert(Date(2008, 12, 28).isoWeek == 52);
6808 assert(Date(2008, 12, 29).isoWeek == 1);
6809 assert(Date(2008, 12, 30).isoWeek == 1);
6810 assert(Date(2008, 12, 31).isoWeek == 1);
6811 assert(Date(2009, 1, 1).isoWeek == 1);
6812 assert(Date(2009, 1, 2).isoWeek == 1);
6813 assert(Date(2009, 1, 3).isoWeek == 1);
6814 assert(Date(2009, 1, 4).isoWeek == 1);
6815
6816 // Test B.C.
6817 // The algorithm should work identically for both A.D. and B.C. since
6818 // it doesn't really take the year into account, so B.C. testing
6819 // probably isn't really needed.
6820 assert(Date(0, 12, 31).isoWeek == 52);
6821 assert(Date(0, 1, 4).isoWeek == 1);
6822 assert(Date(0, 1, 1).isoWeek == 52);
6823
6824 const cdate = Date(1999, 7, 6);
6825 immutable idate = Date(1999, 7, 6);
6826 assert(cdate.isoWeek == 27);
6827 static assert(!__traits(compiles, cdate.isoWeek = 3));
6828 assert(idate.isoWeek == 27);
6829 static assert(!__traits(compiles, idate.isoWeek = 3));
6830 }
6831
6832
6833 /++
6834 $(LREF Date) for the last day in the month that this $(LREF Date) is in.
6835 +/
endOfMonth()6836 @property Date endOfMonth() const @safe pure nothrow
6837 {
6838 try
6839 return Date(_year, _month, maxDay(_year, _month));
6840 catch (Exception e)
6841 assert(0, "Date's constructor threw.");
6842 }
6843
6844 ///
6845 @safe unittest
6846 {
6847 assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31));
6848 assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28));
6849 assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29));
6850 assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30));
6851 }
6852
6853 @safe unittest
6854 {
6855 // Test A.D.
6856 assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31));
6857 assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28));
6858 assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29));
6859 assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31));
6860 assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30));
6861 assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31));
6862 assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30));
6863 assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31));
6864 assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31));
6865 assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30));
6866 assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31));
6867 assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30));
6868 assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31));
6869
6870 // Test B.C.
6871 assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31));
6872 assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28));
6873 assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29));
6874 assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31));
6875 assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30));
6876 assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31));
6877 assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30));
6878 assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31));
6879 assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31));
6880 assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30));
6881 assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31));
6882 assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30));
6883 assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31));
6884
6885 const cdate = Date(1999, 7, 6);
6886 immutable idate = Date(1999, 7, 6);
6887 static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30)));
6888 static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30)));
6889 }
6890
6891
6892 /++
6893 The last day in the month that this $(LREF Date) is in.
6894 +/
daysInMonth()6895 @property ubyte daysInMonth() const @safe pure nothrow @nogc
6896 {
6897 return maxDay(_year, _month);
6898 }
6899
6900 ///
6901 @safe unittest
6902 {
6903 assert(Date(1999, 1, 6).daysInMonth == 31);
6904 assert(Date(1999, 2, 7).daysInMonth == 28);
6905 assert(Date(2000, 2, 7).daysInMonth == 29);
6906 assert(Date(2000, 6, 4).daysInMonth == 30);
6907 }
6908
6909 @safe unittest
6910 {
6911 // Test A.D.
6912 assert(Date(1999, 1, 1).daysInMonth == 31);
6913 assert(Date(1999, 2, 1).daysInMonth == 28);
6914 assert(Date(2000, 2, 1).daysInMonth == 29);
6915 assert(Date(1999, 3, 1).daysInMonth == 31);
6916 assert(Date(1999, 4, 1).daysInMonth == 30);
6917 assert(Date(1999, 5, 1).daysInMonth == 31);
6918 assert(Date(1999, 6, 1).daysInMonth == 30);
6919 assert(Date(1999, 7, 1).daysInMonth == 31);
6920 assert(Date(1999, 8, 1).daysInMonth == 31);
6921 assert(Date(1999, 9, 1).daysInMonth == 30);
6922 assert(Date(1999, 10, 1).daysInMonth == 31);
6923 assert(Date(1999, 11, 1).daysInMonth == 30);
6924 assert(Date(1999, 12, 1).daysInMonth == 31);
6925
6926 // Test B.C.
6927 assert(Date(-1999, 1, 1).daysInMonth == 31);
6928 assert(Date(-1999, 2, 1).daysInMonth == 28);
6929 assert(Date(-2000, 2, 1).daysInMonth == 29);
6930 assert(Date(-1999, 3, 1).daysInMonth == 31);
6931 assert(Date(-1999, 4, 1).daysInMonth == 30);
6932 assert(Date(-1999, 5, 1).daysInMonth == 31);
6933 assert(Date(-1999, 6, 1).daysInMonth == 30);
6934 assert(Date(-1999, 7, 1).daysInMonth == 31);
6935 assert(Date(-1999, 8, 1).daysInMonth == 31);
6936 assert(Date(-1999, 9, 1).daysInMonth == 30);
6937 assert(Date(-1999, 10, 1).daysInMonth == 31);
6938 assert(Date(-1999, 11, 1).daysInMonth == 30);
6939 assert(Date(-1999, 12, 1).daysInMonth == 31);
6940
6941 const cdate = Date(1999, 7, 6);
6942 immutable idate = Date(1999, 7, 6);
6943 static assert(!__traits(compiles, cdate.daysInMonth = 30));
6944 static assert(!__traits(compiles, idate.daysInMonth = 30));
6945 }
6946
6947
6948 /++
6949 Whether the current year is a date in A.D.
6950 +/
isAD()6951 @property bool isAD() const @safe pure nothrow @nogc
6952 {
6953 return _year > 0;
6954 }
6955
6956 ///
6957 @safe unittest
6958 {
6959 assert(Date(1, 1, 1).isAD);
6960 assert(Date(2010, 12, 31).isAD);
6961 assert(!Date(0, 12, 31).isAD);
6962 assert(!Date(-2010, 1, 1).isAD);
6963 }
6964
6965 @safe unittest
6966 {
6967 assert(Date(2010, 7, 4).isAD);
6968 assert(Date(1, 1, 1).isAD);
6969 assert(!Date(0, 1, 1).isAD);
6970 assert(!Date(-1, 1, 1).isAD);
6971 assert(!Date(-2010, 7, 4).isAD);
6972
6973 const cdate = Date(1999, 7, 6);
6974 immutable idate = Date(1999, 7, 6);
6975 assert(cdate.isAD);
6976 assert(idate.isAD);
6977 }
6978
6979
6980 /++
6981 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this
6982 $(LREF Date) at noon (since the Julian day changes at noon).
6983 +/
julianDay()6984 @property long julianDay() const @safe pure nothrow @nogc
6985 {
6986 return dayOfGregorianCal + 1_721_425;
6987 }
6988
6989 @safe unittest
6990 {
6991 assert(Date(-4713, 11, 24).julianDay == 0);
6992 assert(Date(0, 12, 31).julianDay == 1_721_425);
6993 assert(Date(1, 1, 1).julianDay == 1_721_426);
6994 assert(Date(1582, 10, 15).julianDay == 2_299_161);
6995 assert(Date(1858, 11, 17).julianDay == 2_400_001);
6996 assert(Date(1982, 1, 4).julianDay == 2_444_974);
6997 assert(Date(1996, 3, 31).julianDay == 2_450_174);
6998 assert(Date(2010, 8, 24).julianDay == 2_455_433);
6999
7000 const cdate = Date(1999, 7, 6);
7001 immutable idate = Date(1999, 7, 6);
7002 assert(cdate.julianDay == 2_451_366);
7003 assert(idate.julianDay == 2_451_366);
7004 }
7005
7006
7007 /++
7008 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for
7009 any time on this date (since, the modified Julian day changes at
7010 midnight).
7011 +/
modJulianDay()7012 @property long modJulianDay() const @safe pure nothrow @nogc
7013 {
7014 return julianDay - 2_400_001;
7015 }
7016
7017 @safe unittest
7018 {
7019 assert(Date(1858, 11, 17).modJulianDay == 0);
7020 assert(Date(2010, 8, 24).modJulianDay == 55_432);
7021
7022 const cdate = Date(1999, 7, 6);
7023 immutable idate = Date(1999, 7, 6);
7024 assert(cdate.modJulianDay == 51_365);
7025 assert(idate.modJulianDay == 51_365);
7026 }
7027
7028
7029 /++
7030 Converts this $(LREF Date) to a string with the format YYYYMMDD.
7031 +/
toISOString()7032 string toISOString() const @safe pure nothrow
7033 {
7034 import std.format : format;
7035 try
7036 {
7037 if (_year >= 0)
7038 {
7039 if (_year < 10_000)
7040 return format("%04d%02d%02d", _year, _month, _day);
7041 else
7042 return format("+%05d%02d%02d", _year, _month, _day);
7043 }
7044 else if (_year > -10_000)
7045 return format("%05d%02d%02d", _year, _month, _day);
7046 else
7047 return format("%06d%02d%02d", _year, _month, _day);
7048 }
7049 catch (Exception e)
7050 assert(0, "format() threw.");
7051 }
7052
7053 ///
7054 @safe unittest
7055 {
7056 assert(Date(2010, 7, 4).toISOString() == "20100704");
7057 assert(Date(1998, 12, 25).toISOString() == "19981225");
7058 assert(Date(0, 1, 5).toISOString() == "00000105");
7059 assert(Date(-4, 1, 5).toISOString() == "-00040105");
7060 }
7061
7062 @safe unittest
7063 {
7064 // Test A.D.
7065 assert(Date(9, 12, 4).toISOString() == "00091204");
7066 assert(Date(99, 12, 4).toISOString() == "00991204");
7067 assert(Date(999, 12, 4).toISOString() == "09991204");
7068 assert(Date(9999, 7, 4).toISOString() == "99990704");
7069 assert(Date(10000, 10, 20).toISOString() == "+100001020");
7070
7071 // Test B.C.
7072 assert(Date(0, 12, 4).toISOString() == "00001204");
7073 assert(Date(-9, 12, 4).toISOString() == "-00091204");
7074 assert(Date(-99, 12, 4).toISOString() == "-00991204");
7075 assert(Date(-999, 12, 4).toISOString() == "-09991204");
7076 assert(Date(-9999, 7, 4).toISOString() == "-99990704");
7077 assert(Date(-10000, 10, 20).toISOString() == "-100001020");
7078
7079 const cdate = Date(1999, 7, 6);
7080 immutable idate = Date(1999, 7, 6);
7081 assert(cdate.toISOString() == "19990706");
7082 assert(idate.toISOString() == "19990706");
7083 }
7084
7085 /++
7086 Converts this $(LREF Date) to a string with the format YYYY-MM-DD.
7087 +/
toISOExtString()7088 string toISOExtString() const @safe pure nothrow
7089 {
7090 import std.format : format;
7091 try
7092 {
7093 if (_year >= 0)
7094 {
7095 if (_year < 10_000)
7096 return format("%04d-%02d-%02d", _year, _month, _day);
7097 else
7098 return format("+%05d-%02d-%02d", _year, _month, _day);
7099 }
7100 else if (_year > -10_000)
7101 return format("%05d-%02d-%02d", _year, _month, _day);
7102 else
7103 return format("%06d-%02d-%02d", _year, _month, _day);
7104 }
7105 catch (Exception e)
7106 assert(0, "format() threw.");
7107 }
7108
7109 ///
7110 @safe unittest
7111 {
7112 assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04");
7113 assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25");
7114 assert(Date(0, 1, 5).toISOExtString() == "0000-01-05");
7115 assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05");
7116 }
7117
7118 @safe unittest
7119 {
7120 // Test A.D.
7121 assert(Date(9, 12, 4).toISOExtString() == "0009-12-04");
7122 assert(Date(99, 12, 4).toISOExtString() == "0099-12-04");
7123 assert(Date(999, 12, 4).toISOExtString() == "0999-12-04");
7124 assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04");
7125 assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20");
7126
7127 // Test B.C.
7128 assert(Date(0, 12, 4).toISOExtString() == "0000-12-04");
7129 assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04");
7130 assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04");
7131 assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04");
7132 assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04");
7133 assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20");
7134
7135 const cdate = Date(1999, 7, 6);
7136 immutable idate = Date(1999, 7, 6);
7137 assert(cdate.toISOExtString() == "1999-07-06");
7138 assert(idate.toISOExtString() == "1999-07-06");
7139 }
7140
7141 /++
7142 Converts this $(LREF Date) to a string with the format YYYY-Mon-DD.
7143 +/
toSimpleString()7144 string toSimpleString() const @safe pure nothrow
7145 {
7146 import std.format : format;
7147 try
7148 {
7149 if (_year >= 0)
7150 {
7151 if (_year < 10_000)
7152 return format("%04d-%s-%02d", _year, monthToString(_month), _day);
7153 else
7154 return format("+%05d-%s-%02d", _year, monthToString(_month), _day);
7155 }
7156 else if (_year > -10_000)
7157 return format("%05d-%s-%02d", _year, monthToString(_month), _day);
7158 else
7159 return format("%06d-%s-%02d", _year, monthToString(_month), _day);
7160 }
7161 catch (Exception e)
7162 assert(0, "format() threw.");
7163 }
7164
7165 ///
7166 @safe unittest
7167 {
7168 assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04");
7169 assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25");
7170 assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05");
7171 assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05");
7172 }
7173
7174 @safe unittest
7175 {
7176 // Test A.D.
7177 assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04");
7178 assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04");
7179 assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04");
7180 assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04");
7181 assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20");
7182
7183 // Test B.C.
7184 assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04");
7185 assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04");
7186 assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04");
7187 assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04");
7188 assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04");
7189 assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20");
7190
7191 const cdate = Date(1999, 7, 6);
7192 immutable idate = Date(1999, 7, 6);
7193 assert(cdate.toSimpleString() == "1999-Jul-06");
7194 assert(idate.toSimpleString() == "1999-Jul-06");
7195 }
7196
7197
7198 /++
7199 Converts this $(LREF Date) to a string.
7200
7201 This function exists to make it easy to convert a $(LREF Date) to a
7202 string for code that does not care what the exact format is - just that
7203 it presents the information in a clear manner. It also makes it easy to
7204 simply convert a $(LREF Date) to a string when using functions such as
7205 `to!string`, `format`, or `writeln` which use toString to convert
7206 user-defined types. So, it is unlikely that much code will call
7207 toString directly.
7208
7209 The format of the string is purposefully unspecified, and code that
7210 cares about the format of the string should use `toISOString`,
7211 `toISOExtString`, `toSimpleString`, or some other custom formatting
7212 function that explicitly generates the format that the code needs. The
7213 reason is that the code is then clear about what format it's using,
7214 making it less error-prone to maintain the code and interact with other
7215 software that consumes the generated strings. It's for this same reason
7216 $(LREF Date) has no `fromString` function, whereas it does have
7217 `fromISOString`, `fromISOExtString`, and `fromSimpleString`.
7218
7219 The format returned by toString may or may not change in the future.
7220 +/
toString()7221 string toString() const @safe pure nothrow
7222 {
7223 return toSimpleString();
7224 }
7225
7226 @safe unittest
7227 {
7228 auto date = Date(1999, 7, 6);
7229 const cdate = Date(1999, 7, 6);
7230 immutable idate = Date(1999, 7, 6);
7231 assert(date.toString());
7232 assert(cdate.toString());
7233 assert(idate.toString());
7234 }
7235
7236
7237 /++
7238 Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace
7239 is stripped from the given string.
7240
7241 Params:
7242 isoString = A string formatted in the ISO format for dates.
7243
7244 Throws:
7245 $(REF DateTimeException,std,datetime,date) if the given string is
7246 not in the ISO format or if the resulting $(LREF Date) would not be
7247 valid.
7248 +/
7249 static Date fromISOString(S)(in S isoString) @safe pure
7250 if (isSomeString!S)
7251 {
7252 import std.algorithm.searching : startsWith;
7253 import std.conv : to, text, ConvException;
7254 import std.exception : enforce;
7255 import std.string : strip;
7256
7257 auto str = isoString.strip;
7258
7259 enforce!DateTimeException(str.length >= 8, text("Invalid ISO String: ", isoString));
7260
7261 int day, month, year;
7262 auto yearStr = str[0 .. $ - 4];
7263
7264 try
7265 {
7266 // using conversion to uint plus cast because it checks for +/-
7267 // for us quickly while throwing ConvException
7268 day = cast(int) to!uint(str[$ - 2 .. $]);
7269 month = cast(int) to!uint(str[$ - 4 .. $ - 2]);
7270
7271 if (yearStr.length > 4)
7272 {
7273 enforce!DateTimeException(yearStr.startsWith('-', '+'),
7274 text("Invalid ISO String: ", isoString));
7275 year = to!int(yearStr);
7276 }
7277 else
7278 {
7279 year = cast(int) to!uint(yearStr);
7280 }
7281 }
catch(ConvException)7282 catch (ConvException)
7283 {
7284 throw new DateTimeException(text("Invalid ISO String: ", isoString));
7285 }
7286
7287 return Date(year, month, day);
7288 }
7289
7290 ///
7291 @safe unittest
7292 {
7293 assert(Date.fromISOString("20100704") == Date(2010, 7, 4));
7294 assert(Date.fromISOString("19981225") == Date(1998, 12, 25));
7295 assert(Date.fromISOString("00000105") == Date(0, 1, 5));
7296 assert(Date.fromISOString("-00040105") == Date(-4, 1, 5));
7297 assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4));
7298 }
7299
7300 @safe unittest
7301 {
7302 assertThrown!DateTimeException(Date.fromISOString(""));
7303 assertThrown!DateTimeException(Date.fromISOString("990704"));
7304 assertThrown!DateTimeException(Date.fromISOString("0100704"));
7305 assertThrown!DateTimeException(Date.fromISOString("2010070"));
7306 assertThrown!DateTimeException(Date.fromISOString("2010070 "));
7307 assertThrown!DateTimeException(Date.fromISOString("120100704"));
7308 assertThrown!DateTimeException(Date.fromISOString("-0100704"));
7309 assertThrown!DateTimeException(Date.fromISOString("+0100704"));
7310 assertThrown!DateTimeException(Date.fromISOString("2010070a"));
7311 assertThrown!DateTimeException(Date.fromISOString("20100a04"));
7312 assertThrown!DateTimeException(Date.fromISOString("2010a704"));
7313
7314 assertThrown!DateTimeException(Date.fromISOString("99-07-04"));
7315 assertThrown!DateTimeException(Date.fromISOString("010-07-04"));
7316 assertThrown!DateTimeException(Date.fromISOString("2010-07-0"));
7317 assertThrown!DateTimeException(Date.fromISOString("2010-07-0 "));
7318 assertThrown!DateTimeException(Date.fromISOString("12010-07-04"));
7319 assertThrown!DateTimeException(Date.fromISOString("-010-07-04"));
7320 assertThrown!DateTimeException(Date.fromISOString("+010-07-04"));
7321 assertThrown!DateTimeException(Date.fromISOString("2010-07-0a"));
7322 assertThrown!DateTimeException(Date.fromISOString("2010-0a-04"));
7323 assertThrown!DateTimeException(Date.fromISOString("2010-a7-04"));
7324 assertThrown!DateTimeException(Date.fromISOString("2010/07/04"));
7325 assertThrown!DateTimeException(Date.fromISOString("2010/7/04"));
7326 assertThrown!DateTimeException(Date.fromISOString("2010/7/4"));
7327 assertThrown!DateTimeException(Date.fromISOString("2010/07/4"));
7328 assertThrown!DateTimeException(Date.fromISOString("2010-7-04"));
7329 assertThrown!DateTimeException(Date.fromISOString("2010-7-4"));
7330 assertThrown!DateTimeException(Date.fromISOString("2010-07-4"));
7331
7332 assertThrown!DateTimeException(Date.fromISOString("99Jul04"));
7333 assertThrown!DateTimeException(Date.fromISOString("010Jul04"));
7334 assertThrown!DateTimeException(Date.fromISOString("2010Jul0"));
7335 assertThrown!DateTimeException(Date.fromISOString("2010Jul0 "));
7336 assertThrown!DateTimeException(Date.fromISOString("12010Jul04"));
7337 assertThrown!DateTimeException(Date.fromISOString("-010Jul04"));
7338 assertThrown!DateTimeException(Date.fromISOString("+010Jul04"));
7339 assertThrown!DateTimeException(Date.fromISOString("2010Jul0a"));
7340 assertThrown!DateTimeException(Date.fromISOString("2010Jua04"));
7341 assertThrown!DateTimeException(Date.fromISOString("2010aul04"));
7342
7343 assertThrown!DateTimeException(Date.fromISOString("99-Jul-04"));
7344 assertThrown!DateTimeException(Date.fromISOString("010-Jul-04"));
7345 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0"));
7346 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 "));
7347 assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04"));
7348 assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04"));
7349 assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04"));
7350 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a"));
7351 assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04"));
7352 assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04"));
7353 assertThrown!DateTimeException(Date.fromISOString("2010-aul-04"));
7354
7355 assertThrown!DateTimeException(Date.fromISOString("2010-07-04"));
7356 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04"));
7357
7358 assert(Date.fromISOString("19990706") == Date(1999, 7, 6));
7359 assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6));
7360 assert(Date.fromISOString("+019990706") == Date(1999, 7, 6));
7361 assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6));
7362 assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6));
7363 assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6));
7364 }
7365
7366 // bug# 17801
7367 @safe unittest
7368 {
7369 import std.conv : to;
7370 import std.meta : AliasSeq;
7371 foreach (C; AliasSeq!(char, wchar, dchar))
7372 {
7373 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7374 assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21));
7375 }
7376 }
7377
7378
7379 /++
7380 Creates a $(LREF Date) from a string with the format YYYY-MM-DD.
7381 Whitespace is stripped from the given string.
7382
7383 Params:
7384 isoExtString = A string formatted in the ISO Extended format for
7385 dates.
7386
7387 Throws:
7388 $(REF DateTimeException,std,datetime,date) if the given string is
7389 not in the ISO Extended format or if the resulting $(LREF Date)
7390 would not be valid.
7391 +/
7392 static Date fromISOExtString(S)(in S isoExtString) @safe pure
7393 if (isSomeString!(S))
7394 {
7395 import std.algorithm.searching : all, startsWith;
7396 import std.ascii : isDigit;
7397 import std.conv : to;
7398 import std.exception : enforce;
7399 import std.format : format;
7400 import std.string : strip;
7401
7402 auto dstr = to!dstring(strip(isoExtString));
7403
7404 enforce(dstr.length >= 10, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7405
7406 auto day = dstr[$-2 .. $];
7407 auto month = dstr[$-5 .. $-3];
7408 auto year = dstr[0 .. $-6];
7409
7410 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7411 enforce(dstr[$-6] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7412 enforce(all!isDigit(day),
7413 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7414 enforce(all!isDigit(month),
7415 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7416
7417 if (year.length > 4)
7418 {
7419 enforce(year.startsWith('-', '+'),
7420 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7421 enforce(all!isDigit(year[1..$]),
7422 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7423 }
7424 else
7425 enforce(all!isDigit(year),
7426 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
7427
7428 return Date(to!short(year), to!ubyte(month), to!ubyte(day));
7429 }
7430
7431 ///
7432 @safe unittest
7433 {
7434 assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4));
7435 assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25));
7436 assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5));
7437 assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5));
7438 assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4));
7439 }
7440
7441 @safe unittest
7442 {
7443 assertThrown!DateTimeException(Date.fromISOExtString(""));
7444 assertThrown!DateTimeException(Date.fromISOExtString("990704"));
7445 assertThrown!DateTimeException(Date.fromISOExtString("0100704"));
7446 assertThrown!DateTimeException(Date.fromISOExtString("2010070"));
7447 assertThrown!DateTimeException(Date.fromISOExtString("2010070 "));
7448 assertThrown!DateTimeException(Date.fromISOExtString("120100704"));
7449 assertThrown!DateTimeException(Date.fromISOExtString("-0100704"));
7450 assertThrown!DateTimeException(Date.fromISOExtString("+0100704"));
7451 assertThrown!DateTimeException(Date.fromISOExtString("2010070a"));
7452 assertThrown!DateTimeException(Date.fromISOExtString("20100a04"));
7453 assertThrown!DateTimeException(Date.fromISOExtString("2010a704"));
7454
7455 assertThrown!DateTimeException(Date.fromISOExtString("99-07-04"));
7456 assertThrown!DateTimeException(Date.fromISOExtString("010-07-04"));
7457 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0"));
7458 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 "));
7459 assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04"));
7460 assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04"));
7461 assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04"));
7462 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a"));
7463 assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04"));
7464 assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04"));
7465 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04"));
7466 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04"));
7467 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4"));
7468 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4"));
7469 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04"));
7470 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4"));
7471 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4"));
7472
7473 assertThrown!DateTimeException(Date.fromISOExtString("99Jul04"));
7474 assertThrown!DateTimeException(Date.fromISOExtString("010Jul04"));
7475 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0"));
7476 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 "));
7477 assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04"));
7478 assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04"));
7479 assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04"));
7480 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a"));
7481 assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04"));
7482 assertThrown!DateTimeException(Date.fromISOExtString("2010aul04"));
7483
7484 assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04"));
7485 assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04"));
7486 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0"));
7487 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 "));
7488 assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04"));
7489 assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04"));
7490 assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04"));
7491 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a"));
7492 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04"));
7493 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04"));
7494 assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04"));
7495
7496 assertThrown!DateTimeException(Date.fromISOExtString("20100704"));
7497 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04"));
7498
7499 assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6));
7500 assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6));
7501 assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6));
7502 assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6));
7503 assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6));
7504 assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6));
7505 }
7506
7507 // bug# 17801
7508 @safe unittest
7509 {
7510 import std.conv : to;
7511 import std.meta : AliasSeq;
7512 foreach (C; AliasSeq!(char, wchar, dchar))
7513 {
7514 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7515 assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21));
7516 }
7517 }
7518
7519
7520 /++
7521 Creates a $(LREF Date) from a string with the format YYYY-Mon-DD.
7522 Whitespace is stripped from the given string.
7523
7524 Params:
7525 simpleString = A string formatted in the way that toSimpleString
7526 formats dates.
7527
7528 Throws:
7529 $(REF DateTimeException,std,datetime,date) if the given string is
7530 not in the correct format or if the resulting $(LREF Date) would not
7531 be valid.
7532 +/
7533 static Date fromSimpleString(S)(in S simpleString) @safe pure
7534 if (isSomeString!(S))
7535 {
7536 import std.algorithm.searching : all, startsWith;
7537 import std.ascii : isDigit;
7538 import std.conv : to;
7539 import std.exception : enforce;
7540 import std.format : format;
7541 import std.string : strip;
7542
7543 auto dstr = to!dstring(strip(simpleString));
7544
7545 enforce(dstr.length >= 11, new DateTimeException(format("Invalid string format: %s", simpleString)));
7546
7547 auto day = dstr[$-2 .. $];
7548 auto month = monthFromString(to!string(dstr[$-6 .. $-3]));
7549 auto year = dstr[0 .. $-7];
7550
7551 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
7552 enforce(dstr[$-7] == '-', new DateTimeException(format("Invalid string format: %s", simpleString)));
7553 enforce(all!isDigit(day), new DateTimeException(format("Invalid string format: %s", simpleString)));
7554
7555 if (year.length > 4)
7556 {
7557 enforce(year.startsWith('-', '+'),
7558 new DateTimeException(format("Invalid string format: %s", simpleString)));
7559 enforce(all!isDigit(year[1..$]),
7560 new DateTimeException(format("Invalid string format: %s", simpleString)));
7561 }
7562 else
7563 enforce(all!isDigit(year),
7564 new DateTimeException(format("Invalid string format: %s", simpleString)));
7565
7566 return Date(to!short(year), month, to!ubyte(day));
7567 }
7568
7569 ///
7570 @safe unittest
7571 {
7572 assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4));
7573 assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25));
7574 assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5));
7575 assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5));
7576 assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4));
7577 }
7578
7579 @safe unittest
7580 {
7581 assertThrown!DateTimeException(Date.fromSimpleString(""));
7582 assertThrown!DateTimeException(Date.fromSimpleString("990704"));
7583 assertThrown!DateTimeException(Date.fromSimpleString("0100704"));
7584 assertThrown!DateTimeException(Date.fromSimpleString("2010070"));
7585 assertThrown!DateTimeException(Date.fromSimpleString("2010070 "));
7586 assertThrown!DateTimeException(Date.fromSimpleString("120100704"));
7587 assertThrown!DateTimeException(Date.fromSimpleString("-0100704"));
7588 assertThrown!DateTimeException(Date.fromSimpleString("+0100704"));
7589 assertThrown!DateTimeException(Date.fromSimpleString("2010070a"));
7590 assertThrown!DateTimeException(Date.fromSimpleString("20100a04"));
7591 assertThrown!DateTimeException(Date.fromSimpleString("2010a704"));
7592
7593 assertThrown!DateTimeException(Date.fromSimpleString("99-07-04"));
7594 assertThrown!DateTimeException(Date.fromSimpleString("010-07-04"));
7595 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0"));
7596 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 "));
7597 assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04"));
7598 assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04"));
7599 assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04"));
7600 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a"));
7601 assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04"));
7602 assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04"));
7603 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04"));
7604 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04"));
7605 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4"));
7606 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4"));
7607 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04"));
7608 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4"));
7609 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4"));
7610
7611 assertThrown!DateTimeException(Date.fromSimpleString("99Jul04"));
7612 assertThrown!DateTimeException(Date.fromSimpleString("010Jul04"));
7613 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0"));
7614 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 "));
7615 assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04"));
7616 assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04"));
7617 assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04"));
7618 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a"));
7619 assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04"));
7620 assertThrown!DateTimeException(Date.fromSimpleString("2010aul04"));
7621
7622 assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04"));
7623 assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04"));
7624 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0"));
7625 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 "));
7626 assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04"));
7627 assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04"));
7628 assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04"));
7629 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a"));
7630 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04"));
7631 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04"));
7632 assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04"));
7633
7634 assertThrown!DateTimeException(Date.fromSimpleString("20100704"));
7635 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04"));
7636
7637 assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6));
7638 assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6));
7639 assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6));
7640 assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6));
7641 assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6));
7642 assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6));
7643 }
7644
7645 // bug# 17801
7646 @safe unittest
7647 {
7648 import std.conv : to;
7649 import std.meta : AliasSeq;
7650 foreach (C; AliasSeq!(char, wchar, dchar))
7651 {
7652 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
7653 assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21));
7654 }
7655 }
7656
7657
7658 /++
7659 Returns the $(LREF Date) farthest in the past which is representable by
7660 $(LREF Date).
7661 +/
min()7662 @property static Date min() @safe pure nothrow @nogc
7663 {
7664 auto date = Date.init;
7665 date._year = short.min;
7666 date._month = Month.jan;
7667 date._day = 1;
7668
7669 return date;
7670 }
7671
7672 @safe unittest
7673 {
7674 assert(Date.min.year < 0);
7675 assert(Date.min < Date.max);
7676 }
7677
7678
7679 /++
7680 Returns the $(LREF Date) farthest in the future which is representable
7681 by $(LREF Date).
7682 +/
max()7683 @property static Date max() @safe pure nothrow @nogc
7684 {
7685 auto date = Date.init;
7686 date._year = short.max;
7687 date._month = Month.dec;
7688 date._day = 31;
7689
7690 return date;
7691 }
7692
7693 @safe unittest
7694 {
7695 assert(Date.max.year > 0);
7696 assert(Date.max > Date.min);
7697 }
7698
7699
7700 private:
7701
7702 /+
7703 Whether the given values form a valid date.
7704
7705 Params:
7706 year = The year to test.
7707 month = The month of the Gregorian Calendar to test.
7708 day = The day of the month to test.
7709 +/
_valid(int year,int month,int day)7710 static bool _valid(int year, int month, int day) @safe pure nothrow @nogc
7711 {
7712 if (!valid!"months"(month))
7713 return false;
7714 return valid!"days"(year, month, day);
7715 }
7716
7717
7718 package:
7719
7720 /+
7721 Adds the given number of days to this $(LREF Date). A negative number
7722 will subtract.
7723
7724 The month will be adjusted along with the day if the number of days
7725 added (or subtracted) would overflow (or underflow) the current month.
7726 The year will be adjusted along with the month if the increase (or
7727 decrease) to the month would cause it to overflow (or underflow) the
7728 current year.
7729
7730 $(D _addDays(numDays)) is effectively equivalent to
7731 $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days).
7732
7733 Params:
7734 days = The number of days to add to this Date.
7735 +/
7736 ref Date _addDays(long days) return @safe pure nothrow @nogc
7737 {
7738 dayOfGregorianCal = cast(int)(dayOfGregorianCal + days);
7739 return this;
7740 }
7741
7742 @safe unittest
7743 {
7744 // Test A.D.
7745 {
7746 auto date = Date(1999, 2, 28);
7747 date._addDays(1);
7748 assert(date == Date(1999, 3, 1));
7749 date._addDays(-1);
7750 assert(date == Date(1999, 2, 28));
7751 }
7752
7753 {
7754 auto date = Date(2000, 2, 28);
7755 date._addDays(1);
7756 assert(date == Date(2000, 2, 29));
7757 date._addDays(1);
7758 assert(date == Date(2000, 3, 1));
7759 date._addDays(-1);
7760 assert(date == Date(2000, 2, 29));
7761 }
7762
7763 {
7764 auto date = Date(1999, 6, 30);
7765 date._addDays(1);
7766 assert(date == Date(1999, 7, 1));
7767 date._addDays(-1);
7768 assert(date == Date(1999, 6, 30));
7769 }
7770
7771 {
7772 auto date = Date(1999, 7, 31);
7773 date._addDays(1);
7774 assert(date == Date(1999, 8, 1));
7775 date._addDays(-1);
7776 assert(date == Date(1999, 7, 31));
7777 }
7778
7779 {
7780 auto date = Date(1999, 1, 1);
7781 date._addDays(-1);
7782 assert(date == Date(1998, 12, 31));
7783 date._addDays(1);
7784 assert(date == Date(1999, 1, 1));
7785 }
7786
7787 {
7788 auto date = Date(1999, 7, 6);
7789 date._addDays(9);
7790 assert(date == Date(1999, 7, 15));
7791 date._addDays(-11);
7792 assert(date == Date(1999, 7, 4));
7793 date._addDays(30);
7794 assert(date == Date(1999, 8, 3));
7795 date._addDays(-3);
7796 assert(date == Date(1999, 7, 31));
7797 }
7798
7799 {
7800 auto date = Date(1999, 7, 6);
7801 date._addDays(365);
7802 assert(date == Date(2000, 7, 5));
7803 date._addDays(-365);
7804 assert(date == Date(1999, 7, 6));
7805 date._addDays(366);
7806 assert(date == Date(2000, 7, 6));
7807 date._addDays(730);
7808 assert(date == Date(2002, 7, 6));
7809 date._addDays(-1096);
7810 assert(date == Date(1999, 7, 6));
7811 }
7812
7813 // Test B.C.
7814 {
7815 auto date = Date(-1999, 2, 28);
7816 date._addDays(1);
7817 assert(date == Date(-1999, 3, 1));
7818 date._addDays(-1);
7819 assert(date == Date(-1999, 2, 28));
7820 }
7821
7822 {
7823 auto date = Date(-2000, 2, 28);
7824 date._addDays(1);
7825 assert(date == Date(-2000, 2, 29));
7826 date._addDays(1);
7827 assert(date == Date(-2000, 3, 1));
7828 date._addDays(-1);
7829 assert(date == Date(-2000, 2, 29));
7830 }
7831
7832 {
7833 auto date = Date(-1999, 6, 30);
7834 date._addDays(1);
7835 assert(date == Date(-1999, 7, 1));
7836 date._addDays(-1);
7837 assert(date == Date(-1999, 6, 30));
7838 }
7839
7840 {
7841 auto date = Date(-1999, 7, 31);
7842 date._addDays(1);
7843 assert(date == Date(-1999, 8, 1));
7844 date._addDays(-1);
7845 assert(date == Date(-1999, 7, 31));
7846 }
7847
7848 {
7849 auto date = Date(-1999, 1, 1);
7850 date._addDays(-1);
7851 assert(date == Date(-2000, 12, 31));
7852 date._addDays(1);
7853 assert(date == Date(-1999, 1, 1));
7854 }
7855
7856 {
7857 auto date = Date(-1999, 7, 6);
7858 date._addDays(9);
7859 assert(date == Date(-1999, 7, 15));
7860 date._addDays(-11);
7861 assert(date == Date(-1999, 7, 4));
7862 date._addDays(30);
7863 assert(date == Date(-1999, 8, 3));
7864 date._addDays(-3);
7865 }
7866
7867 {
7868 auto date = Date(-1999, 7, 6);
7869 date._addDays(365);
7870 assert(date == Date(-1998, 7, 6));
7871 date._addDays(-365);
7872 assert(date == Date(-1999, 7, 6));
7873 date._addDays(366);
7874 assert(date == Date(-1998, 7, 7));
7875 date._addDays(730);
7876 assert(date == Date(-1996, 7, 6));
7877 date._addDays(-1096);
7878 assert(date == Date(-1999, 7, 6));
7879 }
7880
7881 // Test Both
7882 {
7883 auto date = Date(1, 7, 6);
7884 date._addDays(-365);
7885 assert(date == Date(0, 7, 6));
7886 date._addDays(365);
7887 assert(date == Date(1, 7, 6));
7888 date._addDays(-731);
7889 assert(date == Date(-1, 7, 6));
7890 date._addDays(730);
7891 assert(date == Date(1, 7, 5));
7892 }
7893
7894 const cdate = Date(1999, 7, 6);
7895 immutable idate = Date(1999, 7, 6);
7896 static assert(!__traits(compiles, cdate._addDays(12)));
7897 static assert(!__traits(compiles, idate._addDays(12)));
7898 }
7899
7900
7901 @safe pure invariant()
7902 {
7903 import std.format : format;
7904 assert(valid!"months"(_month),
7905 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day));
7906 assert(valid!"days"(_year, _month, _day),
7907 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day));
7908 }
7909
7910 short _year = 1;
7911 Month _month = Month.jan;
7912 ubyte _day = 1;
7913 }
7914
7915
7916 /++
7917 Represents a time of day with hours, minutes, and seconds. It uses 24 hour
7918 time.
7919 +/
7920 struct TimeOfDay
7921 {
7922 public:
7923
7924 /++
7925 Params:
7926 hour = Hour of the day [0 - 24$(RPAREN).
7927 minute = Minute of the hour [0 - 60$(RPAREN).
7928 second = Second of the minute [0 - 60$(RPAREN).
7929
7930 Throws:
7931 $(REF DateTimeException,std,datetime,date) if the resulting
7932 $(LREF TimeOfDay) would be not be valid.
7933 +/
7934 this(int hour, int minute, int second = 0) @safe pure
7935 {
7936 enforceValid!"hours"(hour);
7937 enforceValid!"minutes"(minute);
7938 enforceValid!"seconds"(second);
7939
7940 _hour = cast(ubyte) hour;
7941 _minute = cast(ubyte) minute;
7942 _second = cast(ubyte) second;
7943 }
7944
7945 @safe unittest
7946 {
7947 assert(TimeOfDay(0, 0) == TimeOfDay.init);
7948
7949 {
7950 auto tod = TimeOfDay(0, 0);
7951 assert(tod._hour == 0);
7952 assert(tod._minute == 0);
7953 assert(tod._second == 0);
7954 }
7955
7956 {
7957 auto tod = TimeOfDay(12, 30, 33);
7958 assert(tod._hour == 12);
7959 assert(tod._minute == 30);
7960 assert(tod._second == 33);
7961 }
7962
7963 {
7964 auto tod = TimeOfDay(23, 59, 59);
7965 assert(tod._hour == 23);
7966 assert(tod._minute == 59);
7967 assert(tod._second == 59);
7968 }
7969
7970 assertThrown!DateTimeException(TimeOfDay(24, 0, 0));
7971 assertThrown!DateTimeException(TimeOfDay(0, 60, 0));
7972 assertThrown!DateTimeException(TimeOfDay(0, 0, 60));
7973 }
7974
7975
7976 /++
7977 Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay).
7978
7979 Returns:
7980 $(BOOKTABLE,
7981 $(TR $(TD this < rhs) $(TD < 0))
7982 $(TR $(TD this == rhs) $(TD 0))
7983 $(TR $(TD this > rhs) $(TD > 0))
7984 )
7985 +/
opCmpTimeOfDay7986 int opCmp(in TimeOfDay rhs) const @safe pure nothrow @nogc
7987 {
7988 if (_hour < rhs._hour)
7989 return -1;
7990 if (_hour > rhs._hour)
7991 return 1;
7992
7993 if (_minute < rhs._minute)
7994 return -1;
7995 if (_minute > rhs._minute)
7996 return 1;
7997
7998 if (_second < rhs._second)
7999 return -1;
8000 if (_second > rhs._second)
8001 return 1;
8002
8003 return 0;
8004 }
8005
8006 @safe unittest
8007 {
8008 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0);
8009
8010 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0);
8011 assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0);
8012 assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0);
8013 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
8014
8015 assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0);
8016 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0);
8017
8018 assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0);
8019 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0);
8020
8021 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
8022 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
8023 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0);
8024 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0);
8025 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0);
8026 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0);
8027
8028 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
8029 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0);
8030 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0);
8031 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0);
8032
8033 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0);
8034 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0);
8035
8036 const ctod = TimeOfDay(12, 30, 33);
8037 immutable itod = TimeOfDay(12, 30, 33);
8038 assert(ctod.opCmp(itod) == 0);
8039 assert(itod.opCmp(ctod) == 0);
8040 }
8041
8042
8043 /++
8044 Hours past midnight.
8045 +/
hourTimeOfDay8046 @property ubyte hour() const @safe pure nothrow @nogc
8047 {
8048 return _hour;
8049 }
8050
8051 @safe unittest
8052 {
8053 assert(TimeOfDay.init.hour == 0);
8054 assert(TimeOfDay(12, 0, 0).hour == 12);
8055
8056 const ctod = TimeOfDay(12, 0, 0);
8057 immutable itod = TimeOfDay(12, 0, 0);
8058 assert(ctod.hour == 12);
8059 assert(itod.hour == 12);
8060 }
8061
8062
8063 /++
8064 Hours past midnight.
8065
8066 Params:
8067 hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to.
8068
8069 Throws:
8070 $(REF DateTimeException,std,datetime,date) if the given hour would
8071 result in an invalid $(LREF TimeOfDay).
8072 +/
hourTimeOfDay8073 @property void hour(int hour) @safe pure
8074 {
8075 enforceValid!"hours"(hour);
8076 _hour = cast(ubyte) hour;
8077 }
8078
8079 @safe unittest
8080 {
8081 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}());
8082
8083 auto tod = TimeOfDay(0, 0, 0);
8084 tod.hour = 12;
8085 assert(tod == TimeOfDay(12, 0, 0));
8086
8087 const ctod = TimeOfDay(0, 0, 0);
8088 immutable itod = TimeOfDay(0, 0, 0);
8089 static assert(!__traits(compiles, ctod.hour = 12));
8090 static assert(!__traits(compiles, itod.hour = 12));
8091 }
8092
8093
8094 /++
8095 Minutes past the hour.
8096 +/
8097 @property ubyte minute() const @safe pure nothrow @nogc
8098 {
8099 return _minute;
8100 }
8101
8102 @safe unittest
8103 {
8104 assert(TimeOfDay.init.minute == 0);
8105 assert(TimeOfDay(0, 30, 0).minute == 30);
8106
8107 const ctod = TimeOfDay(0, 30, 0);
8108 immutable itod = TimeOfDay(0, 30, 0);
8109 assert(ctod.minute == 30);
8110 assert(itod.minute == 30);
8111 }
8112
8113
8114 /++
8115 Minutes past the hour.
8116
8117 Params:
8118 minute = The minute to set this $(LREF TimeOfDay)'s minute to.
8119
8120 Throws:
8121 $(REF DateTimeException,std,datetime,date) if the given minute
8122 would result in an invalid $(LREF TimeOfDay).
8123 +/
8124 @property void minute(int minute) @safe pure
8125 {
8126 enforceValid!"minutes"(minute);
8127 _minute = cast(ubyte) minute;
8128 }
8129
8130 @safe unittest
8131 {
8132 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}());
8133
8134 auto tod = TimeOfDay(0, 0, 0);
8135 tod.minute = 30;
8136 assert(tod == TimeOfDay(0, 30, 0));
8137
8138 const ctod = TimeOfDay(0, 0, 0);
8139 immutable itod = TimeOfDay(0, 0, 0);
8140 static assert(!__traits(compiles, ctod.minute = 30));
8141 static assert(!__traits(compiles, itod.minute = 30));
8142 }
8143
8144
8145 /++
8146 Seconds past the minute.
8147 +/
secondTimeOfDay8148 @property ubyte second() const @safe pure nothrow @nogc
8149 {
8150 return _second;
8151 }
8152
8153 @safe unittest
8154 {
8155 assert(TimeOfDay.init.second == 0);
8156 assert(TimeOfDay(0, 0, 33).second == 33);
8157
8158 const ctod = TimeOfDay(0, 0, 33);
8159 immutable itod = TimeOfDay(0, 0, 33);
8160 assert(ctod.second == 33);
8161 assert(itod.second == 33);
8162 }
8163
8164
8165 /++
8166 Seconds past the minute.
8167
8168 Params:
8169 second = The second to set this $(LREF TimeOfDay)'s second to.
8170
8171 Throws:
8172 $(REF DateTimeException,std,datetime,date) if the given second
8173 would result in an invalid $(LREF TimeOfDay).
8174 +/
secondTimeOfDay8175 @property void second(int second) @safe pure
8176 {
8177 enforceValid!"seconds"(second);
8178 _second = cast(ubyte) second;
8179 }
8180
8181 @safe unittest
8182 {
8183 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}());
8184
8185 auto tod = TimeOfDay(0, 0, 0);
8186 tod.second = 33;
8187 assert(tod == TimeOfDay(0, 0, 33));
8188
8189 const ctod = TimeOfDay(0, 0, 0);
8190 immutable itod = TimeOfDay(0, 0, 0);
8191 static assert(!__traits(compiles, ctod.second = 33));
8192 static assert(!__traits(compiles, itod.second = 33));
8193 }
8194
8195
8196 /++
8197 Adds the given number of units to this $(LREF TimeOfDay). A negative
8198 number will subtract.
8199
8200 The difference between rolling and adding is that rolling does not
8201 affect larger units. For instance, rolling a $(LREF TimeOfDay)
8202 one hours's worth of minutes gets the exact same
8203 $(LREF TimeOfDay).
8204
8205 Accepted units are $(D "hours"), $(D "minutes"), and $(D "seconds").
8206
8207 Params:
8208 units = The units to add.
8209 value = The number of $(D_PARAM units) to add to this
8210 $(LREF TimeOfDay).
8211 +/
8212 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
8213 if (units == "hours")
8214 {
8215 return this += dur!"hours"(value);
8216 }
8217
8218 ///
8219 @safe unittest
8220 {
8221 auto tod1 = TimeOfDay(7, 12, 0);
8222 tod1.roll!"hours"(1);
8223 assert(tod1 == TimeOfDay(8, 12, 0));
8224
8225 auto tod2 = TimeOfDay(7, 12, 0);
8226 tod2.roll!"hours"(-1);
8227 assert(tod2 == TimeOfDay(6, 12, 0));
8228
8229 auto tod3 = TimeOfDay(23, 59, 0);
8230 tod3.roll!"minutes"(1);
8231 assert(tod3 == TimeOfDay(23, 0, 0));
8232
8233 auto tod4 = TimeOfDay(0, 0, 0);
8234 tod4.roll!"minutes"(-1);
8235 assert(tod4 == TimeOfDay(0, 59, 0));
8236
8237 auto tod5 = TimeOfDay(23, 59, 59);
8238 tod5.roll!"seconds"(1);
8239 assert(tod5 == TimeOfDay(23, 59, 0));
8240
8241 auto tod6 = TimeOfDay(0, 0, 0);
8242 tod6.roll!"seconds"(-1);
8243 assert(tod6 == TimeOfDay(0, 0, 59));
8244 }
8245
8246 @safe unittest
8247 {
8248 auto tod = TimeOfDay(12, 27, 2);
8249 tod.roll!"hours"(22).roll!"hours"(-7);
8250 assert(tod == TimeOfDay(3, 27, 2));
8251
8252 const ctod = TimeOfDay(0, 0, 0);
8253 immutable itod = TimeOfDay(0, 0, 0);
8254 static assert(!__traits(compiles, ctod.roll!"hours"(53)));
8255 static assert(!__traits(compiles, itod.roll!"hours"(53)));
8256 }
8257
8258
8259 // Shares documentation with "hours" version.
8260 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
8261 if (units == "minutes" || units == "seconds")
8262 {
8263 import std.format : format;
8264
8265 enum memberVarStr = units[0 .. $ - 1];
8266 value %= 60;
8267 mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr));
8268
8269 if (value < 0)
8270 {
8271 if (newVal < 0)
8272 newVal += 60;
8273 }
8274 else if (newVal >= 60)
8275 newVal -= 60;
8276
8277 mixin(format("_%s = cast(ubyte) newVal;", memberVarStr));
8278 return this;
8279 }
8280
8281 // Test roll!"minutes"().
8282 @safe unittest
8283 {
8284 static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__)
8285 {
8286 orig.roll!"minutes"(minutes);
8287 assert(orig == expected);
8288 }
8289
8290 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
8291 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33));
8292 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33));
8293 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33));
8294 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33));
8295 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33));
8296 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33));
8297 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33));
8298 testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33));
8299 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33));
8300 testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33));
8301 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
8302 testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33));
8303 testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33));
8304 testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33));
8305
8306 testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33));
8307 testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33));
8308 testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33));
8309 testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33));
8310 testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33));
8311 testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33));
8312 testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33));
8313 testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33));
8314
8315 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33));
8316 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33));
8317 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33));
8318 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33));
8319 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33));
8320 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33));
8321 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33));
8322 testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33));
8323 testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33));
8324 testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33));
8325 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
8326 testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33));
8327 testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33));
8328 testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33));
8329
8330 testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33));
8331 testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33));
8332 testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33));
8333 testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33));
8334 testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33));
8335 testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33));
8336 testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33));
8337 testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33));
8338
8339 testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33));
8340 testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33));
8341 testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33));
8342
8343 testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33));
8344 testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33));
8345 testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33));
8346
8347 testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33));
8348 testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33));
8349 testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33));
8350
8351 testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33));
8352 testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33));
8353 testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33));
8354
8355 auto tod = TimeOfDay(12, 27, 2);
8356 tod.roll!"minutes"(97).roll!"minutes"(-102);
8357 assert(tod == TimeOfDay(12, 22, 2));
8358
8359 const ctod = TimeOfDay(0, 0, 0);
8360 immutable itod = TimeOfDay(0, 0, 0);
8361 static assert(!__traits(compiles, ctod.roll!"minutes"(7)));
8362 static assert(!__traits(compiles, itod.roll!"minutes"(7)));
8363 }
8364
8365 // Test roll!"seconds"().
8366 @safe unittest
8367 {
8368 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
8369 {
8370 orig.roll!"seconds"(seconds);
8371 assert(orig == expected);
8372 }
8373
8374 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
8375 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
8376 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
8377 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
8378 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
8379 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
8380 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
8381 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
8382 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
8383 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0));
8384 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3));
8385 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32));
8386 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33));
8387 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34));
8388
8389 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59));
8390 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0));
8391 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1));
8392 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0));
8393 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32));
8394 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33));
8395 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34));
8396 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33));
8397
8398 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
8399 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
8400 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
8401 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
8402 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
8403 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
8404 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
8405 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
8406 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59));
8407 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58));
8408 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34));
8409 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33));
8410 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32));
8411
8412 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
8413 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
8414 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59));
8415
8416 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
8417 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
8418 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59));
8419
8420 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
8421 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
8422 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59));
8423
8424 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0));
8425 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
8426 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
8427
8428 auto tod = TimeOfDay(12, 27, 2);
8429 tod.roll!"seconds"(105).roll!"seconds"(-77);
8430 assert(tod == TimeOfDay(12, 27, 30));
8431
8432 const ctod = TimeOfDay(0, 0, 0);
8433 immutable itod = TimeOfDay(0, 0, 0);
8434 static assert(!__traits(compiles, ctod.roll!"seconds"(7)));
8435 static assert(!__traits(compiles, itod.roll!"seconds"(7)));
8436 }
8437
8438
8439 /++
8440 Gives the result of adding or subtracting a $(REF Duration, core,time)
8441 from this $(LREF TimeOfDay).
8442
8443 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8444 are
8445
8446 $(BOOKTABLE,
8447 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8448 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8449 )
8450
8451 Params:
8452 duration = The $(REF Duration, core,time) to add to or subtract from
8453 this $(LREF TimeOfDay).
8454 +/
8455 TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
8456 if (op == "+" || op == "-")
8457 {
8458 TimeOfDay retval = this;
8459 immutable seconds = duration.total!"seconds";
8460 mixin("return retval._addSeconds(" ~ op ~ "seconds);");
8461 }
8462
8463 ///
8464 @safe unittest
8465 {
8466 import core.time : hours, minutes, seconds;
8467
8468 assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13));
8469 assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12));
8470 assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12));
8471 assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0));
8472
8473 assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11));
8474 assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12));
8475 assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12));
8476 assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59));
8477 }
8478
8479 @safe unittest
8480 {
8481 auto tod = TimeOfDay(12, 30, 33);
8482
8483 assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33));
8484 assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
8485 assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
8486 assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
8487 assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
8488 assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
8489
8490 assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
8491 assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
8492 assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
8493 assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
8494 assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
8495 assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26));
8496
8497 assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
8498 assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33));
8499 assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
8500 assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
8501 assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
8502 assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
8503
8504 assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
8505 assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
8506 assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
8507 assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
8508 assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
8509 assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26));
8510
8511 auto duration = dur!"hours"(11);
8512 const ctod = TimeOfDay(12, 30, 33);
8513 immutable itod = TimeOfDay(12, 30, 33);
8514 assert(tod + duration == TimeOfDay(23, 30, 33));
8515 assert(ctod + duration == TimeOfDay(23, 30, 33));
8516 assert(itod + duration == TimeOfDay(23, 30, 33));
8517
8518 assert(tod - duration == TimeOfDay(1, 30, 33));
8519 assert(ctod - duration == TimeOfDay(1, 30, 33));
8520 assert(itod - duration == TimeOfDay(1, 30, 33));
8521 }
8522
8523
8524 /++
8525 Gives the result of adding or subtracting a $(REF Duration, core,time)
8526 from this $(LREF TimeOfDay), as well as assigning the result to this
8527 $(LREF TimeOfDay).
8528
8529 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8530 are
8531
8532 $(BOOKTABLE,
8533 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8534 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay))
8535 )
8536
8537 Params:
8538 duration = The $(REF Duration, core,time) to add to or subtract from
8539 this $(LREF TimeOfDay).
8540 +/
8541 ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
8542 if (op == "+" || op == "-")
8543 {
8544 immutable seconds = duration.total!"seconds";
8545 mixin("return _addSeconds(" ~ op ~ "seconds);");
8546 }
8547
8548 @safe unittest
8549 {
8550 auto duration = dur!"hours"(12);
8551
8552 assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33));
8553 assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33));
8554 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33));
8555 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33));
8556 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40));
8557 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26));
8558
8559 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40));
8560 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26));
8561 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40));
8562 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26));
8563 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40));
8564 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26));
8565
8566 assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33));
8567 assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33));
8568 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33));
8569 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33));
8570 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40));
8571 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26));
8572
8573 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40));
8574 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26));
8575 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40));
8576 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26));
8577 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40));
8578 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26));
8579
8580 auto tod = TimeOfDay(19, 17, 22);
8581 (tod += dur!"seconds"(9)) += dur!"seconds"(-7292);
8582 assert(tod == TimeOfDay(17, 15, 59));
8583
8584 const ctod = TimeOfDay(12, 33, 30);
8585 immutable itod = TimeOfDay(12, 33, 30);
8586 static assert(!__traits(compiles, ctod += duration));
8587 static assert(!__traits(compiles, itod += duration));
8588 static assert(!__traits(compiles, ctod -= duration));
8589 static assert(!__traits(compiles, itod -= duration));
8590 }
8591
8592
8593 /++
8594 Gives the difference between two $(LREF TimeOfDay)s.
8595
8596 The legal types of arithmetic for $(LREF TimeOfDay) using this operator
8597 are
8598
8599 $(BOOKTABLE,
8600 $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration))
8601 )
8602
8603 Params:
8604 rhs = The $(LREF TimeOfDay) to subtract from this one.
8605 +/
8606 Duration opBinary(string op)(in TimeOfDay rhs) const @safe pure nothrow @nogc
8607 if (op == "-")
8608 {
8609 immutable lhsSec = _hour * 3600 + _minute * 60 + _second;
8610 immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second;
8611
8612 return dur!"seconds"(lhsSec - rhsSec);
8613 }
8614
8615 @safe unittest
8616 {
8617 auto tod = TimeOfDay(12, 30, 33);
8618
8619 assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061));
8620 assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061));
8621 assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200));
8622 assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200));
8623 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240));
8624 assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240));
8625 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1));
8626 assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1));
8627
8628 const ctod = TimeOfDay(12, 30, 33);
8629 immutable itod = TimeOfDay(12, 30, 33);
8630 assert(tod - tod == Duration.zero);
8631 assert(ctod - tod == Duration.zero);
8632 assert(itod - tod == Duration.zero);
8633
8634 assert(tod - ctod == Duration.zero);
8635 assert(ctod - ctod == Duration.zero);
8636 assert(itod - ctod == Duration.zero);
8637
8638 assert(tod - itod == Duration.zero);
8639 assert(ctod - itod == Duration.zero);
8640 assert(itod - itod == Duration.zero);
8641 }
8642
8643
8644 /++
8645 Converts this $(LREF TimeOfDay) to a string with the format HHMMSS.
8646 +/
toISOStringTimeOfDay8647 string toISOString() const @safe pure nothrow
8648 {
8649 import std.format : format;
8650 try
8651 return format("%02d%02d%02d", _hour, _minute, _second);
8652 catch (Exception e)
8653 assert(0, "format() threw.");
8654 }
8655
8656 ///
8657 @safe unittest
8658 {
8659 assert(TimeOfDay(0, 0, 0).toISOString() == "000000");
8660 assert(TimeOfDay(12, 30, 33).toISOString() == "123033");
8661 }
8662
8663 @safe unittest
8664 {
8665 auto tod = TimeOfDay(12, 30, 33);
8666 const ctod = TimeOfDay(12, 30, 33);
8667 immutable itod = TimeOfDay(12, 30, 33);
8668 assert(tod.toISOString() == "123033");
8669 assert(ctod.toISOString() == "123033");
8670 assert(itod.toISOString() == "123033");
8671 }
8672
8673
8674 /++
8675 Converts this $(LREF TimeOfDay) to a string with the format HH:MM:SS.
8676 +/
toISOExtStringTimeOfDay8677 string toISOExtString() const @safe pure nothrow
8678 {
8679 import std.format : format;
8680 try
8681 return format("%02d:%02d:%02d", _hour, _minute, _second);
8682 catch (Exception e)
8683 assert(0, "format() threw.");
8684 }
8685
8686 ///
8687 @safe unittest
8688 {
8689 assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00");
8690 assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33");
8691 }
8692
8693 @safe unittest
8694 {
8695 auto tod = TimeOfDay(12, 30, 33);
8696 const ctod = TimeOfDay(12, 30, 33);
8697 immutable itod = TimeOfDay(12, 30, 33);
8698 assert(tod.toISOExtString() == "12:30:33");
8699 assert(ctod.toISOExtString() == "12:30:33");
8700 assert(itod.toISOExtString() == "12:30:33");
8701 }
8702
8703
8704 /++
8705 Converts this TimeOfDay to a string.
8706
8707 This function exists to make it easy to convert a $(LREF TimeOfDay) to a
8708 string for code that does not care what the exact format is - just that
8709 it presents the information in a clear manner. It also makes it easy to
8710 simply convert a $(LREF TimeOfDay) to a string when using functions such
8711 as `to!string`, `format`, or `writeln` which use toString to convert
8712 user-defined types. So, it is unlikely that much code will call
8713 toString directly.
8714
8715 The format of the string is purposefully unspecified, and code that
8716 cares about the format of the string should use `toISOString`,
8717 `toISOExtString`, or some other custom formatting function that
8718 explicitly generates the format that the code needs. The reason is that
8719 the code is then clear about what format it's using, making it less
8720 error-prone to maintain the code and interact with other software that
8721 consumes the generated strings. It's for this same reason that
8722 $(LREF TimeOfDay) has no `fromString` function, whereas it does have
8723 `fromISOString` and `fromISOExtString`.
8724
8725 The format returned by toString may or may not change in the future.
8726 +/
toStringTimeOfDay8727 string toString() const @safe pure nothrow
8728 {
8729 return toISOExtString();
8730 }
8731
8732 @safe unittest
8733 {
8734 auto tod = TimeOfDay(12, 30, 33);
8735 const ctod = TimeOfDay(12, 30, 33);
8736 immutable itod = TimeOfDay(12, 30, 33);
8737 assert(tod.toString());
8738 assert(ctod.toString());
8739 assert(itod.toString());
8740 }
8741
8742
8743 /++
8744 Creates a $(LREF TimeOfDay) from a string with the format HHMMSS.
8745 Whitespace is stripped from the given string.
8746
8747 Params:
8748 isoString = A string formatted in the ISO format for times.
8749
8750 Throws:
8751 $(REF DateTimeException,std,datetime,date) if the given string is
8752 not in the ISO format or if the resulting $(LREF TimeOfDay) would
8753 not be valid.
8754 +/
8755 static TimeOfDay fromISOString(S)(in S isoString) @safe pure
8756 if (isSomeString!S)
8757 {
8758 import std.conv : to, text, ConvException;
8759 import std.exception : enforce;
8760 import std.string : strip;
8761
8762 int hours, minutes, seconds;
8763 auto str = strip(isoString);
8764
8765 enforce!DateTimeException(str.length == 6, text("Invalid ISO String: ", isoString));
8766
8767 try
8768 {
8769 // cast to int from uint is used because it checks for
8770 // non digits without extra loops
8771 hours = cast(int) to!uint(str[0 .. 2]);
8772 minutes = cast(int) to!uint(str[2 .. 4]);
8773 seconds = cast(int) to!uint(str[4 .. $]);
8774 }
catchTimeOfDay8775 catch (ConvException)
8776 {
8777 throw new DateTimeException(text("Invalid ISO String: ", isoString));
8778 }
8779
8780 return TimeOfDay(hours, minutes, seconds);
8781 }
8782
8783 ///
8784 @safe unittest
8785 {
8786 assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0));
8787 assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33));
8788 assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33));
8789 }
8790
8791 @safe unittest
8792 {
8793 assertThrown!DateTimeException(TimeOfDay.fromISOString(""));
8794 assertThrown!DateTimeException(TimeOfDay.fromISOString("0"));
8795 assertThrown!DateTimeException(TimeOfDay.fromISOString("00"));
8796 assertThrown!DateTimeException(TimeOfDay.fromISOString("000"));
8797 assertThrown!DateTimeException(TimeOfDay.fromISOString("0000"));
8798 assertThrown!DateTimeException(TimeOfDay.fromISOString("00000"));
8799 assertThrown!DateTimeException(TimeOfDay.fromISOString("13033"));
8800 assertThrown!DateTimeException(TimeOfDay.fromISOString("1277"));
8801 assertThrown!DateTimeException(TimeOfDay.fromISOString("12707"));
8802 assertThrown!DateTimeException(TimeOfDay.fromISOString("12070"));
8803 assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a"));
8804 assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3"));
8805 assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33"));
8806 assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033"));
8807 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033"));
8808 assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033"));
8809 assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330"));
8810 assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033"));
8811 assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033"));
8812 assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033"));
8813 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am"));
8814 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm"));
8815
8816 assertThrown!DateTimeException(TimeOfDay.fromISOString("0::"));
8817 assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:"));
8818 assertThrown!DateTimeException(TimeOfDay.fromISOString("::0"));
8819 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0"));
8820 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00"));
8821 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0"));
8822 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0"));
8823 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0"));
8824 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00"));
8825 assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33"));
8826 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7"));
8827 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07"));
8828 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0"));
8829 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a"));
8830 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3"));
8831 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33"));
8832 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33"));
8833 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33"));
8834 assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33"));
8835 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30"));
8836 assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30"));
8837 assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33"));
8838 assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33"));
8839 assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33"));
8840 assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33"));
8841 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am"));
8842 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm"));
8843
8844 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33"));
8845
8846 assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17));
8847 assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12));
8848 assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7));
8849 assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17));
8850 assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17));
8851 assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17));
8852 }
8853
8854 // bug# 17801
8855 @safe unittest
8856 {
8857 import std.conv : to;
8858 import std.meta : AliasSeq;
8859 foreach (C; AliasSeq!(char, wchar, dchar))
8860 {
8861 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8862 assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16));
8863 }
8864 }
8865
8866
8867 /++
8868 Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS.
8869 Whitespace is stripped from the given string.
8870
8871 Params:
8872 isoExtString = A string formatted in the ISO Extended format for
8873 times.
8874
8875 Throws:
8876 $(REF DateTimeException,std,datetime,date) if the given string is
8877 not in the ISO Extended format or if the resulting $(LREF TimeOfDay)
8878 would not be valid.
8879 +/
8880 static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure
8881 if (isSomeString!S)
8882 {
8883 import std.algorithm.searching : all;
8884 import std.ascii : isDigit;
8885 import std.conv : to;
8886 import std.exception : enforce;
8887 import std.format : format;
8888 import std.string : strip;
8889
8890 auto dstr = to!dstring(strip(isoExtString));
8891
8892 enforce(dstr.length == 8, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8893
8894 auto hours = dstr[0 .. 2];
8895 auto minutes = dstr[3 .. 5];
8896 auto seconds = dstr[6 .. $];
8897
8898 enforce(dstr[2] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8899 enforce(dstr[5] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8900 enforce(all!isDigit(hours),
8901 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8902 enforce(all!isDigit(minutes),
8903 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8904 enforce(all!isDigit(seconds),
8905 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)));
8906
8907 return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds));
8908 }
8909
8910 ///
8911 @safe unittest
8912 {
8913 assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0));
8914 assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33));
8915 assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33));
8916 }
8917
8918 @safe unittest
8919 {
8920 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(""));
8921 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0"));
8922 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00"));
8923 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000"));
8924 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000"));
8925 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000"));
8926 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033"));
8927 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277"));
8928 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707"));
8929 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070"));
8930 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a"));
8931 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3"));
8932 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33"));
8933 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033"));
8934 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033"));
8935 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033"));
8936 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330"));
8937 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033"));
8938 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033"));
8939 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033"));
8940 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am"));
8941 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm"));
8942
8943 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::"));
8944 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:"));
8945 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0"));
8946 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0"));
8947 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00"));
8948 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0"));
8949 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0"));
8950 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0"));
8951 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00"));
8952 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33"));
8953 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7"));
8954 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07"));
8955 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0"));
8956 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a"));
8957 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3"));
8958 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33"));
8959 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33"));
8960 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33"));
8961 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33"));
8962 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30"));
8963 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30"));
8964 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33"));
8965 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33"));
8966 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33"));
8967 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33"));
8968 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am"));
8969 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm"));
8970
8971 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033"));
8972
8973 assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17));
8974 assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12));
8975 assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7));
8976 assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17));
8977 assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17));
8978 assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17));
8979 }
8980
8981 // bug# 17801
8982 @safe unittest
8983 {
8984 import std.conv : to;
8985 import std.meta : AliasSeq;
8986 foreach (C; AliasSeq!(char, wchar, dchar))
8987 {
8988 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[]))
8989 assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16));
8990 }
8991 }
8992
8993
8994 /++
8995 Returns midnight.
8996 +/
minTimeOfDay8997 @property static TimeOfDay min() @safe pure nothrow @nogc
8998 {
8999 return TimeOfDay.init;
9000 }
9001
9002 @safe unittest
9003 {
9004 assert(TimeOfDay.min.hour == 0);
9005 assert(TimeOfDay.min.minute == 0);
9006 assert(TimeOfDay.min.second == 0);
9007 assert(TimeOfDay.min < TimeOfDay.max);
9008 }
9009
9010
9011 /++
9012 Returns one second short of midnight.
9013 +/
maxTimeOfDay9014 @property static TimeOfDay max() @safe pure nothrow @nogc
9015 {
9016 auto tod = TimeOfDay.init;
9017 tod._hour = maxHour;
9018 tod._minute = maxMinute;
9019 tod._second = maxSecond;
9020
9021 return tod;
9022 }
9023
9024 @safe unittest
9025 {
9026 assert(TimeOfDay.max.hour == 23);
9027 assert(TimeOfDay.max.minute == 59);
9028 assert(TimeOfDay.max.second == 59);
9029 assert(TimeOfDay.max > TimeOfDay.min);
9030 }
9031
9032
9033 private:
9034
9035 /+
9036 Add seconds to the time of day. Negative values will subtract. If the
9037 number of seconds overflows (or underflows), then the seconds will wrap,
9038 increasing (or decreasing) the number of minutes accordingly. If the
9039 number of minutes overflows (or underflows), then the minutes will wrap.
9040 If the number of minutes overflows(or underflows), then the hour will
9041 wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30).
9042
9043 Params:
9044 seconds = The number of seconds to add to this TimeOfDay.
9045 +/
9046 ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc
9047 {
9048 long hnsecs = convert!("seconds", "hnsecs")(seconds);
9049 hnsecs += convert!("hours", "hnsecs")(_hour);
9050 hnsecs += convert!("minutes", "hnsecs")(_minute);
9051 hnsecs += convert!("seconds", "hnsecs")(_second);
9052
9053 hnsecs %= convert!("days", "hnsecs")(1);
9054
9055 if (hnsecs < 0)
9056 hnsecs += convert!("days", "hnsecs")(1);
9057
9058 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs);
9059 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
9060 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs);
9061
9062 _hour = cast(ubyte) newHours;
9063 _minute = cast(ubyte) newMinutes;
9064 _second = cast(ubyte) newSeconds;
9065
9066 return this;
9067 }
9068
9069 @safe unittest
9070 {
9071 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__)
9072 {
9073 orig._addSeconds(seconds);
9074 assert(orig == expected);
9075 }
9076
9077 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33));
9078 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34));
9079 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35));
9080 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36));
9081 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37));
9082 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38));
9083 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43));
9084 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48));
9085 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59));
9086 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0));
9087 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3));
9088 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32));
9089 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33));
9090 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34));
9091
9092 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59));
9093 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0));
9094 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1));
9095 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0));
9096 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32));
9097 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33));
9098 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34));
9099 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33));
9100
9101 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32));
9102 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31));
9103 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30));
9104 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29));
9105 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28));
9106 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23));
9107 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18));
9108 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0));
9109 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59));
9110 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58));
9111 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34));
9112 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33));
9113 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32));
9114
9115 testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0));
9116 testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59));
9117 testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33));
9118 testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32));
9119 testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59));
9120 testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33));
9121
9122 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1));
9123 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0));
9124 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59));
9125
9126 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1));
9127 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0));
9128 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59));
9129
9130 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1));
9131 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0));
9132 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59));
9133
9134 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0));
9135 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59));
9136 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58));
9137
9138 const ctod = TimeOfDay(0, 0, 0);
9139 immutable itod = TimeOfDay(0, 0, 0);
9140 static assert(!__traits(compiles, ctod._addSeconds(7)));
9141 static assert(!__traits(compiles, itod._addSeconds(7)));
9142 }
9143
9144
9145 /+
9146 Whether the given values form a valid $(LREF TimeOfDay).
9147 +/
9148 static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc
9149 {
9150 return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second);
9151 }
9152
9153
9154 @safe pure invariant()
9155 {
9156 import std.format : format;
9157 assert(_valid(_hour, _minute, _second),
9158 format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second));
9159 }
9160
9161
9162 package:
9163
9164 ubyte _hour;
9165 ubyte _minute;
9166 ubyte _second;
9167
9168 enum ubyte maxHour = 24 - 1;
9169 enum ubyte maxMinute = 60 - 1;
9170 enum ubyte maxSecond = 60 - 1;
9171 }
9172
9173
9174 /++
9175 Returns whether the given value is valid for the given unit type when in a
9176 time point. Naturally, a duration is not held to a particular range, but
9177 the values in a time point are (e.g. a month must be in the range of
9178 1 - 12 inclusive).
9179
9180 Params:
9181 units = The units of time to validate.
9182 value = The number to validate.
9183 +/
valid(string units)9184 bool valid(string units)(int value) @safe pure nothrow @nogc
9185 if (units == "months" ||
9186 units == "hours" ||
9187 units == "minutes" ||
9188 units == "seconds")
9189 {
9190 static if (units == "months")
9191 return value >= Month.jan && value <= Month.dec;
9192 else static if (units == "hours")
9193 return value >= 0 && value <= 23;
9194 else static if (units == "minutes")
9195 return value >= 0 && value <= 59;
9196 else static if (units == "seconds")
9197 return value >= 0 && value <= 59;
9198 }
9199
9200 ///
9201 @safe unittest
9202 {
9203 assert(valid!"hours"(12));
9204 assert(!valid!"hours"(32));
9205 assert(valid!"months"(12));
9206 assert(!valid!"months"(13));
9207 }
9208
9209 /++
9210 Returns whether the given day is valid for the given year and month.
9211
9212 Params:
9213 units = The units of time to validate.
9214 year = The year of the day to validate.
9215 month = The month of the day to validate (January is 1).
9216 day = The day to validate.
9217 +/
9218 bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc
9219 if (units == "days")
9220 {
9221 return day > 0 && day <= maxDay(year, month);
9222 }
9223
9224 ///
9225 @safe pure nothrow @nogc unittest
9226 {
9227 assert(valid!"days"(2016, 2, 29));
9228 assert(!valid!"days"(2016, 2, 30));
9229 assert(valid!"days"(2017, 2, 20));
9230 assert(!valid!"days"(2017, 2, 29));
9231 }
9232
9233
9234 /++
9235 Params:
9236 units = The units of time to validate.
9237 value = The number to validate.
9238 file = The file that the $(LREF DateTimeException) will list if thrown.
9239 line = The line number that the $(LREF DateTimeException) will list if
9240 thrown.
9241
9242 Throws:
9243 $(LREF DateTimeException) if $(D valid!units(value)) is false.
9244 +/
9245 void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure
9246 if (units == "months" ||
9247 units == "hours" ||
9248 units == "minutes" ||
9249 units == "seconds")
9250 {
9251 import std.format : format;
9252
9253 static if (units == "months")
9254 {
9255 if (!valid!units(value))
9256 throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line);
9257 }
9258 else static if (units == "hours")
9259 {
9260 if (!valid!units(value))
9261 throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line);
9262 }
9263 else static if (units == "minutes")
9264 {
9265 if (!valid!units(value))
9266 throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line);
9267 }
9268 else static if (units == "seconds")
9269 {
9270 if (!valid!units(value))
9271 throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line);
9272 }
9273 }
9274
9275
9276 /++
9277 Params:
9278 units = The units of time to validate.
9279 year = The year of the day to validate.
9280 month = The month of the day to validate.
9281 day = The day to validate.
9282 file = The file that the $(LREF DateTimeException) will list if thrown.
9283 line = The line number that the $(LREF DateTimeException) will list if
9284 thrown.
9285
9286 Throws:
9287 $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false.
9288 +/
9289 void enforceValid(string units)
9290 (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure
9291 if (units == "days")
9292 {
9293 import std.format : format;
9294 if (!valid!"days"(year, month, day))
9295 throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line);
9296 }
9297
9298
9299 /++
9300 Returns the number of days from the current day of the week to the given
9301 day of the week. If they are the same, then the result is 0.
9302
9303 Params:
9304 currDoW = The current day of the week.
9305 dow = The day of the week to get the number of days to.
9306 +/
daysToDayOfWeek(DayOfWeek currDoW,DayOfWeek dow)9307 int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc
9308 {
9309 if (currDoW == dow)
9310 return 0;
9311 if (currDoW < dow)
9312 return dow - currDoW;
9313 return DayOfWeek.sat - currDoW + dow + 1;
9314 }
9315
9316 ///
9317 @safe pure nothrow @nogc unittest
9318 {
9319 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
9320 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
9321 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
9322 }
9323
9324 @safe unittest
9325 {
9326 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0);
9327 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1);
9328 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2);
9329 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3);
9330 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4);
9331 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5);
9332 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6);
9333
9334 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6);
9335 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0);
9336 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1);
9337 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2);
9338 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3);
9339 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4);
9340 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5);
9341
9342 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5);
9343 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6);
9344 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0);
9345 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1);
9346 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2);
9347 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3);
9348 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4);
9349
9350 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4);
9351 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5);
9352 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6);
9353 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0);
9354 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1);
9355 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2);
9356 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3);
9357
9358 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3);
9359 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4);
9360 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5);
9361 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6);
9362 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0);
9363 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1);
9364 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2);
9365
9366 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2);
9367 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3);
9368 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4);
9369 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5);
9370 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6);
9371 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0);
9372 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1);
9373
9374 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1);
9375 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2);
9376 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3);
9377 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4);
9378 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5);
9379 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6);
9380 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0);
9381 }
9382
9383
9384 /++
9385 Returns the number of months from the current months of the year to the
9386 given month of the year. If they are the same, then the result is 0.
9387
9388 Params:
9389 currMonth = The current month of the year.
9390 month = The month of the year to get the number of months to.
9391 +/
monthsToMonth(int currMonth,int month)9392 int monthsToMonth(int currMonth, int month) @safe pure
9393 {
9394 enforceValid!"months"(currMonth);
9395 enforceValid!"months"(month);
9396
9397 if (currMonth == month)
9398 return 0;
9399 if (currMonth < month)
9400 return month - currMonth;
9401 return Month.dec - currMonth + month;
9402 }
9403
9404 ///
9405 @safe pure unittest
9406 {
9407 assert(monthsToMonth(Month.jan, Month.jan) == 0);
9408 assert(monthsToMonth(Month.jan, Month.dec) == 11);
9409 assert(monthsToMonth(Month.jul, Month.oct) == 3);
9410 }
9411
9412 @safe unittest
9413 {
9414 assert(monthsToMonth(Month.jan, Month.jan) == 0);
9415 assert(monthsToMonth(Month.jan, Month.feb) == 1);
9416 assert(monthsToMonth(Month.jan, Month.mar) == 2);
9417 assert(monthsToMonth(Month.jan, Month.apr) == 3);
9418 assert(monthsToMonth(Month.jan, Month.may) == 4);
9419 assert(monthsToMonth(Month.jan, Month.jun) == 5);
9420 assert(monthsToMonth(Month.jan, Month.jul) == 6);
9421 assert(monthsToMonth(Month.jan, Month.aug) == 7);
9422 assert(monthsToMonth(Month.jan, Month.sep) == 8);
9423 assert(monthsToMonth(Month.jan, Month.oct) == 9);
9424 assert(monthsToMonth(Month.jan, Month.nov) == 10);
9425 assert(monthsToMonth(Month.jan, Month.dec) == 11);
9426
9427 assert(monthsToMonth(Month.may, Month.jan) == 8);
9428 assert(monthsToMonth(Month.may, Month.feb) == 9);
9429 assert(monthsToMonth(Month.may, Month.mar) == 10);
9430 assert(monthsToMonth(Month.may, Month.apr) == 11);
9431 assert(monthsToMonth(Month.may, Month.may) == 0);
9432 assert(monthsToMonth(Month.may, Month.jun) == 1);
9433 assert(monthsToMonth(Month.may, Month.jul) == 2);
9434 assert(monthsToMonth(Month.may, Month.aug) == 3);
9435 assert(monthsToMonth(Month.may, Month.sep) == 4);
9436 assert(monthsToMonth(Month.may, Month.oct) == 5);
9437 assert(monthsToMonth(Month.may, Month.nov) == 6);
9438 assert(monthsToMonth(Month.may, Month.dec) == 7);
9439
9440 assert(monthsToMonth(Month.oct, Month.jan) == 3);
9441 assert(monthsToMonth(Month.oct, Month.feb) == 4);
9442 assert(monthsToMonth(Month.oct, Month.mar) == 5);
9443 assert(monthsToMonth(Month.oct, Month.apr) == 6);
9444 assert(monthsToMonth(Month.oct, Month.may) == 7);
9445 assert(monthsToMonth(Month.oct, Month.jun) == 8);
9446 assert(monthsToMonth(Month.oct, Month.jul) == 9);
9447 assert(monthsToMonth(Month.oct, Month.aug) == 10);
9448 assert(monthsToMonth(Month.oct, Month.sep) == 11);
9449 assert(monthsToMonth(Month.oct, Month.oct) == 0);
9450 assert(monthsToMonth(Month.oct, Month.nov) == 1);
9451 assert(monthsToMonth(Month.oct, Month.dec) == 2);
9452
9453 assert(monthsToMonth(Month.dec, Month.jan) == 1);
9454 assert(monthsToMonth(Month.dec, Month.feb) == 2);
9455 assert(monthsToMonth(Month.dec, Month.mar) == 3);
9456 assert(monthsToMonth(Month.dec, Month.apr) == 4);
9457 assert(monthsToMonth(Month.dec, Month.may) == 5);
9458 assert(monthsToMonth(Month.dec, Month.jun) == 6);
9459 assert(monthsToMonth(Month.dec, Month.jul) == 7);
9460 assert(monthsToMonth(Month.dec, Month.aug) == 8);
9461 assert(monthsToMonth(Month.dec, Month.sep) == 9);
9462 assert(monthsToMonth(Month.dec, Month.oct) == 10);
9463 assert(monthsToMonth(Month.dec, Month.nov) == 11);
9464 assert(monthsToMonth(Month.dec, Month.dec) == 0);
9465 }
9466
9467
9468 /++
9469 Whether the given Gregorian Year is a leap year.
9470
9471 Params:
9472 year = The year to to be tested.
9473 +/
yearIsLeapYear(int year)9474 bool yearIsLeapYear(int year) @safe pure nothrow @nogc
9475 {
9476 if (year % 400 == 0)
9477 return true;
9478 if (year % 100 == 0)
9479 return false;
9480 return year % 4 == 0;
9481 }
9482
9483 ///
9484 @safe unittest
9485 {
foreach(year;[1,2,100,2001,2002,2003,2005,2006,2007,2009,2010])9486 foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010])
9487 {
9488 assert(!yearIsLeapYear(year));
9489 assert(!yearIsLeapYear(-year));
9490 }
9491
foreach(year;[0,4,8,400,800,1600,1996,2000,2004,2008,2012])9492 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
9493 {
9494 assert(yearIsLeapYear(year));
9495 assert(yearIsLeapYear(-year));
9496 }
9497 }
9498
9499 @safe unittest
9500 {
9501 import std.format : format;
foreach(year;[1,2,3,5,6,7,100,200,300,500,600,700,1998,1999,2001,2002,2003,2005,2006,2007,2009,2010,2011])9502 foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999,
9503 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011])
9504 {
9505 assert(!yearIsLeapYear(year), format("year: %s.", year));
9506 assert(!yearIsLeapYear(-year), format("year: %s.", year));
9507 }
9508
foreach(year;[0,4,8,400,800,1600,1996,2000,2004,2008,2012])9509 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012])
9510 {
9511 assert(yearIsLeapYear(year), format("year: %s.", year));
9512 assert(yearIsLeapYear(-year), format("year: %s.", year));
9513 }
9514 }
9515
9516
9517 /++
9518 Whether the given type defines all of the necessary functions for it to
9519 function as a time point.
9520
9521 1. $(D T) must define a static property named $(D min) which is the smallest
9522 value of $(D T) as $(D Unqual!T).
9523
9524 2. $(D T) must define a static property named $(D max) which is the largest
9525 value of $(D T) as $(D Unqual!T).
9526
9527 3. $(D T) must define an $(D opBinary) for addition and subtraction that
9528 accepts $(REF Duration, core,time) and returns $(D Unqual!T).
9529
9530 4. $(D T) must define an $(D opOpAssign) for addition and subtraction that
9531 accepts $(REF Duration, core,time) and returns $(D ref Unqual!T).
9532
9533 5. $(D T) must define a $(D opBinary) for subtraction which accepts $(D T)
9534 and returns returns $(REF Duration, core,time).
9535 +/
isTimePoint(T)9536 template isTimePoint(T)
9537 {
9538 import core.time : Duration;
9539 import std.traits : FunctionAttribute, functionAttributes, Unqual;
9540
9541 enum isTimePoint = hasMin &&
9542 hasMax &&
9543 hasOverloadedOpBinaryWithDuration &&
9544 hasOverloadedOpAssignWithDuration &&
9545 hasOverloadedOpBinaryWithSelf &&
9546 !is(U == Duration);
9547
9548 private:
9549
9550 alias U = Unqual!T;
9551
9552 enum hasMin = __traits(hasMember, T, "min") &&
9553 is(typeof(T.min) == U) &&
9554 is(typeof({static assert(__traits(isStaticFunction, T.min));}));
9555
9556 enum hasMax = __traits(hasMember, T, "max") &&
9557 is(typeof(T.max) == U) &&
9558 is(typeof({static assert(__traits(isStaticFunction, T.max));}));
9559
9560 enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) &&
9561 is(typeof(T.init - Duration.init) == U);
9562
9563 enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) &&
9564 is(typeof(U.init -= Duration.init) == U) &&
9565 is(typeof(
9566 {
9567 alias add = U.opOpAssign!"+";
9568 alias sub = U.opOpAssign!"-";
9569 alias FA = FunctionAttribute;
9570 static assert((functionAttributes!add & FA.ref_) != 0);
9571 static assert((functionAttributes!sub & FA.ref_) != 0);
9572 }));
9573
9574 enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration);
9575 }
9576
9577 ///
9578 @safe unittest
9579 {
9580 import core.time : Duration;
9581 import std.datetime.interval : Interval;
9582 import std.datetime.systime : SysTime;
9583
9584 static assert(isTimePoint!Date);
9585 static assert(isTimePoint!DateTime);
9586 static assert(isTimePoint!SysTime);
9587 static assert(isTimePoint!TimeOfDay);
9588
9589 static assert(!isTimePoint!int);
9590 static assert(!isTimePoint!Duration);
9591 static assert(!isTimePoint!(Interval!SysTime));
9592 }
9593
9594 @safe unittest
9595 {
9596 import core.time;
9597 import std.datetime.interval;
9598 import std.datetime.systime;
9599 import std.meta : AliasSeq;
9600
9601 foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay))
9602 {
9603 static assert(isTimePoint!(const TP), TP.stringof);
9604 static assert(isTimePoint!(immutable TP), TP.stringof);
9605 }
9606
9607 foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date))
9608 static assert(!isTimePoint!T, T.stringof);
9609 }
9610
9611
9612 /++
9613 Whether all of the given strings are valid units of time.
9614
9615 $(D "nsecs") is not considered a valid unit of time. Nothing in std.datetime
9616 can handle precision greater than hnsecs, and the few functions in core.time
9617 which deal with "nsecs" deal with it explicitly.
9618 +/
validTimeUnits(string[]units...)9619 bool validTimeUnits(string[] units...) @safe pure nothrow @nogc
9620 {
9621 import std.algorithm.searching : canFind;
9622 foreach (str; units)
9623 {
9624 if (!canFind(timeStrings[], str))
9625 return false;
9626 }
9627 return true;
9628 }
9629
9630 ///
9631 @safe @nogc nothrow unittest
9632 {
9633 assert(validTimeUnits("msecs", "seconds", "minutes"));
9634 assert(validTimeUnits("days", "weeks", "months"));
9635 assert(!validTimeUnits("ms", "seconds", "minutes"));
9636 }
9637
9638
9639 /++
9640 Compares two time unit strings. $(D "years") are the largest units and
9641 $(D "hnsecs") are the smallest.
9642
9643 Returns:
9644 $(BOOKTABLE,
9645 $(TR $(TD this < rhs) $(TD < 0))
9646 $(TR $(TD this == rhs) $(TD 0))
9647 $(TR $(TD this > rhs) $(TD > 0))
9648 )
9649
9650 Throws:
9651 $(LREF DateTimeException) if either of the given strings is not a valid
9652 time unit string.
9653 +/
cmpTimeUnits(string lhs,string rhs)9654 int cmpTimeUnits(string lhs, string rhs) @safe pure
9655 {
9656 import std.algorithm.searching : countUntil;
9657 import std.exception : enforce;
9658 import std.format : format;
9659
9660 auto tstrings = timeStrings;
9661 immutable indexOfLHS = countUntil(tstrings, lhs);
9662 immutable indexOfRHS = countUntil(tstrings, rhs);
9663
9664 enforce(indexOfLHS != -1, format("%s is not a valid TimeString", lhs));
9665 enforce(indexOfRHS != -1, format("%s is not a valid TimeString", rhs));
9666
9667 if (indexOfLHS < indexOfRHS)
9668 return -1;
9669 if (indexOfLHS > indexOfRHS)
9670 return 1;
9671
9672 return 0;
9673 }
9674
9675 ///
9676 @safe pure unittest
9677 {
9678 assert(cmpTimeUnits("hours", "hours") == 0);
9679 assert(cmpTimeUnits("hours", "weeks") < 0);
9680 assert(cmpTimeUnits("months", "seconds") > 0);
9681 }
9682
9683 @safe unittest
9684 {
foreach(i,outerUnits;timeStrings)9685 foreach (i, outerUnits; timeStrings)
9686 {
9687 assert(cmpTimeUnits(outerUnits, outerUnits) == 0);
9688
9689 // For some reason, $ won't compile.
9690 foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length])
9691 assert(cmpTimeUnits(outerUnits, innerUnits) == -1);
9692 }
9693
foreach(i,outerUnits;timeStrings)9694 foreach (i, outerUnits; timeStrings)
9695 {
9696 foreach (innerUnits; timeStrings[0 .. i])
9697 assert(cmpTimeUnits(outerUnits, innerUnits) == 1);
9698 }
9699 }
9700
9701
9702 /++
9703 Compares two time unit strings at compile time. $(D "years") are the largest
9704 units and $(D "hnsecs") are the smallest.
9705
9706 This template is used instead of $(D cmpTimeUnits) because exceptions
9707 can't be thrown at compile time and $(D cmpTimeUnits) must enforce that
9708 the strings it's given are valid time unit strings. This template uses a
9709 template constraint instead.
9710
9711 Returns:
9712 $(BOOKTABLE,
9713 $(TR $(TD this < rhs) $(TD < 0))
9714 $(TR $(TD this == rhs) $(TD 0))
9715 $(TR $(TD this > rhs) $(TD > 0))
9716 )
9717 +/
9718 template CmpTimeUnits(string lhs, string rhs)
9719 if (validTimeUnits(lhs, rhs))
9720 {
9721 enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs);
9722 }
9723
9724
9725 // Helper function for CmpTimeUnits.
cmpTimeUnitsCTFE(string lhs,string rhs)9726 private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc
9727 {
9728 import std.algorithm.searching : countUntil;
9729 auto tstrings = timeStrings;
9730 immutable indexOfLHS = countUntil(tstrings, lhs);
9731 immutable indexOfRHS = countUntil(tstrings, rhs);
9732
9733 if (indexOfLHS < indexOfRHS)
9734 return -1;
9735 if (indexOfLHS > indexOfRHS)
9736 return 1;
9737
9738 return 0;
9739 }
9740
9741 @safe unittest
9742 {
9743 import std.format : format;
9744 import std.meta : AliasSeq;
9745
genTest(size_t index)9746 static string genTest(size_t index)
9747 {
9748 auto currUnits = timeStrings[index];
9749 auto test = format(`assert(CmpTimeUnits!("%s", "%s") == 0);`, currUnits, currUnits);
9750
9751 foreach (units; timeStrings[index + 1 .. $])
9752 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == -1);`, currUnits, units);
9753
9754 foreach (units; timeStrings[0 .. index])
9755 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == 1);`, currUnits, units);
9756
9757 return test;
9758 }
9759
9760 static assert(timeStrings.length == 10);
9761 foreach (n; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
9762 mixin(genTest(n));
9763 }
9764
9765
9766 package:
9767
9768
9769 /+
9770 Array of the short (three letter) names of each month.
9771 +/
9772 immutable string[12] _monthNames = ["Jan",
9773 "Feb",
9774 "Mar",
9775 "Apr",
9776 "May",
9777 "Jun",
9778 "Jul",
9779 "Aug",
9780 "Sep",
9781 "Oct",
9782 "Nov",
9783 "Dec"];
9784
9785 /+
9786 The maximum valid Day in the given month in the given year.
9787
9788 Params:
9789 year = The year to get the day for.
9790 month = The month of the Gregorian Calendar to get the day for.
9791 +/
maxDay(int year,int month)9792 ubyte maxDay(int year, int month) @safe pure nothrow @nogc
9793 in
9794 {
9795 assert(valid!"months"(month));
9796 }
9797 body
9798 {
9799 switch (month)
9800 {
9801 case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec:
9802 return 31;
9803 case Month.feb:
9804 return yearIsLeapYear(year) ? 29 : 28;
9805 case Month.apr, Month.jun, Month.sep, Month.nov:
9806 return 30;
9807 default:
9808 assert(0, "Invalid month.");
9809 }
9810 }
9811
9812 @safe unittest
9813 {
9814 // Test A.D.
9815 assert(maxDay(1999, 1) == 31);
9816 assert(maxDay(1999, 2) == 28);
9817 assert(maxDay(1999, 3) == 31);
9818 assert(maxDay(1999, 4) == 30);
9819 assert(maxDay(1999, 5) == 31);
9820 assert(maxDay(1999, 6) == 30);
9821 assert(maxDay(1999, 7) == 31);
9822 assert(maxDay(1999, 8) == 31);
9823 assert(maxDay(1999, 9) == 30);
9824 assert(maxDay(1999, 10) == 31);
9825 assert(maxDay(1999, 11) == 30);
9826 assert(maxDay(1999, 12) == 31);
9827
9828 assert(maxDay(2000, 1) == 31);
9829 assert(maxDay(2000, 2) == 29);
9830 assert(maxDay(2000, 3) == 31);
9831 assert(maxDay(2000, 4) == 30);
9832 assert(maxDay(2000, 5) == 31);
9833 assert(maxDay(2000, 6) == 30);
9834 assert(maxDay(2000, 7) == 31);
9835 assert(maxDay(2000, 8) == 31);
9836 assert(maxDay(2000, 9) == 30);
9837 assert(maxDay(2000, 10) == 31);
9838 assert(maxDay(2000, 11) == 30);
9839 assert(maxDay(2000, 12) == 31);
9840
9841 // Test B.C.
9842 assert(maxDay(-1999, 1) == 31);
9843 assert(maxDay(-1999, 2) == 28);
9844 assert(maxDay(-1999, 3) == 31);
9845 assert(maxDay(-1999, 4) == 30);
9846 assert(maxDay(-1999, 5) == 31);
9847 assert(maxDay(-1999, 6) == 30);
9848 assert(maxDay(-1999, 7) == 31);
9849 assert(maxDay(-1999, 8) == 31);
9850 assert(maxDay(-1999, 9) == 30);
9851 assert(maxDay(-1999, 10) == 31);
9852 assert(maxDay(-1999, 11) == 30);
9853 assert(maxDay(-1999, 12) == 31);
9854
9855 assert(maxDay(-2000, 1) == 31);
9856 assert(maxDay(-2000, 2) == 29);
9857 assert(maxDay(-2000, 3) == 31);
9858 assert(maxDay(-2000, 4) == 30);
9859 assert(maxDay(-2000, 5) == 31);
9860 assert(maxDay(-2000, 6) == 30);
9861 assert(maxDay(-2000, 7) == 31);
9862 assert(maxDay(-2000, 8) == 31);
9863 assert(maxDay(-2000, 9) == 30);
9864 assert(maxDay(-2000, 10) == 31);
9865 assert(maxDay(-2000, 11) == 30);
9866 assert(maxDay(-2000, 12) == 31);
9867 }
9868
9869 /+
9870 Splits out a particular unit from hnsecs and gives the value for that
9871 unit and the remaining hnsecs. It really shouldn't be used unless unless
9872 all units larger than the given units have already been split out.
9873
9874 Params:
9875 units = The units to split out.
9876 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left
9877 after splitting out the given units.
9878
9879 Returns:
9880 The number of the given units from converting hnsecs to those units.
9881 +/
9882 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc
9883 if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0)
9884 {
9885 import core.time : convert;
9886 immutable value = convert!("hnsecs", units)(hnsecs);
9887 hnsecs -= convert!(units, "hnsecs")(value);
9888 return value;
9889 }
9890
9891 @safe unittest
9892 {
9893 auto hnsecs = 2595000000007L;
9894 immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
9895 assert(days == 3);
9896 assert(hnsecs == 3000000007);
9897
9898 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs);
9899 assert(minutes == 5);
9900 assert(hnsecs == 7);
9901 }
9902
9903
9904 /+
9905 Returns the day of the week for the given day of the Gregorian Calendar.
9906
9907 Params:
9908 day = The day of the Gregorian Calendar for which to get the day of
9909 the week.
9910 +/
getDayOfWeek(int day)9911 DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc
9912 {
9913 // January 1st, 1 A.D. was a Monday
9914 if (day >= 0)
9915 return cast(DayOfWeek)(day % 7);
9916 else
9917 {
9918 immutable dow = cast(DayOfWeek)((day % 7) + 7);
9919
9920 if (dow == 7)
9921 return DayOfWeek.sun;
9922 else
9923 return dow;
9924 }
9925 }
9926
9927 @safe unittest
9928 {
9929 import std.datetime.systime : SysTime;
9930
9931 // Test A.D.
9932 assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon);
9933 assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue);
9934 assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed);
9935 assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu);
9936 assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri);
9937 assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat);
9938 assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun);
9939 assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon);
9940 assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue);
9941 assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue);
9942 assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed);
9943 assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu);
9944 assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
9945 assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat);
9946 assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun);
9947 assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon);
9948 assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue);
9949 assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed);
9950 assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu);
9951 assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri);
9952 assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat);
9953 assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun);
9954
9955 // Test B.C.
9956 assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun);
9957 assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat);
9958 assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri);
9959 assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu);
9960 assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed);
9961 assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue);
9962 assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon);
9963 assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun);
9964 assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat);
9965 }
9966
9967
9968 private:
9969
9970 enum daysInYear = 365; // The number of days in a non-leap year.
9971 enum daysInLeapYear = 366; // The numbef or days in a leap year.
9972 enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years.
9973 enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years.
9974 enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years.
9975
9976 /+
9977 Array of integers representing the last days of each month in a year.
9978 +/
9979 immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
9980
9981 /+
9982 Array of integers representing the last days of each month in a leap year.
9983 +/
9984 immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];
9985
9986
9987 /+
9988 Returns the string representation of the given month.
9989 +/
9990 string monthToString(Month month) @safe pure
9991 {
9992 import std.format : format;
9993 assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month));
9994 return _monthNames[month - Month.jan];
9995 }
9996
9997 @safe unittest
9998 {
9999 assert(monthToString(Month.jan) == "Jan");
10000 assert(monthToString(Month.feb) == "Feb");
10001 assert(monthToString(Month.mar) == "Mar");
10002 assert(monthToString(Month.apr) == "Apr");
10003 assert(monthToString(Month.may) == "May");
10004 assert(monthToString(Month.jun) == "Jun");
10005 assert(monthToString(Month.jul) == "Jul");
10006 assert(monthToString(Month.aug) == "Aug");
10007 assert(monthToString(Month.sep) == "Sep");
10008 assert(monthToString(Month.oct) == "Oct");
10009 assert(monthToString(Month.nov) == "Nov");
10010 assert(monthToString(Month.dec) == "Dec");
10011 }
10012
10013
10014 /+
10015 Returns the Month corresponding to the given string.
10016
10017 Params:
10018 monthStr = The string representation of the month to get the Month for.
10019
10020 Throws:
10021 $(REF DateTimeException,std,datetime,date) if the given month is not a
10022 valid month string.
10023 +/
10024 Month monthFromString(string monthStr) @safe pure
10025 {
10026 import std.format : format;
10027 switch (monthStr)
10028 {
10029 case "Jan":
10030 return Month.jan;
10031 case "Feb":
10032 return Month.feb;
10033 case "Mar":
10034 return Month.mar;
10035 case "Apr":
10036 return Month.apr;
10037 case "May":
10038 return Month.may;
10039 case "Jun":
10040 return Month.jun;
10041 case "Jul":
10042 return Month.jul;
10043 case "Aug":
10044 return Month.aug;
10045 case "Sep":
10046 return Month.sep;
10047 case "Oct":
10048 return Month.oct;
10049 case "Nov":
10050 return Month.nov;
10051 case "Dec":
10052 return Month.dec;
10053 default:
10054 throw new DateTimeException(format("Invalid month %s", monthStr));
10055 }
10056 }
10057
10058 @safe unittest
10059 {
10060 import std.stdio : writeln;
10061 import std.traits : EnumMembers;
10062 foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY",
10063 "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"])
10064 {
10065 scope(failure) writeln(badStr);
10066 assertThrown!DateTimeException(monthFromString(badStr));
10067 }
10068
10069 foreach (month; EnumMembers!Month)
10070 {
10071 scope(failure) writeln(month);
10072 assert(monthFromString(monthToString(month)) == month);
10073 }
10074 }
10075
10076
10077 version (unittest)
10078 {
10079 // All of these helper arrays are sorted in ascending order.
10080 auto testYearsBC = [-1999, -1200, -600, -4, -1, 0];
10081 auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012];
10082
10083 // I'd use a Tuple, but I get forward reference errors if I try.
10084 struct MonthDay
10085 {
10086 Month month;
10087 short day;
10088
10089 this(int m, short d)
10090 {
10091 month = cast(Month) m;
10092 day = d;
10093 }
10094 }
10095
10096 MonthDay[] testMonthDays = [MonthDay(1, 1),
10097 MonthDay(1, 2),
10098 MonthDay(3, 17),
10099 MonthDay(7, 4),
10100 MonthDay(10, 27),
10101 MonthDay(12, 30),
10102 MonthDay(12, 31)];
10103
10104 auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31];
10105
10106 auto testTODs = [TimeOfDay(0, 0, 0),
10107 TimeOfDay(0, 0, 1),
10108 TimeOfDay(0, 1, 0),
10109 TimeOfDay(1, 0, 0),
10110 TimeOfDay(13, 13, 13),
10111 TimeOfDay(23, 59, 59)];
10112
10113 auto testHours = [0, 1, 12, 22, 23];
10114 auto testMinSecs = [0, 1, 30, 58, 59];
10115
10116 // Throwing exceptions is incredibly expensive, so we want to use a smaller
10117 // set of values for tests using assertThrown.
10118 auto testTODsThrown = [TimeOfDay(0, 0, 0),
10119 TimeOfDay(13, 13, 13),
10120 TimeOfDay(23, 59, 59)];
10121
10122 Date[] testDatesBC;
10123 Date[] testDatesAD;
10124
10125 DateTime[] testDateTimesBC;
10126 DateTime[] testDateTimesAD;
10127
10128 // I'd use a Tuple, but I get forward reference errors if I try.
10129 struct GregDay { int day; Date date; }
10130 auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar
10131 GregDay(-735_233, Date(-2012, 1, 1)),
10132 GregDay(-735_202, Date(-2012, 2, 1)),
10133 GregDay(-735_175, Date(-2012, 2, 28)),
10134 GregDay(-735_174, Date(-2012, 2, 29)),
10135 GregDay(-735_173, Date(-2012, 3, 1)),
10136 GregDay(-734_502, Date(-2010, 1, 1)),
10137 GregDay(-734_472, Date(-2010, 1, 31)),
10138 GregDay(-734_471, Date(-2010, 2, 1)),
10139 GregDay(-734_444, Date(-2010, 2, 28)),
10140 GregDay(-734_443, Date(-2010, 3, 1)),
10141 GregDay(-734_413, Date(-2010, 3, 31)),
10142 GregDay(-734_412, Date(-2010, 4, 1)),
10143 GregDay(-734_383, Date(-2010, 4, 30)),
10144 GregDay(-734_382, Date(-2010, 5, 1)),
10145 GregDay(-734_352, Date(-2010, 5, 31)),
10146 GregDay(-734_351, Date(-2010, 6, 1)),
10147 GregDay(-734_322, Date(-2010, 6, 30)),
10148 GregDay(-734_321, Date(-2010, 7, 1)),
10149 GregDay(-734_291, Date(-2010, 7, 31)),
10150 GregDay(-734_290, Date(-2010, 8, 1)),
10151 GregDay(-734_260, Date(-2010, 8, 31)),
10152 GregDay(-734_259, Date(-2010, 9, 1)),
10153 GregDay(-734_230, Date(-2010, 9, 30)),
10154 GregDay(-734_229, Date(-2010, 10, 1)),
10155 GregDay(-734_199, Date(-2010, 10, 31)),
10156 GregDay(-734_198, Date(-2010, 11, 1)),
10157 GregDay(-734_169, Date(-2010, 11, 30)),
10158 GregDay(-734_168, Date(-2010, 12, 1)),
10159 GregDay(-734_139, Date(-2010, 12, 30)),
10160 GregDay(-734_138, Date(-2010, 12, 31)),
10161 GregDay(-731_215, Date(-2001, 1, 1)),
10162 GregDay(-730_850, Date(-2000, 1, 1)),
10163 GregDay(-730_849, Date(-2000, 1, 2)),
10164 GregDay(-730_486, Date(-2000, 12, 30)),
10165 GregDay(-730_485, Date(-2000, 12, 31)),
10166 GregDay(-730_484, Date(-1999, 1, 1)),
10167 GregDay(-694_690, Date(-1901, 1, 1)),
10168 GregDay(-694_325, Date(-1900, 1, 1)),
10169 GregDay(-585_118, Date(-1601, 1, 1)),
10170 GregDay(-584_753, Date(-1600, 1, 1)),
10171 GregDay(-584_388, Date(-1600, 12, 31)),
10172 GregDay(-584_387, Date(-1599, 1, 1)),
10173 GregDay(-365_972, Date(-1001, 1, 1)),
10174 GregDay(-365_607, Date(-1000, 1, 1)),
10175 GregDay(-183_351, Date(-501, 1, 1)),
10176 GregDay(-182_986, Date(-500, 1, 1)),
10177 GregDay(-182_621, Date(-499, 1, 1)),
10178 GregDay(-146_827, Date(-401, 1, 1)),
10179 GregDay(-146_462, Date(-400, 1, 1)),
10180 GregDay(-146_097, Date(-400, 12, 31)),
10181 GregDay(-110_302, Date(-301, 1, 1)),
10182 GregDay(-109_937, Date(-300, 1, 1)),
10183 GregDay(-73_778, Date(-201, 1, 1)),
10184 GregDay(-73_413, Date(-200, 1, 1)),
10185 GregDay(-38_715, Date(-105, 1, 1)),
10186 GregDay(-37_254, Date(-101, 1, 1)),
10187 GregDay(-36_889, Date(-100, 1, 1)),
10188 GregDay(-36_524, Date(-99, 1, 1)),
10189 GregDay(-36_160, Date(-99, 12, 31)),
10190 GregDay(-35_794, Date(-97, 1, 1)),
10191 GregDay(-18_627, Date(-50, 1, 1)),
10192 GregDay(-18_262, Date(-49, 1, 1)),
10193 GregDay(-3652, Date(-9, 1, 1)),
10194 GregDay(-2191, Date(-5, 1, 1)),
10195 GregDay(-1827, Date(-5, 12, 31)),
10196 GregDay(-1826, Date(-4, 1, 1)),
10197 GregDay(-1825, Date(-4, 1, 2)),
10198 GregDay(-1462, Date(-4, 12, 30)),
10199 GregDay(-1461, Date(-4, 12, 31)),
10200 GregDay(-1460, Date(-3, 1, 1)),
10201 GregDay(-1096, Date(-3, 12, 31)),
10202 GregDay(-1095, Date(-2, 1, 1)),
10203 GregDay(-731, Date(-2, 12, 31)),
10204 GregDay(-730, Date(-1, 1, 1)),
10205 GregDay(-367, Date(-1, 12, 30)),
10206 GregDay(-366, Date(-1, 12, 31)),
10207 GregDay(-365, Date(0, 1, 1)),
10208 GregDay(-31, Date(0, 11, 30)),
10209 GregDay(-30, Date(0, 12, 1)),
10210 GregDay(-1, Date(0, 12, 30)),
10211 GregDay(0, Date(0, 12, 31))];
10212
10213 auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)),
10214 GregDay(2, Date(1, 1, 2)),
10215 GregDay(32, Date(1, 2, 1)),
10216 GregDay(365, Date(1, 12, 31)),
10217 GregDay(366, Date(2, 1, 1)),
10218 GregDay(731, Date(3, 1, 1)),
10219 GregDay(1096, Date(4, 1, 1)),
10220 GregDay(1097, Date(4, 1, 2)),
10221 GregDay(1460, Date(4, 12, 30)),
10222 GregDay(1461, Date(4, 12, 31)),
10223 GregDay(1462, Date(5, 1, 1)),
10224 GregDay(17_898, Date(50, 1, 1)),
10225 GregDay(35_065, Date(97, 1, 1)),
10226 GregDay(36_160, Date(100, 1, 1)),
10227 GregDay(36_525, Date(101, 1, 1)),
10228 GregDay(37_986, Date(105, 1, 1)),
10229 GregDay(72_684, Date(200, 1, 1)),
10230 GregDay(73_049, Date(201, 1, 1)),
10231 GregDay(109_208, Date(300, 1, 1)),
10232 GregDay(109_573, Date(301, 1, 1)),
10233 GregDay(145_732, Date(400, 1, 1)),
10234 GregDay(146_098, Date(401, 1, 1)),
10235 GregDay(182_257, Date(500, 1, 1)),
10236 GregDay(182_622, Date(501, 1, 1)),
10237 GregDay(364_878, Date(1000, 1, 1)),
10238 GregDay(365_243, Date(1001, 1, 1)),
10239 GregDay(584_023, Date(1600, 1, 1)),
10240 GregDay(584_389, Date(1601, 1, 1)),
10241 GregDay(693_596, Date(1900, 1, 1)),
10242 GregDay(693_961, Date(1901, 1, 1)),
10243 GregDay(729_755, Date(1999, 1, 1)),
10244 GregDay(730_120, Date(2000, 1, 1)),
10245 GregDay(730_121, Date(2000, 1, 2)),
10246 GregDay(730_484, Date(2000, 12, 30)),
10247 GregDay(730_485, Date(2000, 12, 31)),
10248 GregDay(730_486, Date(2001, 1, 1)),
10249 GregDay(733_773, Date(2010, 1, 1)),
10250 GregDay(733_774, Date(2010, 1, 2)),
10251 GregDay(733_803, Date(2010, 1, 31)),
10252 GregDay(733_804, Date(2010, 2, 1)),
10253 GregDay(733_831, Date(2010, 2, 28)),
10254 GregDay(733_832, Date(2010, 3, 1)),
10255 GregDay(733_862, Date(2010, 3, 31)),
10256 GregDay(733_863, Date(2010, 4, 1)),
10257 GregDay(733_892, Date(2010, 4, 30)),
10258 GregDay(733_893, Date(2010, 5, 1)),
10259 GregDay(733_923, Date(2010, 5, 31)),
10260 GregDay(733_924, Date(2010, 6, 1)),
10261 GregDay(733_953, Date(2010, 6, 30)),
10262 GregDay(733_954, Date(2010, 7, 1)),
10263 GregDay(733_984, Date(2010, 7, 31)),
10264 GregDay(733_985, Date(2010, 8, 1)),
10265 GregDay(734_015, Date(2010, 8, 31)),
10266 GregDay(734_016, Date(2010, 9, 1)),
10267 GregDay(734_045, Date(2010, 9, 30)),
10268 GregDay(734_046, Date(2010, 10, 1)),
10269 GregDay(734_076, Date(2010, 10, 31)),
10270 GregDay(734_077, Date(2010, 11, 1)),
10271 GregDay(734_106, Date(2010, 11, 30)),
10272 GregDay(734_107, Date(2010, 12, 1)),
10273 GregDay(734_136, Date(2010, 12, 30)),
10274 GregDay(734_137, Date(2010, 12, 31)),
10275 GregDay(734_503, Date(2012, 1, 1)),
10276 GregDay(734_534, Date(2012, 2, 1)),
10277 GregDay(734_561, Date(2012, 2, 28)),
10278 GregDay(734_562, Date(2012, 2, 29)),
10279 GregDay(734_563, Date(2012, 3, 1)),
10280 GregDay(734_858, Date(2012, 12, 21))];
10281
10282 // I'd use a Tuple, but I get forward reference errors if I try.
10283 struct DayOfYear { int day; MonthDay md; }
10284 auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)),
10285 DayOfYear(2, MonthDay(1, 2)),
10286 DayOfYear(3, MonthDay(1, 3)),
10287 DayOfYear(31, MonthDay(1, 31)),
10288 DayOfYear(32, MonthDay(2, 1)),
10289 DayOfYear(59, MonthDay(2, 28)),
10290 DayOfYear(60, MonthDay(3, 1)),
10291 DayOfYear(90, MonthDay(3, 31)),
10292 DayOfYear(91, MonthDay(4, 1)),
10293 DayOfYear(120, MonthDay(4, 30)),
10294 DayOfYear(121, MonthDay(5, 1)),
10295 DayOfYear(151, MonthDay(5, 31)),
10296 DayOfYear(152, MonthDay(6, 1)),
10297 DayOfYear(181, MonthDay(6, 30)),
10298 DayOfYear(182, MonthDay(7, 1)),
10299 DayOfYear(212, MonthDay(7, 31)),
10300 DayOfYear(213, MonthDay(8, 1)),
10301 DayOfYear(243, MonthDay(8, 31)),
10302 DayOfYear(244, MonthDay(9, 1)),
10303 DayOfYear(273, MonthDay(9, 30)),
10304 DayOfYear(274, MonthDay(10, 1)),
10305 DayOfYear(304, MonthDay(10, 31)),
10306 DayOfYear(305, MonthDay(11, 1)),
10307 DayOfYear(334, MonthDay(11, 30)),
10308 DayOfYear(335, MonthDay(12, 1)),
10309 DayOfYear(363, MonthDay(12, 29)),
10310 DayOfYear(364, MonthDay(12, 30)),
10311 DayOfYear(365, MonthDay(12, 31))];
10312
10313 auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)),
10314 DayOfYear(2, MonthDay(1, 2)),
10315 DayOfYear(3, MonthDay(1, 3)),
10316 DayOfYear(31, MonthDay(1, 31)),
10317 DayOfYear(32, MonthDay(2, 1)),
10318 DayOfYear(59, MonthDay(2, 28)),
10319 DayOfYear(60, MonthDay(2, 29)),
10320 DayOfYear(61, MonthDay(3, 1)),
10321 DayOfYear(91, MonthDay(3, 31)),
10322 DayOfYear(92, MonthDay(4, 1)),
10323 DayOfYear(121, MonthDay(4, 30)),
10324 DayOfYear(122, MonthDay(5, 1)),
10325 DayOfYear(152, MonthDay(5, 31)),
10326 DayOfYear(153, MonthDay(6, 1)),
10327 DayOfYear(182, MonthDay(6, 30)),
10328 DayOfYear(183, MonthDay(7, 1)),
10329 DayOfYear(213, MonthDay(7, 31)),
10330 DayOfYear(214, MonthDay(8, 1)),
10331 DayOfYear(244, MonthDay(8, 31)),
10332 DayOfYear(245, MonthDay(9, 1)),
10333 DayOfYear(274, MonthDay(9, 30)),
10334 DayOfYear(275, MonthDay(10, 1)),
10335 DayOfYear(305, MonthDay(10, 31)),
10336 DayOfYear(306, MonthDay(11, 1)),
10337 DayOfYear(335, MonthDay(11, 30)),
10338 DayOfYear(336, MonthDay(12, 1)),
10339 DayOfYear(364, MonthDay(12, 29)),
10340 DayOfYear(365, MonthDay(12, 30)),
10341 DayOfYear(366, MonthDay(12, 31))];
10342
10343 void initializeTests() @safe
10344 {
10345 foreach (year; testYearsBC)
10346 {
10347 foreach (md; testMonthDays)
10348 testDatesBC ~= Date(year, md.month, md.day);
10349 }
10350
10351 foreach (year; testYearsAD)
10352 {
10353 foreach (md; testMonthDays)
10354 testDatesAD ~= Date(year, md.month, md.day);
10355 }
10356
10357 foreach (dt; testDatesBC)
10358 {
10359 foreach (tod; testTODs)
10360 testDateTimesBC ~= DateTime(dt, tod);
10361 }
10362
10363 foreach (dt; testDatesAD)
10364 {
10365 foreach (tod; testTODs)
10366 testDateTimesAD ~= DateTime(dt, tod);
10367 }
10368 }
10369 }
10370