]>
Commit | Line | Data |
---|---|---|
b4c522fa | 1 | // Written in the D programming language |
b4c522fa | 2 | /++ |
5fee5ec3 IB |
3 | |
4 | $(SCRIPT inhibitQuickIndex = 1;) | |
5 | $(DIVC quickindex, | |
6 | $(BOOKTABLE, | |
7 | $(TR $(TH Category) $(TH Functions)) | |
8 | $(TR $(TD Main date types) $(TD | |
9 | $(LREF Date) | |
10 | $(LREF DateTime) | |
11 | )) | |
12 | $(TR $(TD Other date types) $(TD | |
13 | $(LREF Month) | |
14 | $(LREF DayOfWeek) | |
15 | $(LREF TimeOfDay) | |
16 | )) | |
17 | $(TR $(TD Date checking) $(TD | |
18 | $(LREF valid) | |
19 | $(LREF validTimeUnits) | |
20 | $(LREF yearIsLeapYear) | |
21 | $(LREF isTimePoint) | |
22 | $(LREF enforceValid) | |
23 | )) | |
24 | $(TR $(TD Date conversion) $(TD | |
25 | $(LREF daysToDayOfWeek) | |
26 | $(LREF monthsToMonth) | |
27 | )) | |
28 | $(TR $(TD Time units) $(TD | |
29 | $(LREF cmpTimeUnits) | |
30 | $(LREF timeStrings) | |
31 | )) | |
32 | $(TR $(TD Other) $(TD | |
33 | $(LREF AllowDayOverflow) | |
34 | $(LREF DateTimeException) | |
35 | )) | |
36 | )) | |
37 | ||
b4c522fa | 38 | License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). |
5fee5ec3 IB |
39 | Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) |
40 | Source: $(PHOBOSSRC std/datetime/date.d) | |
b4c522fa IB |
41 | +/ |
42 | module std.datetime.date; | |
43 | ||
5fee5ec3 | 44 | import core.time : TimeException; |
b4c522fa IB |
45 | import std.traits : isSomeString, Unqual; |
46 | import std.typecons : Flag; | |
5fee5ec3 | 47 | import std.range.primitives : isOutputRange; |
b4c522fa | 48 | |
5fee5ec3 | 49 | version (StdUnittest) import std.exception : assertThrown; |
b4c522fa IB |
50 | |
51 | @safe unittest | |
52 | { | |
53 | initializeTests(); | |
54 | } | |
55 | ||
56 | ||
57 | /++ | |
58 | Exception type used by std.datetime. It's an alias to | |
59 | $(REF TimeException,core,time). Either can be caught without concern about | |
60 | which module it came from. | |
61 | +/ | |
62 | alias DateTimeException = TimeException; | |
63 | ||
64 | ||
65 | /++ | |
66 | Represents the 12 months of the Gregorian year (January is 1). | |
67 | +/ | |
68 | enum Month : ubyte | |
69 | { | |
70 | jan = 1, /// | |
71 | feb, /// | |
72 | mar, /// | |
73 | apr, /// | |
74 | may, /// | |
75 | jun, /// | |
76 | jul, /// | |
77 | aug, /// | |
78 | sep, /// | |
79 | oct, /// | |
80 | nov, /// | |
81 | dec /// | |
82 | } | |
83 | ||
5fee5ec3 IB |
84 | /// |
85 | @safe pure unittest | |
86 | { | |
87 | assert(Date(2018, 10, 1).month == Month.oct); | |
88 | assert(DateTime(1, 1, 1).month == Month.jan); | |
89 | } | |
90 | ||
b4c522fa IB |
91 | |
92 | /++ | |
93 | Represents the 7 days of the Gregorian week (Sunday is 0). | |
94 | +/ | |
95 | enum DayOfWeek : ubyte | |
96 | { | |
97 | sun = 0, /// | |
98 | mon, /// | |
99 | tue, /// | |
100 | wed, /// | |
101 | thu, /// | |
102 | fri, /// | |
103 | sat /// | |
104 | } | |
105 | ||
5fee5ec3 IB |
106 | /// |
107 | @safe pure unittest | |
108 | { | |
109 | assert(Date(2018, 10, 1).dayOfWeek == DayOfWeek.mon); | |
110 | assert(DateTime(5, 5, 5).dayOfWeek == DayOfWeek.thu); | |
111 | } | |
b4c522fa IB |
112 | |
113 | /++ | |
114 | In some date calculations, adding months or years can cause the date to fall | |
115 | on a day of the month which is not valid (e.g. February 29th 2001 or | |
116 | June 31st 2000). If overflow is allowed (as is the default), then the month | |
117 | will be incremented accordingly (so, February 29th 2001 would become | |
118 | March 1st 2001, and June 31st 2000 would become July 1st 2000). If overflow | |
119 | is not allowed, then the day will be adjusted to the last valid day in that | |
120 | month (so, February 29th 2001 would become February 28th 2001 and | |
121 | June 31st 2000 would become June 30th 2000). | |
122 | ||
123 | AllowDayOverflow only applies to calculations involving months or years. | |
124 | ||
5fee5ec3 | 125 | If set to `AllowDayOverflow.no`, then day overflow is not allowed. |
b4c522fa | 126 | |
5fee5ec3 | 127 | Otherwise, if set to `AllowDayOverflow.yes`, then day overflow is |
b4c522fa IB |
128 | allowed. |
129 | +/ | |
130 | alias AllowDayOverflow = Flag!"allowDayOverflow"; | |
131 | ||
132 | ||
133 | /++ | |
134 | Array of the strings representing time units, starting with the smallest | |
5fee5ec3 | 135 | unit and going to the largest. It does not include `"nsecs"`. |
b4c522fa | 136 | |
5fee5ec3 IB |
137 | Includes `"hnsecs"` (hecto-nanoseconds (100 ns)), |
138 | `"usecs"` (microseconds), `"msecs"` (milliseconds), `"seconds"`, | |
139 | `"minutes"`, `"hours"`, `"days"`, `"weeks"`, `"months"`, and | |
140 | `"years"` | |
b4c522fa IB |
141 | +/ |
142 | immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes", | |
143 | "hours", "days", "weeks", "months", "years"]; | |
144 | ||
145 | ||
146 | /++ | |
5fee5ec3 IB |
147 | Combines the $(REF Date,std,datetime,date) and |
148 | $(REF TimeOfDay,std,datetime,date) structs to give an object which holds | |
149 | both the date and the time. It is optimized for calendar-based operations | |
150 | and has no concept of time zone. For an object which is optimized for time | |
151 | operations based on the system time, use | |
152 | $(REF SysTime,std,datetime,systime). $(REF SysTime,std,datetime,systime) has | |
153 | a concept of time zone and has much higher precision (hnsecs). `DateTime` | |
154 | is intended primarily for calendar-based uses rather than precise time | |
155 | operations. | |
b4c522fa IB |
156 | +/ |
157 | struct DateTime | |
158 | { | |
159 | public: | |
160 | ||
161 | /++ | |
162 | Params: | |
163 | date = The date portion of $(LREF DateTime). | |
164 | tod = The time portion of $(LREF DateTime). | |
165 | +/ | |
5fee5ec3 | 166 | this(Date date, TimeOfDay tod = TimeOfDay.init) @safe pure nothrow @nogc |
b4c522fa IB |
167 | { |
168 | _date = date; | |
169 | _tod = tod; | |
170 | } | |
171 | ||
172 | @safe unittest | |
173 | { | |
174 | { | |
175 | auto dt = DateTime.init; | |
176 | assert(dt._date == Date.init); | |
177 | assert(dt._tod == TimeOfDay.init); | |
178 | } | |
179 | ||
180 | { | |
181 | auto dt = DateTime(Date(1999, 7 ,6)); | |
182 | assert(dt._date == Date(1999, 7, 6)); | |
183 | assert(dt._tod == TimeOfDay.init); | |
184 | } | |
185 | ||
186 | { | |
187 | auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33)); | |
188 | assert(dt._date == Date(1999, 7, 6)); | |
189 | assert(dt._tod == TimeOfDay(12, 30, 33)); | |
190 | } | |
191 | } | |
192 | ||
193 | ||
194 | /++ | |
195 | Params: | |
196 | year = The year portion of the date. | |
197 | month = The month portion of the date (January is 1). | |
198 | day = The day portion of the date. | |
199 | hour = The hour portion of the time; | |
200 | minute = The minute portion of the time; | |
201 | second = The second portion of the time; | |
202 | +/ | |
203 | this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0) @safe pure | |
204 | { | |
205 | _date = Date(year, month, day); | |
206 | _tod = TimeOfDay(hour, minute, second); | |
207 | } | |
208 | ||
209 | @safe unittest | |
210 | { | |
211 | { | |
212 | auto dt = DateTime(1999, 7 ,6); | |
213 | assert(dt._date == Date(1999, 7, 6)); | |
214 | assert(dt._tod == TimeOfDay.init); | |
215 | } | |
216 | ||
217 | { | |
218 | auto dt = DateTime(1999, 7 ,6, 12, 30, 33); | |
219 | assert(dt._date == Date(1999, 7, 6)); | |
220 | assert(dt._tod == TimeOfDay(12, 30, 33)); | |
221 | } | |
222 | } | |
223 | ||
224 | ||
225 | /++ | |
5fee5ec3 | 226 | Compares this $(LREF DateTime) with the given `DateTime.`. |
b4c522fa IB |
227 | |
228 | Returns: | |
229 | $(BOOKTABLE, | |
230 | $(TR $(TD this < rhs) $(TD < 0)) | |
231 | $(TR $(TD this == rhs) $(TD 0)) | |
232 | $(TR $(TD this > rhs) $(TD > 0)) | |
233 | ) | |
234 | +/ | |
5fee5ec3 | 235 | int opCmp(DateTime rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
236 | { |
237 | immutable dateResult = _date.opCmp(rhs._date); | |
238 | ||
239 | if (dateResult != 0) | |
240 | return dateResult; | |
241 | ||
242 | return _tod.opCmp(rhs._tod); | |
243 | } | |
244 | ||
245 | @safe unittest | |
246 | { | |
247 | // Test A.D. | |
248 | assert(DateTime(Date.init, TimeOfDay.init).opCmp(DateTime.init) == 0); | |
249 | ||
250 | assert(DateTime(Date(1999, 1, 1)).opCmp(DateTime(Date(1999, 1, 1))) == 0); | |
251 | assert(DateTime(Date(1, 7, 1)).opCmp(DateTime(Date(1, 7, 1))) == 0); | |
252 | assert(DateTime(Date(1, 1, 6)).opCmp(DateTime(Date(1, 1, 6))) == 0); | |
253 | ||
254 | assert(DateTime(Date(1999, 7, 1)).opCmp(DateTime(Date(1999, 7, 1))) == 0); | |
255 | assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) == 0); | |
256 | ||
257 | assert(DateTime(Date(1, 7, 6)).opCmp(DateTime(Date(1, 7, 6))) == 0); | |
258 | ||
259 | assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(2000, 7, 6))) < 0); | |
260 | assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); | |
261 | assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 8, 6))) < 0); | |
262 | assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); | |
263 | assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) < 0); | |
264 | assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 7, 6))) > 0); | |
265 | ||
266 | assert(DateTime(Date(1999, 8, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); | |
267 | assert(DateTime(Date(2000, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); | |
268 | assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); | |
269 | assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); | |
270 | assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 8, 6))) < 0); | |
271 | assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); | |
272 | ||
273 | ||
274 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).opCmp( | |
275 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))) == 0); | |
276 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)).opCmp( | |
277 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))) == 0); | |
278 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)).opCmp( | |
279 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))) == 0); | |
280 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( | |
281 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); | |
282 | ||
283 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)).opCmp( | |
284 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))) == 0); | |
285 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
286 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); | |
287 | ||
288 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)).opCmp( | |
289 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))) == 0); | |
290 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( | |
291 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); | |
292 | ||
293 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
294 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); | |
295 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
296 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
297 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
298 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); | |
299 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
300 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
301 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
302 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) < 0); | |
303 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
304 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
305 | ||
306 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
307 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); | |
308 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
309 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); | |
310 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
311 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); | |
312 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
313 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); | |
314 | ||
315 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
316 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); | |
317 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
318 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); | |
319 | ||
320 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
321 | DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
322 | assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
323 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); | |
324 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
325 | DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
326 | assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
327 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); | |
328 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
329 | DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
330 | assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
331 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); | |
332 | ||
333 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
334 | DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); | |
335 | assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
336 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); | |
337 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
338 | DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); | |
339 | assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
340 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); | |
341 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
342 | DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); | |
343 | assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
344 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); | |
345 | ||
346 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( | |
347 | DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); | |
348 | assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
349 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); | |
350 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( | |
351 | DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))) < 0); | |
352 | assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
353 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
354 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( | |
355 | DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); | |
356 | assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
357 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); | |
358 | ||
359 | // Test B.C. | |
360 | assert(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)).opCmp( | |
361 | DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))) == 0); | |
362 | assert(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)).opCmp( | |
363 | DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))) == 0); | |
364 | assert(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)).opCmp( | |
365 | DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))) == 0); | |
366 | ||
367 | assert(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)).opCmp( | |
368 | DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))) == 0); | |
369 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
370 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); | |
371 | ||
372 | assert(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
373 | DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))) == 0); | |
374 | ||
375 | assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
376 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
377 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
378 | DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
379 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
380 | DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); | |
381 | assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
382 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
383 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
384 | DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); | |
385 | assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
386 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
387 | ||
388 | assert(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
389 | DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); | |
390 | assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( | |
391 | DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
392 | assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
393 | DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); | |
394 | assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
395 | DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
396 | assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
397 | DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); | |
398 | assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
399 | DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); | |
400 | ||
401 | // Test Both | |
402 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
403 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
404 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
405 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
406 | ||
407 | assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
408 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
409 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
410 | DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) > 0); | |
411 | ||
412 | assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( | |
413 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
414 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
415 | DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); | |
416 | ||
417 | assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( | |
418 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); | |
419 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( | |
420 | DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))) > 0); | |
421 | ||
422 | assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( | |
423 | DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))) < 0); | |
424 | assert(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)).opCmp( | |
425 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); | |
426 | ||
427 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); | |
428 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); | |
429 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); | |
430 | assert(dt.opCmp(dt) == 0); | |
431 | assert(dt.opCmp(cdt) == 0); | |
432 | assert(dt.opCmp(idt) == 0); | |
433 | assert(cdt.opCmp(dt) == 0); | |
434 | assert(cdt.opCmp(cdt) == 0); | |
435 | assert(cdt.opCmp(idt) == 0); | |
436 | assert(idt.opCmp(dt) == 0); | |
437 | assert(idt.opCmp(cdt) == 0); | |
438 | assert(idt.opCmp(idt) == 0); | |
439 | } | |
440 | ||
441 | ||
442 | /++ | |
443 | The date portion of $(LREF DateTime). | |
444 | +/ | |
445 | @property Date date() const @safe pure nothrow @nogc | |
446 | { | |
447 | return _date; | |
448 | } | |
449 | ||
450 | @safe unittest | |
451 | { | |
452 | { | |
453 | auto dt = DateTime.init; | |
454 | assert(dt.date == Date.init); | |
455 | } | |
456 | ||
457 | { | |
458 | auto dt = DateTime(Date(1999, 7, 6)); | |
459 | assert(dt.date == Date(1999, 7, 6)); | |
460 | } | |
461 | ||
462 | const cdt = DateTime(1999, 7, 6); | |
463 | immutable idt = DateTime(1999, 7, 6); | |
464 | assert(cdt.date == Date(1999, 7, 6)); | |
465 | assert(idt.date == Date(1999, 7, 6)); | |
466 | } | |
467 | ||
468 | ||
469 | /++ | |
470 | The date portion of $(LREF DateTime). | |
471 | ||
472 | Params: | |
473 | date = The Date to set this $(LREF DateTime)'s date portion to. | |
474 | +/ | |
5fee5ec3 | 475 | @property void date(Date date) @safe pure nothrow @nogc |
b4c522fa IB |
476 | { |
477 | _date = date; | |
478 | } | |
479 | ||
480 | @safe unittest | |
481 | { | |
482 | auto dt = DateTime.init; | |
483 | dt.date = Date(1999, 7, 6); | |
484 | assert(dt._date == Date(1999, 7, 6)); | |
485 | assert(dt._tod == TimeOfDay.init); | |
486 | ||
487 | const cdt = DateTime(1999, 7, 6); | |
488 | immutable idt = DateTime(1999, 7, 6); | |
489 | static assert(!__traits(compiles, cdt.date = Date(2010, 1, 1))); | |
490 | static assert(!__traits(compiles, idt.date = Date(2010, 1, 1))); | |
491 | } | |
492 | ||
493 | ||
494 | /++ | |
495 | The time portion of $(LREF DateTime). | |
496 | +/ | |
497 | @property TimeOfDay timeOfDay() const @safe pure nothrow @nogc | |
498 | { | |
499 | return _tod; | |
500 | } | |
501 | ||
502 | @safe unittest | |
503 | { | |
504 | { | |
505 | auto dt = DateTime.init; | |
506 | assert(dt.timeOfDay == TimeOfDay.init); | |
507 | } | |
508 | ||
509 | { | |
510 | auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33)); | |
511 | assert(dt.timeOfDay == TimeOfDay(12, 30, 33)); | |
512 | } | |
513 | ||
514 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
515 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
516 | assert(cdt.timeOfDay == TimeOfDay(12, 30, 33)); | |
517 | assert(idt.timeOfDay == TimeOfDay(12, 30, 33)); | |
518 | } | |
519 | ||
520 | ||
521 | /++ | |
522 | The time portion of $(LREF DateTime). | |
523 | ||
524 | Params: | |
525 | tod = The $(REF TimeOfDay,std,datetime,date) to set this | |
526 | $(LREF DateTime)'s time portion to. | |
527 | +/ | |
5fee5ec3 | 528 | @property void timeOfDay(TimeOfDay tod) @safe pure nothrow @nogc |
b4c522fa IB |
529 | { |
530 | _tod = tod; | |
531 | } | |
532 | ||
533 | @safe unittest | |
534 | { | |
535 | auto dt = DateTime.init; | |
536 | dt.timeOfDay = TimeOfDay(12, 30, 33); | |
537 | assert(dt._date == Date.init); | |
538 | assert(dt._tod == TimeOfDay(12, 30, 33)); | |
539 | ||
540 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
541 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
542 | static assert(!__traits(compiles, cdt.timeOfDay = TimeOfDay(12, 30, 33))); | |
543 | static assert(!__traits(compiles, idt.timeOfDay = TimeOfDay(12, 30, 33))); | |
544 | } | |
545 | ||
546 | ||
547 | /++ | |
548 | Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive | |
549 | are B.C. | |
550 | +/ | |
551 | @property short year() const @safe pure nothrow @nogc | |
552 | { | |
553 | return _date.year; | |
554 | } | |
555 | ||
556 | @safe unittest | |
557 | { | |
558 | assert(Date.init.year == 1); | |
559 | assert(Date(1999, 7, 6).year == 1999); | |
560 | assert(Date(-1999, 7, 6).year == -1999); | |
561 | ||
562 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
563 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
564 | assert(idt.year == 1999); | |
565 | assert(idt.year == 1999); | |
566 | } | |
567 | ||
568 | ||
569 | /++ | |
570 | Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive | |
571 | are B.C. | |
572 | ||
573 | Params: | |
574 | year = The year to set this $(LREF DateTime)'s year to. | |
575 | ||
576 | Throws: | |
577 | $(REF DateTimeException,std,datetime,date) if the new year is not | |
578 | a leap year and if the resulting date would be on February 29th. | |
579 | +/ | |
580 | @property void year(int year) @safe pure | |
581 | { | |
582 | _date.year = year; | |
583 | } | |
584 | ||
585 | /// | |
586 | @safe unittest | |
587 | { | |
588 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999); | |
589 | assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010); | |
590 | assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7); | |
591 | } | |
592 | ||
593 | @safe unittest | |
594 | { | |
5fee5ec3 | 595 | static void testDT(DateTime dt, int year, DateTime expected, size_t line = __LINE__) |
b4c522fa IB |
596 | { |
597 | dt.year = year; | |
598 | assert(dt == expected); | |
599 | } | |
600 | ||
601 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), | |
602 | 1999, | |
603 | DateTime(Date(1999, 1, 1), TimeOfDay(12, 30, 33))); | |
604 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), | |
605 | 0, | |
606 | DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33))); | |
607 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), | |
608 | -1999, | |
609 | DateTime(Date(-1999, 1, 1), TimeOfDay(12, 30, 33))); | |
610 | ||
611 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
612 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
613 | static assert(!__traits(compiles, cdt.year = 7)); | |
614 | static assert(!__traits(compiles, idt.year = 7)); | |
615 | } | |
616 | ||
617 | ||
618 | /++ | |
619 | Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. | |
620 | ||
621 | Throws: | |
5fee5ec3 | 622 | $(REF DateTimeException,std,datetime,date) if `isAD` is true. |
b4c522fa IB |
623 | +/ |
624 | @property short yearBC() const @safe pure | |
625 | { | |
626 | return _date.yearBC; | |
627 | } | |
628 | ||
629 | /// | |
630 | @safe unittest | |
631 | { | |
632 | assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1); | |
633 | assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2); | |
634 | assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101); | |
635 | } | |
636 | ||
637 | @safe unittest | |
638 | { | |
5fee5ec3 | 639 | assertThrown!DateTimeException((DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1)))); |
b4c522fa IB |
640 | |
641 | auto dt = DateTime(1999, 7, 6, 12, 30, 33); | |
642 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
643 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
644 | dt.yearBC = 12; | |
645 | assert(dt.yearBC == 12); | |
646 | static assert(!__traits(compiles, cdt.yearBC = 12)); | |
647 | static assert(!__traits(compiles, idt.yearBC = 12)); | |
648 | } | |
649 | ||
650 | ||
651 | /++ | |
652 | Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. | |
653 | ||
654 | Params: | |
655 | year = The year B.C. to set this $(LREF DateTime)'s year to. | |
656 | ||
657 | Throws: | |
658 | $(REF DateTimeException,std,datetime,date) if a non-positive value | |
659 | is given. | |
660 | +/ | |
661 | @property void yearBC(int year) @safe pure | |
662 | { | |
663 | _date.yearBC = year; | |
664 | } | |
665 | ||
666 | /// | |
667 | @safe unittest | |
668 | { | |
669 | auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0)); | |
670 | dt.yearBC = 1; | |
671 | assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0))); | |
672 | ||
673 | dt.yearBC = 10; | |
674 | assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0))); | |
675 | } | |
676 | ||
677 | @safe unittest | |
678 | { | |
679 | assertThrown!DateTimeException((DateTime dt){dt.yearBC = -1;}(DateTime(Date(1, 1, 1)))); | |
680 | ||
681 | auto dt = DateTime(1999, 7, 6, 12, 30, 33); | |
682 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
683 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
684 | dt.yearBC = 12; | |
685 | assert(dt.yearBC == 12); | |
686 | static assert(!__traits(compiles, cdt.yearBC = 12)); | |
687 | static assert(!__traits(compiles, idt.yearBC = 12)); | |
688 | } | |
689 | ||
690 | ||
691 | /++ | |
692 | Month of a Gregorian Year. | |
693 | +/ | |
694 | @property Month month() const @safe pure nothrow @nogc | |
695 | { | |
696 | return _date.month; | |
697 | } | |
698 | ||
699 | /// | |
700 | @safe unittest | |
701 | { | |
702 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7); | |
703 | assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10); | |
704 | assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4); | |
705 | } | |
706 | ||
707 | @safe unittest | |
708 | { | |
709 | assert(DateTime.init.month == 1); | |
710 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); | |
711 | assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); | |
712 | ||
713 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
714 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
715 | assert(cdt.month == 7); | |
716 | assert(idt.month == 7); | |
717 | } | |
718 | ||
719 | ||
720 | /++ | |
721 | Month of a Gregorian Year. | |
722 | ||
723 | Params: | |
724 | month = The month to set this $(LREF DateTime)'s month to. | |
725 | ||
726 | Throws: | |
727 | $(REF DateTimeException,std,datetime,date) if the given month is | |
728 | not a valid month. | |
729 | +/ | |
730 | @property void month(Month month) @safe pure | |
731 | { | |
732 | _date.month = month; | |
733 | } | |
734 | ||
735 | @safe unittest | |
736 | { | |
5fee5ec3 | 737 | static void testDT(DateTime dt, Month month, DateTime expected = DateTime.init, size_t line = __LINE__) |
b4c522fa IB |
738 | { |
739 | dt.month = month; | |
740 | assert(expected != DateTime.init); | |
741 | assert(dt == expected); | |
742 | } | |
743 | ||
744 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 0)); | |
745 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 13)); | |
746 | ||
747 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), | |
748 | cast(Month) 7, | |
749 | DateTime(Date(1, 7, 1), TimeOfDay(12, 30, 33))); | |
750 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)), | |
751 | cast(Month) 7, | |
752 | DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))); | |
753 | ||
754 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
755 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
756 | static assert(!__traits(compiles, cdt.month = 12)); | |
757 | static assert(!__traits(compiles, idt.month = 12)); | |
758 | } | |
759 | ||
760 | ||
761 | /++ | |
762 | Day of a Gregorian Month. | |
763 | +/ | |
764 | @property ubyte day() const @safe pure nothrow @nogc | |
765 | { | |
766 | return _date.day; | |
767 | } | |
768 | ||
769 | /// | |
770 | @safe unittest | |
771 | { | |
772 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6); | |
773 | assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4); | |
774 | assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5); | |
775 | } | |
776 | ||
777 | @safe unittest | |
778 | { | |
779 | import std.format : format; | |
780 | import std.range : chain; | |
781 | ||
782 | static void test(DateTime dateTime, int expected) | |
783 | { | |
784 | assert(dateTime.day == expected, format("Value given: %s", dateTime)); | |
785 | } | |
786 | ||
787 | foreach (year; chain(testYearsBC, testYearsAD)) | |
788 | { | |
789 | foreach (md; testMonthDays) | |
790 | { | |
791 | foreach (tod; testTODs) | |
792 | test(DateTime(Date(year, md.month, md.day), tod), md.day); | |
793 | } | |
794 | } | |
795 | ||
796 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
797 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
798 | assert(cdt.day == 6); | |
799 | assert(idt.day == 6); | |
800 | } | |
801 | ||
802 | ||
803 | /++ | |
804 | Day of a Gregorian Month. | |
805 | ||
806 | Params: | |
807 | day = The day of the month to set this $(LREF DateTime)'s day to. | |
808 | ||
809 | Throws: | |
810 | $(REF DateTimeException,std,datetime,date) if the given day is not | |
811 | a valid day of the current month. | |
812 | +/ | |
813 | @property void day(int day) @safe pure | |
814 | { | |
815 | _date.day = day; | |
816 | } | |
817 | ||
818 | @safe unittest | |
819 | { | |
820 | import std.exception : assertNotThrown; | |
821 | ||
822 | static void testDT(DateTime dt, int day) | |
823 | { | |
824 | dt.day = day; | |
825 | } | |
826 | ||
827 | // Test A.D. | |
828 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 0)); | |
829 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 32)); | |
830 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 29)); | |
831 | assertThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 30)); | |
832 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 32)); | |
833 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 31)); | |
834 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 32)); | |
835 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 31)); | |
836 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 32)); | |
837 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 32)); | |
838 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 31)); | |
839 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 32)); | |
840 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 31)); | |
841 | assertThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 32)); | |
842 | ||
843 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 31)); | |
844 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 28)); | |
845 | assertNotThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 29)); | |
846 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 31)); | |
847 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 30)); | |
848 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 31)); | |
849 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 30)); | |
850 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 31)); | |
851 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 31)); | |
852 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 30)); | |
853 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 31)); | |
854 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 30)); | |
855 | assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 31)); | |
856 | ||
857 | { | |
858 | auto dt = DateTime(Date(1, 1, 1), TimeOfDay(7, 12, 22)); | |
859 | dt.day = 6; | |
860 | assert(dt == DateTime(Date(1, 1, 6), TimeOfDay(7, 12, 22))); | |
861 | } | |
862 | ||
863 | // Test B.C. | |
864 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 0)); | |
865 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 32)); | |
866 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 29)); | |
867 | assertThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 30)); | |
868 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 32)); | |
869 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 31)); | |
870 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 32)); | |
871 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 31)); | |
872 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 32)); | |
873 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 32)); | |
874 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 31)); | |
875 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 32)); | |
876 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 31)); | |
877 | assertThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 32)); | |
878 | ||
879 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 31)); | |
880 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 28)); | |
881 | assertNotThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 29)); | |
882 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 31)); | |
883 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 30)); | |
884 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 31)); | |
885 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 30)); | |
886 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 31)); | |
887 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 31)); | |
888 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 30)); | |
889 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 31)); | |
890 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 30)); | |
891 | assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 31)); | |
892 | ||
893 | auto dt = DateTime(Date(-1, 1, 1), TimeOfDay(7, 12, 22)); | |
894 | dt.day = 6; | |
895 | assert(dt == DateTime(Date(-1, 1, 6), TimeOfDay(7, 12, 22))); | |
896 | ||
897 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
898 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
899 | static assert(!__traits(compiles, cdt.day = 27)); | |
900 | static assert(!__traits(compiles, idt.day = 27)); | |
901 | } | |
902 | ||
903 | ||
904 | /++ | |
905 | Hours past midnight. | |
906 | +/ | |
907 | @property ubyte hour() const @safe pure nothrow @nogc | |
908 | { | |
909 | return _tod.hour; | |
910 | } | |
911 | ||
912 | @safe unittest | |
913 | { | |
914 | assert(DateTime.init.hour == 0); | |
915 | assert(DateTime(Date.init, TimeOfDay(12, 0, 0)).hour == 12); | |
916 | ||
917 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
918 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
919 | assert(cdt.hour == 12); | |
920 | assert(idt.hour == 12); | |
921 | } | |
922 | ||
923 | ||
924 | /++ | |
925 | Hours past midnight. | |
926 | ||
927 | Params: | |
928 | hour = The hour of the day to set this $(LREF DateTime)'s hour to. | |
929 | ||
930 | Throws: | |
931 | $(REF DateTimeException,std,datetime,date) if the given hour would | |
932 | result in an invalid $(LREF DateTime). | |
933 | +/ | |
934 | @property void hour(int hour) @safe pure | |
935 | { | |
936 | _tod.hour = hour; | |
937 | } | |
938 | ||
939 | @safe unittest | |
940 | { | |
941 | assertThrown!DateTimeException((){DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).hour = 24;}()); | |
942 | ||
943 | auto dt = DateTime.init; | |
944 | dt.hour = 12; | |
945 | assert(dt == DateTime(1, 1, 1, 12, 0, 0)); | |
946 | ||
947 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
948 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
949 | static assert(!__traits(compiles, cdt.hour = 27)); | |
950 | static assert(!__traits(compiles, idt.hour = 27)); | |
951 | } | |
952 | ||
953 | ||
954 | /++ | |
955 | Minutes past the hour. | |
956 | +/ | |
957 | @property ubyte minute() const @safe pure nothrow @nogc | |
958 | { | |
959 | return _tod.minute; | |
960 | } | |
961 | ||
962 | @safe unittest | |
963 | { | |
964 | assert(DateTime.init.minute == 0); | |
965 | assert(DateTime(1, 1, 1, 0, 30, 0).minute == 30); | |
966 | ||
967 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
968 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
969 | assert(cdt.minute == 30); | |
970 | assert(idt.minute == 30); | |
971 | } | |
972 | ||
973 | ||
974 | /++ | |
975 | Minutes past the hour. | |
976 | ||
977 | Params: | |
978 | minute = The minute to set this $(LREF DateTime)'s minute to. | |
979 | ||
980 | Throws: | |
981 | $(REF DateTimeException,std,datetime,date) if the given minute | |
982 | would result in an invalid $(LREF DateTime). | |
983 | +/ | |
984 | @property void minute(int minute) @safe pure | |
985 | { | |
986 | _tod.minute = minute; | |
987 | } | |
988 | ||
989 | @safe unittest | |
990 | { | |
991 | assertThrown!DateTimeException((){DateTime.init.minute = 60;}()); | |
992 | ||
993 | auto dt = DateTime.init; | |
994 | dt.minute = 30; | |
995 | assert(dt == DateTime(1, 1, 1, 0, 30, 0)); | |
996 | ||
997 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
998 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
999 | static assert(!__traits(compiles, cdt.minute = 27)); | |
1000 | static assert(!__traits(compiles, idt.minute = 27)); | |
1001 | } | |
1002 | ||
1003 | ||
1004 | /++ | |
1005 | Seconds past the minute. | |
1006 | +/ | |
1007 | @property ubyte second() const @safe pure nothrow @nogc | |
1008 | { | |
1009 | return _tod.second; | |
1010 | } | |
1011 | ||
1012 | @safe unittest | |
1013 | { | |
1014 | assert(DateTime.init.second == 0); | |
1015 | assert(DateTime(1, 1, 1, 0, 0, 33).second == 33); | |
1016 | ||
1017 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1018 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1019 | assert(cdt.second == 33); | |
1020 | assert(idt.second == 33); | |
1021 | } | |
1022 | ||
1023 | ||
1024 | /++ | |
1025 | Seconds past the minute. | |
1026 | ||
1027 | Params: | |
1028 | second = The second to set this $(LREF DateTime)'s second to. | |
1029 | ||
1030 | Throws: | |
1031 | $(REF DateTimeException,std,datetime,date) if the given seconds | |
1032 | would result in an invalid $(LREF DateTime). | |
1033 | +/ | |
1034 | @property void second(int second) @safe pure | |
1035 | { | |
1036 | _tod.second = second; | |
1037 | } | |
1038 | ||
1039 | @safe unittest | |
1040 | { | |
1041 | assertThrown!DateTimeException((){DateTime.init.second = 60;}()); | |
1042 | ||
1043 | auto dt = DateTime.init; | |
1044 | dt.second = 33; | |
1045 | assert(dt == DateTime(1, 1, 1, 0, 0, 33)); | |
1046 | ||
1047 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1048 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1049 | static assert(!__traits(compiles, cdt.second = 27)); | |
1050 | static assert(!__traits(compiles, idt.second = 27)); | |
1051 | } | |
1052 | ||
1053 | ||
1054 | /++ | |
5fee5ec3 IB |
1055 | Adds the given number of years or months to this $(LREF DateTime), |
1056 | mutating it. A negative number will subtract. | |
b4c522fa IB |
1057 | |
1058 | Note that if day overflow is allowed, and the date with the adjusted | |
1059 | year/month overflows the number of days in the new month, then the month | |
1060 | will be incremented by one, and the day set to the number of days | |
1061 | overflowed. (e.g. if the day were 31 and the new month were June, then | |
1062 | the month would be incremented to July, and the new day would be 1). If | |
1063 | day overflow is not allowed, then the day will be set to the last valid | |
1064 | day in the month (e.g. June 31st would become June 30th). | |
1065 | ||
1066 | Params: | |
1067 | units = The type of units to add ("years" or "months"). | |
1068 | value = The number of months or years to add to this | |
1069 | $(LREF DateTime). | |
1070 | allowOverflow = Whether the days should be allowed to overflow, | |
1071 | causing the month to increment. | |
5fee5ec3 IB |
1072 | |
1073 | Returns: | |
1074 | A reference to the `DateTime` (`this`). | |
b4c522fa IB |
1075 | +/ |
1076 | ref DateTime add(string units) | |
1077 | (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc | |
1078 | if (units == "years" || units == "months") | |
1079 | { | |
1080 | _date.add!units(value, allowOverflow); | |
1081 | return this; | |
1082 | } | |
1083 | ||
1084 | /// | |
1085 | @safe unittest | |
1086 | { | |
1087 | auto dt1 = DateTime(2010, 1, 1, 12, 30, 33); | |
1088 | dt1.add!"months"(11); | |
1089 | assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33)); | |
1090 | ||
1091 | auto dt2 = DateTime(2010, 1, 1, 12, 30, 33); | |
1092 | dt2.add!"months"(-11); | |
1093 | assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33)); | |
1094 | ||
1095 | auto dt3 = DateTime(2000, 2, 29, 12, 30, 33); | |
1096 | dt3.add!"years"(1); | |
1097 | assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33)); | |
1098 | ||
1099 | auto dt4 = DateTime(2000, 2, 29, 12, 30, 33); | |
1100 | dt4.add!"years"(1, AllowDayOverflow.no); | |
1101 | assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33)); | |
1102 | } | |
1103 | ||
1104 | @safe unittest | |
1105 | { | |
1106 | auto dt = DateTime(2000, 1, 31); | |
1107 | dt.add!"years"(7).add!"months"(-4); | |
1108 | assert(dt == DateTime(2006, 10, 1)); | |
1109 | ||
1110 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1111 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1112 | static assert(!__traits(compiles, cdt.add!"years"(4))); | |
1113 | static assert(!__traits(compiles, idt.add!"years"(4))); | |
1114 | static assert(!__traits(compiles, cdt.add!"months"(4))); | |
1115 | static assert(!__traits(compiles, idt.add!"months"(4))); | |
1116 | } | |
1117 | ||
1118 | ||
1119 | /++ | |
5fee5ec3 IB |
1120 | Adds the given number of years or months to this $(LREF DateTime), |
1121 | mutating it. A negative number will subtract. | |
b4c522fa IB |
1122 | |
1123 | The difference between rolling and adding is that rolling does not | |
1124 | affect larger units. Rolling a $(LREF DateTime) 12 months | |
1125 | gets the exact same $(LREF DateTime). However, the days can still be | |
1126 | affected due to the differing number of days in each month. | |
1127 | ||
1128 | Because there are no units larger than years, there is no difference | |
1129 | between adding and rolling years. | |
1130 | ||
1131 | Params: | |
1132 | units = The type of units to add ("years" or "months"). | |
1133 | value = The number of months or years to add to this | |
1134 | $(LREF DateTime). | |
1135 | allowOverflow = Whether the days should be allowed to overflow, | |
1136 | causing the month to increment. | |
5fee5ec3 IB |
1137 | |
1138 | Returns: | |
1139 | A reference to the `DateTime` (`this`). | |
b4c522fa IB |
1140 | +/ |
1141 | ref DateTime roll(string units) | |
1142 | (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc | |
1143 | if (units == "years" || units == "months") | |
1144 | { | |
1145 | _date.roll!units(value, allowOverflow); | |
1146 | return this; | |
1147 | } | |
1148 | ||
1149 | /// | |
1150 | @safe unittest | |
1151 | { | |
1152 | auto dt1 = DateTime(2010, 1, 1, 12, 33, 33); | |
1153 | dt1.roll!"months"(1); | |
1154 | assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33)); | |
1155 | ||
1156 | auto dt2 = DateTime(2010, 1, 1, 12, 33, 33); | |
1157 | dt2.roll!"months"(-1); | |
1158 | assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33)); | |
1159 | ||
1160 | auto dt3 = DateTime(1999, 1, 29, 12, 33, 33); | |
1161 | dt3.roll!"months"(1); | |
1162 | assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33)); | |
1163 | ||
1164 | auto dt4 = DateTime(1999, 1, 29, 12, 33, 33); | |
1165 | dt4.roll!"months"(1, AllowDayOverflow.no); | |
1166 | assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33)); | |
1167 | ||
1168 | auto dt5 = DateTime(2000, 2, 29, 12, 30, 33); | |
1169 | dt5.roll!"years"(1); | |
1170 | assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33)); | |
1171 | ||
1172 | auto dt6 = DateTime(2000, 2, 29, 12, 30, 33); | |
1173 | dt6.roll!"years"(1, AllowDayOverflow.no); | |
1174 | assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33)); | |
1175 | } | |
1176 | ||
1177 | @safe unittest | |
1178 | { | |
1179 | auto dt = DateTime(2000, 1, 31); | |
1180 | dt.roll!"years"(7).roll!"months"(-4); | |
1181 | assert(dt == DateTime(2007, 10, 1)); | |
1182 | ||
1183 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1184 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1185 | static assert(!__traits(compiles, cdt.roll!"years"(4))); | |
1186 | static assert(!__traits(compiles, idt.roll!"years"(4))); | |
1187 | static assert(!__traits(compiles, cdt.roll!"months"(4))); | |
1188 | static assert(!__traits(compiles, idt.roll!"months"(4))); | |
1189 | } | |
1190 | ||
1191 | ||
1192 | /++ | |
5fee5ec3 IB |
1193 | Adds the given number of units to this $(LREF DateTime), mutating it. A |
1194 | negative number will subtract. | |
b4c522fa IB |
1195 | |
1196 | The difference between rolling and adding is that rolling does not | |
1197 | affect larger units. For instance, rolling a $(LREF DateTime) one | |
1198 | year's worth of days gets the exact same $(LREF DateTime). | |
1199 | ||
5fee5ec3 IB |
1200 | Accepted units are `"days"`, `"minutes"`, `"hours"`, |
1201 | `"minutes"`, and `"seconds"`. | |
b4c522fa IB |
1202 | |
1203 | Params: | |
1204 | units = The units to add. | |
1205 | value = The number of $(D_PARAM units) to add to this | |
1206 | $(LREF DateTime). | |
5fee5ec3 IB |
1207 | |
1208 | Returns: | |
1209 | A reference to the `DateTime` (`this`). | |
b4c522fa IB |
1210 | +/ |
1211 | ref DateTime roll(string units)(long value) @safe pure nothrow @nogc | |
1212 | if (units == "days") | |
1213 | { | |
1214 | _date.roll!"days"(value); | |
1215 | return this; | |
1216 | } | |
1217 | ||
1218 | /// | |
1219 | @safe unittest | |
1220 | { | |
1221 | auto dt1 = DateTime(2010, 1, 1, 11, 23, 12); | |
1222 | dt1.roll!"days"(1); | |
1223 | assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12)); | |
1224 | dt1.roll!"days"(365); | |
1225 | assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12)); | |
1226 | dt1.roll!"days"(-32); | |
1227 | assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12)); | |
1228 | ||
1229 | auto dt2 = DateTime(2010, 7, 4, 12, 0, 0); | |
1230 | dt2.roll!"hours"(1); | |
1231 | assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0)); | |
1232 | ||
1233 | auto dt3 = DateTime(2010, 1, 1, 0, 0, 0); | |
1234 | dt3.roll!"seconds"(-1); | |
1235 | assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59)); | |
1236 | } | |
1237 | ||
1238 | @safe unittest | |
1239 | { | |
1240 | auto dt = DateTime(2000, 1, 31); | |
1241 | dt.roll!"days"(7).roll!"days"(-4); | |
1242 | assert(dt == DateTime(2000, 1, 3)); | |
1243 | ||
1244 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1245 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1246 | static assert(!__traits(compiles, cdt.roll!"days"(4))); | |
1247 | static assert(!__traits(compiles, idt.roll!"days"(4))); | |
1248 | } | |
1249 | ||
1250 | ||
5fee5ec3 | 1251 | /// ditto |
b4c522fa IB |
1252 | ref DateTime roll(string units)(long value) @safe pure nothrow @nogc |
1253 | if (units == "hours" || | |
1254 | units == "minutes" || | |
1255 | units == "seconds") | |
1256 | { | |
1257 | _tod.roll!units(value); | |
1258 | return this; | |
1259 | } | |
1260 | ||
1261 | // Test roll!"hours"(). | |
1262 | @safe unittest | |
1263 | { | |
5fee5ec3 | 1264 | static void testDT(DateTime orig, int hours, DateTime expected, size_t line = __LINE__) |
b4c522fa IB |
1265 | { |
1266 | orig.roll!"hours"(hours); | |
1267 | assert(orig == expected); | |
1268 | } | |
1269 | ||
1270 | // Test A.D. | |
1271 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1272 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1273 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1274 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1275 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1276 | DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); | |
1277 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1278 | DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); | |
1279 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1280 | DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); | |
1281 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1282 | DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); | |
1283 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 6, | |
1284 | DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); | |
1285 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7, | |
1286 | DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
1287 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 8, | |
1288 | DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); | |
1289 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 9, | |
1290 | DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); | |
1291 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1292 | DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1293 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 11, | |
1294 | DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1295 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 12, | |
1296 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1297 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 13, | |
1298 | DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1299 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 14, | |
1300 | DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); | |
1301 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1302 | DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); | |
1303 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 16, | |
1304 | DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); | |
1305 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 17, | |
1306 | DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
1307 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 18, | |
1308 | DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); | |
1309 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 19, | |
1310 | DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); | |
1311 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 20, | |
1312 | DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); | |
1313 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 21, | |
1314 | DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); | |
1315 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 22, | |
1316 | DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); | |
1317 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 23, | |
1318 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1319 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 24, | |
1320 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1321 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 25, | |
1322 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1323 | ||
1324 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
1325 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1326 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
1327 | DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); | |
1328 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
1329 | DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); | |
1330 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
1331 | DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); | |
1332 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
1333 | DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); | |
1334 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -6, | |
1335 | DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); | |
1336 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -7, | |
1337 | DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
1338 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -8, | |
1339 | DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); | |
1340 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -9, | |
1341 | DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); | |
1342 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
1343 | DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); | |
1344 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -11, | |
1345 | DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1346 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -12, | |
1347 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1348 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -13, | |
1349 | DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1350 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -14, | |
1351 | DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1352 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
1353 | DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); | |
1354 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -16, | |
1355 | DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); | |
1356 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -17, | |
1357 | DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
1358 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -18, | |
1359 | DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); | |
1360 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -19, | |
1361 | DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); | |
1362 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -20, | |
1363 | DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); | |
1364 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -21, | |
1365 | DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); | |
1366 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -22, | |
1367 | DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); | |
1368 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -23, | |
1369 | DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1370 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -24, | |
1371 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1372 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -25, | |
1373 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1374 | ||
1375 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 1, | |
1376 | DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1377 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 0, | |
1378 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1379 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), -1, | |
1380 | DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1381 | ||
1382 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 1, | |
1383 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1384 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 0, | |
1385 | DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1386 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), -1, | |
1387 | DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1388 | ||
1389 | testDT(DateTime(Date(1999, 7, 31), TimeOfDay(23, 30, 33)), 1, | |
1390 | DateTime(Date(1999, 7, 31), TimeOfDay(0, 30, 33))); | |
1391 | testDT(DateTime(Date(1999, 8, 1), TimeOfDay(0, 30, 33)), -1, | |
1392 | DateTime(Date(1999, 8, 1), TimeOfDay(23, 30, 33))); | |
1393 | ||
1394 | testDT(DateTime(Date(1999, 12, 31), TimeOfDay(23, 30, 33)), 1, | |
1395 | DateTime(Date(1999, 12, 31), TimeOfDay(0, 30, 33))); | |
1396 | testDT(DateTime(Date(2000, 1, 1), TimeOfDay(0, 30, 33)), -1, | |
1397 | DateTime(Date(2000, 1, 1), TimeOfDay(23, 30, 33))); | |
1398 | ||
1399 | testDT(DateTime(Date(1999, 2, 28), TimeOfDay(23, 30, 33)), 25, | |
1400 | DateTime(Date(1999, 2, 28), TimeOfDay(0, 30, 33))); | |
1401 | testDT(DateTime(Date(1999, 3, 2), TimeOfDay(0, 30, 33)), -25, | |
1402 | DateTime(Date(1999, 3, 2), TimeOfDay(23, 30, 33))); | |
1403 | ||
1404 | testDT(DateTime(Date(2000, 2, 28), TimeOfDay(23, 30, 33)), 25, | |
1405 | DateTime(Date(2000, 2, 28), TimeOfDay(0, 30, 33))); | |
1406 | testDT(DateTime(Date(2000, 3, 1), TimeOfDay(0, 30, 33)), -25, | |
1407 | DateTime(Date(2000, 3, 1), TimeOfDay(23, 30, 33))); | |
1408 | ||
1409 | // Test B.C. | |
1410 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1411 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1412 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1413 | DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1414 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1415 | DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); | |
1416 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1417 | DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); | |
1418 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1419 | DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); | |
1420 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1421 | DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); | |
1422 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 6, | |
1423 | DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); | |
1424 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7, | |
1425 | DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); | |
1426 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 8, | |
1427 | DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); | |
1428 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 9, | |
1429 | DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); | |
1430 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1431 | DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1432 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 11, | |
1433 | DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1434 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 12, | |
1435 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1436 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 13, | |
1437 | DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1438 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 14, | |
1439 | DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); | |
1440 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1441 | DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); | |
1442 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 16, | |
1443 | DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); | |
1444 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 17, | |
1445 | DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); | |
1446 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 18, | |
1447 | DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); | |
1448 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 19, | |
1449 | DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); | |
1450 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 20, | |
1451 | DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); | |
1452 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 21, | |
1453 | DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); | |
1454 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 22, | |
1455 | DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); | |
1456 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 23, | |
1457 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1458 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 24, | |
1459 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1460 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 25, | |
1461 | DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1462 | ||
1463 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
1464 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1465 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
1466 | DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); | |
1467 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
1468 | DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); | |
1469 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
1470 | DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); | |
1471 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
1472 | DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); | |
1473 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -6, | |
1474 | DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); | |
1475 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -7, | |
1476 | DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); | |
1477 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -8, | |
1478 | DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); | |
1479 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -9, | |
1480 | DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); | |
1481 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
1482 | DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); | |
1483 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -11, | |
1484 | DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1485 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -12, | |
1486 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1487 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -13, | |
1488 | DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1489 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -14, | |
1490 | DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1491 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
1492 | DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); | |
1493 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -16, | |
1494 | DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); | |
1495 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -17, | |
1496 | DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); | |
1497 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -18, | |
1498 | DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); | |
1499 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -19, | |
1500 | DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); | |
1501 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -20, | |
1502 | DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); | |
1503 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -21, | |
1504 | DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); | |
1505 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -22, | |
1506 | DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); | |
1507 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -23, | |
1508 | DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); | |
1509 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -24, | |
1510 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1511 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -25, | |
1512 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); | |
1513 | ||
1514 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 1, | |
1515 | DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); | |
1516 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 0, | |
1517 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1518 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), -1, | |
1519 | DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1520 | ||
1521 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 1, | |
1522 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); | |
1523 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 0, | |
1524 | DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); | |
1525 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), -1, | |
1526 | DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); | |
1527 | ||
1528 | testDT(DateTime(Date(-1999, 7, 31), TimeOfDay(23, 30, 33)), 1, | |
1529 | DateTime(Date(-1999, 7, 31), TimeOfDay(0, 30, 33))); | |
1530 | testDT(DateTime(Date(-1999, 8, 1), TimeOfDay(0, 30, 33)), -1, | |
1531 | DateTime(Date(-1999, 8, 1), TimeOfDay(23, 30, 33))); | |
1532 | ||
1533 | testDT(DateTime(Date(-2001, 12, 31), TimeOfDay(23, 30, 33)), 1, | |
1534 | DateTime(Date(-2001, 12, 31), TimeOfDay(0, 30, 33))); | |
1535 | testDT(DateTime(Date(-2000, 1, 1), TimeOfDay(0, 30, 33)), -1, | |
1536 | DateTime(Date(-2000, 1, 1), TimeOfDay(23, 30, 33))); | |
1537 | ||
1538 | testDT(DateTime(Date(-2001, 2, 28), TimeOfDay(23, 30, 33)), 25, | |
1539 | DateTime(Date(-2001, 2, 28), TimeOfDay(0, 30, 33))); | |
1540 | testDT(DateTime(Date(-2001, 3, 2), TimeOfDay(0, 30, 33)), -25, | |
1541 | DateTime(Date(-2001, 3, 2), TimeOfDay(23, 30, 33))); | |
1542 | ||
1543 | testDT(DateTime(Date(-2000, 2, 28), TimeOfDay(23, 30, 33)), 25, | |
1544 | DateTime(Date(-2000, 2, 28), TimeOfDay(0, 30, 33))); | |
1545 | testDT(DateTime(Date(-2000, 3, 1), TimeOfDay(0, 30, 33)), -25, | |
1546 | DateTime(Date(-2000, 3, 1), TimeOfDay(23, 30, 33))); | |
1547 | ||
1548 | // Test Both | |
1549 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 17_546, | |
1550 | DateTime(Date(-1, 1, 1), TimeOfDay(13, 30, 33))); | |
1551 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -17_546, | |
1552 | DateTime(Date(1, 1, 1), TimeOfDay(11, 30, 33))); | |
1553 | ||
1554 | auto dt = DateTime(2000, 1, 31, 9, 7, 6); | |
1555 | dt.roll!"hours"(27).roll!"hours"(-9); | |
1556 | assert(dt == DateTime(2000, 1, 31, 3, 7, 6)); | |
1557 | ||
1558 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1559 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1560 | static assert(!__traits(compiles, cdt.roll!"hours"(4))); | |
1561 | static assert(!__traits(compiles, idt.roll!"hours"(4))); | |
1562 | } | |
1563 | ||
1564 | // Test roll!"minutes"(). | |
1565 | @safe unittest | |
1566 | { | |
5fee5ec3 | 1567 | static void testDT(DateTime orig, int minutes, DateTime expected, size_t line = __LINE__) |
b4c522fa IB |
1568 | { |
1569 | orig.roll!"minutes"(minutes); | |
1570 | assert(orig == expected); | |
1571 | } | |
1572 | ||
1573 | // Test A.D. | |
1574 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1575 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1576 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1577 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1578 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1579 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 32, 33))); | |
1580 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1581 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 33))); | |
1582 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1583 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 34, 33))); | |
1584 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1585 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 35, 33))); | |
1586 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1587 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 40, 33))); | |
1588 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1589 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1590 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 29, | |
1591 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1592 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, | |
1593 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1594 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 45, | |
1595 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1596 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, | |
1597 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1598 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 75, | |
1599 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1600 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 90, | |
1601 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1602 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 100, | |
1603 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 10, 33))); | |
1604 | ||
1605 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 689, | |
1606 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1607 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 690, | |
1608 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1609 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 691, | |
1610 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1611 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 960, | |
1612 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1613 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, | |
1614 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1615 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, | |
1616 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1617 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, | |
1618 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1619 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, | |
1620 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1621 | ||
1622 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
1623 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1624 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
1625 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 28, 33))); | |
1626 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
1627 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 27, 33))); | |
1628 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
1629 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 26, 33))); | |
1630 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
1631 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 25, 33))); | |
1632 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
1633 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 20, 33))); | |
1634 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
1635 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1636 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -29, | |
1637 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1638 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -30, | |
1639 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1640 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -45, | |
1641 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1642 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, | |
1643 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1644 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -75, | |
1645 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1646 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -90, | |
1647 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1648 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -100, | |
1649 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 50, 33))); | |
1650 | ||
1651 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -749, | |
1652 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1653 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -750, | |
1654 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1655 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -751, | |
1656 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1657 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -960, | |
1658 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1659 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, | |
1660 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1661 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, | |
1662 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1663 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, | |
1664 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1665 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, | |
1666 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1667 | ||
1668 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 1, | |
1669 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1670 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 0, | |
1671 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1672 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), -1, | |
1673 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1674 | ||
1675 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 1, | |
1676 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 0, 33))); | |
1677 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 0, | |
1678 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33))); | |
1679 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), -1, | |
1680 | DateTime(Date(1999, 7, 6), TimeOfDay(11, 58, 33))); | |
1681 | ||
1682 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 1, | |
1683 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 1, 33))); | |
1684 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 0, | |
1685 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))); | |
1686 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), -1, | |
1687 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 59, 33))); | |
1688 | ||
1689 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 1, | |
1690 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 0, 33))); | |
1691 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 0, | |
1692 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33))); | |
1693 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), -1, | |
1694 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 58, 33))); | |
1695 | ||
1696 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 1, | |
1697 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 0, 33))); | |
1698 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 0, | |
1699 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33))); | |
1700 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), -1, | |
1701 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 58, 33))); | |
1702 | ||
1703 | // Test B.C. | |
1704 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1705 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1706 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1707 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1708 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1709 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 32, 33))); | |
1710 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1711 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 33, 33))); | |
1712 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1713 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 34, 33))); | |
1714 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1715 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 35, 33))); | |
1716 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1717 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 40, 33))); | |
1718 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1719 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1720 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 29, | |
1721 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1722 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, | |
1723 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1724 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 45, | |
1725 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1726 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, | |
1727 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1728 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 75, | |
1729 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1730 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 90, | |
1731 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1732 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 100, | |
1733 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 10, 33))); | |
1734 | ||
1735 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 689, | |
1736 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1737 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 690, | |
1738 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1739 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 691, | |
1740 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1741 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 960, | |
1742 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1743 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, | |
1744 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1745 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, | |
1746 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1747 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, | |
1748 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1749 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, | |
1750 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1751 | ||
1752 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
1753 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1754 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
1755 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 28, 33))); | |
1756 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
1757 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 27, 33))); | |
1758 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
1759 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 26, 33))); | |
1760 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
1761 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 25, 33))); | |
1762 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
1763 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 20, 33))); | |
1764 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
1765 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1766 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -29, | |
1767 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1768 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -30, | |
1769 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1770 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -45, | |
1771 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); | |
1772 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, | |
1773 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1774 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -75, | |
1775 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); | |
1776 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -90, | |
1777 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1778 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -100, | |
1779 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 50, 33))); | |
1780 | ||
1781 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -749, | |
1782 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1783 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -750, | |
1784 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1785 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -751, | |
1786 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1787 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -960, | |
1788 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1789 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, | |
1790 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); | |
1791 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, | |
1792 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1793 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, | |
1794 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); | |
1795 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, | |
1796 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1797 | ||
1798 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 1, | |
1799 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); | |
1800 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 0, | |
1801 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); | |
1802 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), -1, | |
1803 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); | |
1804 | ||
1805 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 1, | |
1806 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 0, 33))); | |
1807 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 0, | |
1808 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33))); | |
1809 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), -1, | |
1810 | DateTime(Date(-1999, 7, 6), TimeOfDay(11, 58, 33))); | |
1811 | ||
1812 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 1, | |
1813 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 1, 33))); | |
1814 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 0, | |
1815 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33))); | |
1816 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), -1, | |
1817 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 59, 33))); | |
1818 | ||
1819 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 1, | |
1820 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 0, 33))); | |
1821 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 0, | |
1822 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33))); | |
1823 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), -1, | |
1824 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 58, 33))); | |
1825 | ||
1826 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 1, | |
1827 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 0, 33))); | |
1828 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 0, | |
1829 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33))); | |
1830 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), -1, | |
1831 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 58, 33))); | |
1832 | ||
1833 | // Test Both | |
1834 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, | |
1835 | DateTime(Date(1, 1, 1), TimeOfDay(0, 59, 0))); | |
1836 | testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)), 1, | |
1837 | DateTime(Date(0, 12, 31), TimeOfDay(23, 0, 0))); | |
1838 | ||
1839 | testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, | |
1840 | DateTime(Date(0, 1, 1), TimeOfDay(0, 59, 0))); | |
1841 | testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)), 1, | |
1842 | DateTime(Date(-1, 12, 31), TimeOfDay(23, 0, 0))); | |
1843 | ||
1844 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_760, | |
1845 | DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); | |
1846 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -1_052_760, | |
1847 | DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); | |
1848 | ||
1849 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_782, | |
1850 | DateTime(Date(-1, 1, 1), TimeOfDay(11, 52, 33))); | |
1851 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 52, 33)), -1_052_782, | |
1852 | DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); | |
1853 | ||
1854 | auto dt = DateTime(2000, 1, 31, 9, 7, 6); | |
1855 | dt.roll!"minutes"(92).roll!"minutes"(-292); | |
1856 | assert(dt == DateTime(2000, 1, 31, 9, 47, 6)); | |
1857 | ||
1858 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
1859 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
1860 | static assert(!__traits(compiles, cdt.roll!"minutes"(4))); | |
1861 | static assert(!__traits(compiles, idt.roll!"minutes"(4))); | |
1862 | } | |
1863 | ||
1864 | // Test roll!"seconds"(). | |
1865 | @safe unittest | |
1866 | { | |
5fee5ec3 | 1867 | static void testDT(DateTime orig, int seconds, DateTime expected, size_t line = __LINE__) |
b4c522fa IB |
1868 | { |
1869 | orig.roll!"seconds"(seconds); | |
1870 | assert(orig == expected); | |
1871 | } | |
1872 | ||
1873 | // Test A.D. | |
1874 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1875 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1876 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1877 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); | |
1878 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1879 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 35))); | |
1880 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1881 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 36))); | |
1882 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1883 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 37))); | |
1884 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1885 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 38))); | |
1886 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1887 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 43))); | |
1888 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1889 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 48))); | |
1890 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 26, | |
1891 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); | |
1892 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 27, | |
1893 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); | |
1894 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, | |
1895 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 3))); | |
1896 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 59, | |
1897 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); | |
1898 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, | |
1899 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1900 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 61, | |
1901 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); | |
1902 | ||
1903 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, | |
1904 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); | |
1905 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, | |
1906 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); | |
1907 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, | |
1908 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); | |
1909 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, | |
1910 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); | |
1911 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, | |
1912 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); | |
1913 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, | |
1914 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1915 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, | |
1916 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); | |
1917 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, | |
1918 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1919 | ||
1920 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
1921 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); | |
1922 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
1923 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 31))); | |
1924 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
1925 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 30))); | |
1926 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
1927 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 29))); | |
1928 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
1929 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 28))); | |
1930 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
1931 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 23))); | |
1932 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
1933 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 18))); | |
1934 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -33, | |
1935 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); | |
1936 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -34, | |
1937 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); | |
1938 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -35, | |
1939 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 58))); | |
1940 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -59, | |
1941 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); | |
1942 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, | |
1943 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1944 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -61, | |
1945 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); | |
1946 | ||
1947 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 1, | |
1948 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); | |
1949 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 0, | |
1950 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); | |
1951 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), -1, | |
1952 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); | |
1953 | ||
1954 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 1, | |
1955 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 1))); | |
1956 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 0, | |
1957 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))); | |
1958 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), -1, | |
1959 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 59))); | |
1960 | ||
1961 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 1, | |
1962 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 1))); | |
1963 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 0, | |
1964 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))); | |
1965 | testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), -1, | |
1966 | DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 59))); | |
1967 | ||
1968 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 1, | |
1969 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 0))); | |
1970 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 0, | |
1971 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59))); | |
1972 | testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), -1, | |
1973 | DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 58))); | |
1974 | ||
1975 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 1, | |
1976 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 0))); | |
1977 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 0, | |
1978 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59))); | |
1979 | testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), -1, | |
1980 | DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 58))); | |
1981 | ||
1982 | // Test B.C. | |
1983 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, | |
1984 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
1985 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, | |
1986 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); | |
1987 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, | |
1988 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 35))); | |
1989 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, | |
1990 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 36))); | |
1991 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, | |
1992 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 37))); | |
1993 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, | |
1994 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 38))); | |
1995 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, | |
1996 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 43))); | |
1997 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, | |
1998 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 48))); | |
1999 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 26, | |
2000 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); | |
2001 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 27, | |
2002 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); | |
2003 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, | |
2004 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 3))); | |
2005 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 59, | |
2006 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); | |
2007 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, | |
2008 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
2009 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 61, | |
2010 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); | |
2011 | ||
2012 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, | |
2013 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); | |
2014 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, | |
2015 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); | |
2016 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, | |
2017 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); | |
2018 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, | |
2019 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); | |
2020 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, | |
2021 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); | |
2022 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, | |
2023 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
2024 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, | |
2025 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); | |
2026 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, | |
2027 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
2028 | ||
2029 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, | |
2030 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); | |
2031 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, | |
2032 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 31))); | |
2033 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, | |
2034 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 30))); | |
2035 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, | |
2036 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 29))); | |
2037 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, | |
2038 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 28))); | |
2039 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, | |
2040 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 23))); | |
2041 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, | |
2042 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 18))); | |
2043 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -33, | |
2044 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); | |
2045 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -34, | |
2046 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); | |
2047 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -35, | |
2048 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 58))); | |
2049 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -59, | |
2050 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); | |
2051 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, | |
2052 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
2053 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -61, | |
2054 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); | |
2055 | ||
2056 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 1, | |
2057 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); | |
2058 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 0, | |
2059 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); | |
2060 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), -1, | |
2061 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); | |
2062 | ||
2063 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 1, | |
2064 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 1))); | |
2065 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 0, | |
2066 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0))); | |
2067 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), -1, | |
2068 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 59))); | |
2069 | ||
2070 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 1, | |
2071 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 1))); | |
2072 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 0, | |
2073 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0))); | |
2074 | testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), -1, | |
2075 | DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 59))); | |
2076 | ||
2077 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 1, | |
2078 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 0))); | |
2079 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 0, | |
2080 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59))); | |
2081 | testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), -1, | |
2082 | DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 58))); | |
2083 | ||
2084 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 1, | |
2085 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 0))); | |
2086 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 0, | |
2087 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59))); | |
2088 | testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), -1, | |
2089 | DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 58))); | |
2090 | ||
2091 | // Test Both | |
2092 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, | |
2093 | DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 59))); | |
2094 | testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)), 1, | |
2095 | DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0))); | |
2096 | ||
2097 | testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, | |
2098 | DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 59))); | |
2099 | testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 59)), 1, | |
2100 | DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0))); | |
2101 | ||
2102 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_600L, | |
2103 | DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); | |
2104 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -63_165_600L, | |
2105 | DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); | |
2106 | ||
2107 | testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_617L, | |
2108 | DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 50))); | |
2109 | testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 50)), -63_165_617L, | |
2110 | DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); | |
2111 | ||
2112 | auto dt = DateTime(2000, 1, 31, 9, 7, 6); | |
2113 | dt.roll!"seconds"(92).roll!"seconds"(-292); | |
2114 | assert(dt == DateTime(2000, 1, 31, 9, 7, 46)); | |
2115 | ||
2116 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
2117 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
2118 | static assert(!__traits(compiles, cdt.roll!"seconds"(4))); | |
2119 | static assert(!__traits(compiles, idt.roll!"seconds"(4))); | |
2120 | } | |
2121 | ||
2122 | ||
5fee5ec3 | 2123 | import core.time : Duration; |
b4c522fa IB |
2124 | /++ |
2125 | Gives the result of adding or subtracting a $(REF Duration, core,time) | |
2126 | from this $(LREF DateTime). | |
2127 | ||
2128 | The legal types of arithmetic for $(LREF DateTime) using this operator | |
2129 | are | |
2130 | ||
2131 | $(BOOKTABLE, | |
2132 | $(TR $(TD DateTime) $(TD +) $(TD Duration) $(TD -->) $(TD DateTime)) | |
2133 | $(TR $(TD DateTime) $(TD -) $(TD Duration) $(TD -->) $(TD DateTime)) | |
2134 | ) | |
2135 | ||
2136 | Params: | |
2137 | duration = The $(REF Duration, core,time) to add to or subtract from | |
2138 | this $(LREF DateTime). | |
2139 | +/ | |
2140 | DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc | |
2141 | if (op == "+" || op == "-") | |
2142 | { | |
2143 | DateTime retval = this; | |
2144 | immutable seconds = duration.total!"seconds"; | |
2145 | mixin("return retval._addSeconds(" ~ op ~ "seconds);"); | |
2146 | } | |
2147 | ||
2148 | /// | |
2149 | @safe unittest | |
2150 | { | |
2151 | import core.time : hours, seconds; | |
2152 | ||
2153 | assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == | |
2154 | DateTime(2016, 1, 1, 0, 0, 0)); | |
2155 | ||
2156 | assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == | |
2157 | DateTime(2016, 1, 1, 0, 59, 59)); | |
2158 | ||
2159 | assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == | |
2160 | DateTime(2015, 12, 31, 23, 59, 59)); | |
2161 | ||
2162 | assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == | |
2163 | DateTime(2015, 12, 31, 23, 59, 59)); | |
2164 | } | |
2165 | ||
2166 | @safe unittest | |
2167 | { | |
5fee5ec3 IB |
2168 | import core.time : dur; |
2169 | ||
b4c522fa IB |
2170 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); |
2171 | ||
2172 | assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); | |
2173 | assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); | |
2174 | assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); | |
2175 | assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); | |
2176 | ||
2177 | assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
2178 | assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
2179 | assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); | |
2180 | assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); | |
2181 | assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2182 | assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2183 | assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2184 | assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2185 | assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2186 | assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2187 | assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2188 | assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2189 | ||
2190 | assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); | |
2191 | assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); | |
2192 | assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); | |
2193 | assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); | |
2194 | ||
2195 | assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
2196 | assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
2197 | assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); | |
2198 | assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); | |
2199 | assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2200 | assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2201 | assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2202 | assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2203 | assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2204 | assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2205 | assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2206 | assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2207 | ||
2208 | auto duration = dur!"seconds"(12); | |
2209 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2210 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2211 | assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45)); | |
2212 | assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45)); | |
2213 | assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21)); | |
2214 | assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21)); | |
2215 | } | |
2216 | ||
b4c522fa IB |
2217 | |
2218 | /++ | |
2219 | Gives the result of adding or subtracting a duration from this | |
2220 | $(LREF DateTime), as well as assigning the result to this | |
2221 | $(LREF DateTime). | |
2222 | ||
2223 | The legal types of arithmetic for $(LREF DateTime) using this operator | |
2224 | are | |
2225 | ||
2226 | $(BOOKTABLE, | |
2227 | $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime)) | |
2228 | $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime)) | |
2229 | ) | |
2230 | ||
2231 | Params: | |
2232 | duration = The duration to add to or subtract from this | |
2233 | $(LREF DateTime). | |
2234 | +/ | |
9fa27ed0 IB |
2235 | ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc |
2236 | if (op == "+" || op == "-") | |
b4c522fa | 2237 | { |
9fa27ed0 | 2238 | import core.time : convert; |
b4c522fa IB |
2239 | import std.format : format; |
2240 | ||
2241 | DateTime retval = this; | |
9fa27ed0 | 2242 | immutable hnsecs = duration.total!"hnsecs"; |
b4c522fa IB |
2243 | |
2244 | mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op)); | |
2245 | } | |
2246 | ||
2247 | @safe unittest | |
2248 | { | |
5fee5ec3 | 2249 | import core.time : dur; |
b4c522fa IB |
2250 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == |
2251 | DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); | |
2252 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == | |
2253 | DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); | |
2254 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == | |
2255 | DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); | |
2256 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == | |
2257 | DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); | |
2258 | ||
2259 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == | |
2260 | DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
2261 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == | |
2262 | DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
2263 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == | |
2264 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); | |
2265 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == | |
2266 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); | |
2267 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == | |
2268 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2269 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == | |
2270 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2271 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == | |
2272 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2273 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == | |
2274 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2275 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == | |
2276 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2277 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == | |
2278 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2279 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == | |
2280 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2281 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == | |
2282 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2283 | ||
2284 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == | |
2285 | DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); | |
2286 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == | |
2287 | DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); | |
2288 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == | |
2289 | DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); | |
2290 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == | |
2291 | DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); | |
2292 | ||
2293 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == | |
2294 | DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); | |
2295 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == | |
2296 | DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); | |
2297 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == | |
2298 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); | |
2299 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == | |
2300 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); | |
2301 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == | |
2302 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2303 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == | |
2304 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2305 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == | |
2306 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2307 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == | |
2308 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2309 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == | |
2310 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2311 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == | |
2312 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2313 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == | |
2314 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); | |
2315 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == | |
2316 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); | |
2317 | ||
2318 | auto dt = DateTime(2000, 1, 31, 9, 7, 6); | |
2319 | (dt += dur!"seconds"(92)) -= dur!"days"(-500); | |
2320 | assert(dt == DateTime(2001, 6, 14, 9, 8, 38)); | |
2321 | ||
2322 | auto duration = dur!"seconds"(12); | |
2323 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2324 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2325 | static assert(!__traits(compiles, cdt += duration)); | |
2326 | static assert(!__traits(compiles, idt += duration)); | |
2327 | static assert(!__traits(compiles, cdt -= duration)); | |
2328 | static assert(!__traits(compiles, idt -= duration)); | |
2329 | } | |
2330 | ||
b4c522fa IB |
2331 | |
2332 | /++ | |
2333 | Gives the difference between two $(LREF DateTime)s. | |
2334 | ||
2335 | The legal types of arithmetic for $(LREF DateTime) using this operator are | |
2336 | ||
2337 | $(BOOKTABLE, | |
2338 | $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration)) | |
2339 | ) | |
2340 | +/ | |
5fee5ec3 | 2341 | Duration opBinary(string op)(DateTime rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
2342 | if (op == "-") |
2343 | { | |
2344 | immutable dateResult = _date - rhs.date; | |
2345 | immutable todResult = _tod - rhs._tod; | |
2346 | ||
5fee5ec3 | 2347 | import core.time : dur; |
b4c522fa IB |
2348 | return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs"); |
2349 | } | |
2350 | ||
2351 | @safe unittest | |
2352 | { | |
2353 | auto dt = DateTime(1999, 7, 6, 12, 30, 33); | |
2354 | ||
5fee5ec3 | 2355 | import core.time : dur; |
b4c522fa IB |
2356 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) == |
2357 | dur!"seconds"(31_536_000)); | |
2358 | assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2359 | dur!"seconds"(-31_536_000)); | |
2360 | ||
2361 | assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2362 | dur!"seconds"(26_78_400)); | |
2363 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) == | |
2364 | dur!"seconds"(-26_78_400)); | |
2365 | ||
2366 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) == | |
2367 | dur!"seconds"(86_400)); | |
2368 | assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2369 | dur!"seconds"(-86_400)); | |
2370 | ||
2371 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) == | |
2372 | dur!"seconds"(3600)); | |
2373 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2374 | dur!"seconds"(-3600)); | |
2375 | ||
2376 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2377 | dur!"seconds"(60)); | |
2378 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) == | |
2379 | dur!"seconds"(-60)); | |
2380 | ||
2381 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == | |
2382 | dur!"seconds"(1)); | |
2383 | assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) == | |
2384 | dur!"seconds"(-1)); | |
2385 | ||
2386 | assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033)); | |
2387 | assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033)); | |
2388 | assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367)); | |
2389 | assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367)); | |
2390 | ||
2391 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2392 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2393 | assert(dt - dt == Duration.zero); | |
2394 | assert(cdt - dt == Duration.zero); | |
2395 | assert(idt - dt == Duration.zero); | |
2396 | ||
2397 | assert(dt - cdt == Duration.zero); | |
2398 | assert(cdt - cdt == Duration.zero); | |
2399 | assert(idt - cdt == Duration.zero); | |
2400 | ||
2401 | assert(dt - idt == Duration.zero); | |
2402 | assert(cdt - idt == Duration.zero); | |
2403 | assert(idt - idt == Duration.zero); | |
2404 | } | |
2405 | ||
2406 | ||
2407 | /++ | |
2408 | Returns the difference between the two $(LREF DateTime)s in months. | |
2409 | ||
2410 | To get the difference in years, subtract the year property | |
2411 | of two $(LREF DateTime)s. To get the difference in days or weeks, | |
2412 | subtract the $(LREF DateTime)s themselves and use the | |
2413 | $(REF Duration, core,time) that results. Because converting between | |
2414 | months and smaller units requires a specific date (which | |
2415 | $(REF Duration, core,time)s don't have), getting the difference in | |
2416 | months requires some math using both the year and month properties, so | |
2417 | this is a convenience function for getting the difference in months. | |
2418 | ||
2419 | Note that the number of days in the months or how far into the month | |
2420 | either date is is irrelevant. It is the difference in the month property | |
2421 | combined with the difference in years * 12. So, for instance, | |
2422 | December 31st and January 1st are one month apart just as December 1st | |
2423 | and January 31st are one month apart. | |
2424 | ||
2425 | Params: | |
2426 | rhs = The $(LREF DateTime) to subtract from this one. | |
2427 | +/ | |
5fee5ec3 | 2428 | int diffMonths(DateTime rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
2429 | { |
2430 | return _date.diffMonths(rhs._date); | |
2431 | } | |
2432 | ||
2433 | /// | |
2434 | @safe unittest | |
2435 | { | |
2436 | assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( | |
2437 | DateTime(1999, 1, 31, 23, 59, 59)) == 1); | |
2438 | ||
2439 | assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( | |
2440 | DateTime(1999, 2, 1, 12, 3, 42)) == -1); | |
2441 | ||
2442 | assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( | |
2443 | DateTime(1999, 1, 1, 2, 4, 7)) == 2); | |
2444 | ||
2445 | assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( | |
2446 | DateTime(1999, 3, 31, 0, 30, 58)) == -2); | |
2447 | } | |
2448 | ||
2449 | @safe unittest | |
2450 | { | |
2451 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2452 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2453 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2454 | assert(dt.diffMonths(dt) == 0); | |
2455 | assert(cdt.diffMonths(dt) == 0); | |
2456 | assert(idt.diffMonths(dt) == 0); | |
2457 | ||
2458 | assert(dt.diffMonths(cdt) == 0); | |
2459 | assert(cdt.diffMonths(cdt) == 0); | |
2460 | assert(idt.diffMonths(cdt) == 0); | |
2461 | ||
2462 | assert(dt.diffMonths(idt) == 0); | |
2463 | assert(cdt.diffMonths(idt) == 0); | |
2464 | assert(idt.diffMonths(idt) == 0); | |
2465 | } | |
2466 | ||
2467 | ||
2468 | /++ | |
2469 | Whether this $(LREF DateTime) is in a leap year. | |
2470 | +/ | |
2471 | @property bool isLeapYear() const @safe pure nothrow @nogc | |
2472 | { | |
2473 | return _date.isLeapYear; | |
2474 | } | |
2475 | ||
2476 | @safe unittest | |
2477 | { | |
2478 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2479 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2480 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2481 | assert(!dt.isLeapYear); | |
2482 | assert(!cdt.isLeapYear); | |
2483 | assert(!idt.isLeapYear); | |
2484 | } | |
2485 | ||
2486 | ||
2487 | /++ | |
2488 | Day of the week this $(LREF DateTime) is on. | |
2489 | +/ | |
2490 | @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc | |
2491 | { | |
2492 | return _date.dayOfWeek; | |
2493 | } | |
2494 | ||
2495 | @safe unittest | |
2496 | { | |
2497 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2498 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2499 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2500 | assert(dt.dayOfWeek == DayOfWeek.tue); | |
2501 | assert(cdt.dayOfWeek == DayOfWeek.tue); | |
2502 | assert(idt.dayOfWeek == DayOfWeek.tue); | |
2503 | } | |
2504 | ||
2505 | ||
2506 | /++ | |
2507 | Day of the year this $(LREF DateTime) is on. | |
2508 | +/ | |
2509 | @property ushort dayOfYear() const @safe pure nothrow @nogc | |
2510 | { | |
2511 | return _date.dayOfYear; | |
2512 | } | |
2513 | ||
2514 | /// | |
2515 | @safe unittest | |
2516 | { | |
2517 | assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); | |
2518 | assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); | |
2519 | assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); | |
2520 | } | |
2521 | ||
2522 | @safe unittest | |
2523 | { | |
2524 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2525 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2526 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2527 | assert(dt.dayOfYear == 187); | |
2528 | assert(cdt.dayOfYear == 187); | |
2529 | assert(idt.dayOfYear == 187); | |
2530 | } | |
2531 | ||
2532 | ||
2533 | /++ | |
2534 | Day of the year. | |
2535 | ||
2536 | Params: | |
2537 | day = The day of the year to set which day of the year this | |
2538 | $(LREF DateTime) is on. | |
2539 | +/ | |
2540 | @property void dayOfYear(int day) @safe pure | |
2541 | { | |
2542 | _date.dayOfYear = day; | |
2543 | } | |
2544 | ||
2545 | @safe unittest | |
2546 | { | |
2547 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2548 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2549 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2550 | dt.dayOfYear = 12; | |
2551 | assert(dt.dayOfYear == 12); | |
2552 | static assert(!__traits(compiles, cdt.dayOfYear = 12)); | |
2553 | static assert(!__traits(compiles, idt.dayOfYear = 12)); | |
2554 | } | |
2555 | ||
2556 | ||
2557 | /++ | |
2558 | The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. | |
2559 | +/ | |
2560 | @property int dayOfGregorianCal() const @safe pure nothrow @nogc | |
2561 | { | |
2562 | return _date.dayOfGregorianCal; | |
2563 | } | |
2564 | ||
2565 | /// | |
2566 | @safe unittest | |
2567 | { | |
2568 | assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); | |
2569 | assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); | |
2570 | assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); | |
2571 | ||
2572 | assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); | |
2573 | assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); | |
2574 | assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); | |
2575 | ||
2576 | assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); | |
2577 | assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); | |
2578 | } | |
2579 | ||
2580 | @safe unittest | |
2581 | { | |
2582 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2583 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2584 | assert(cdt.dayOfGregorianCal == 729_941); | |
2585 | assert(idt.dayOfGregorianCal == 729_941); | |
2586 | } | |
2587 | ||
2588 | ||
2589 | /++ | |
2590 | The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. | |
2591 | Setting this property does not affect the time portion of | |
2592 | $(LREF DateTime). | |
2593 | ||
2594 | Params: | |
2595 | days = The day of the Gregorian Calendar to set this $(LREF DateTime) | |
2596 | to. | |
2597 | +/ | |
2598 | @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc | |
2599 | { | |
2600 | _date.dayOfGregorianCal = days; | |
2601 | } | |
2602 | ||
2603 | /// | |
2604 | @safe unittest | |
2605 | { | |
2606 | auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); | |
2607 | dt.dayOfGregorianCal = 1; | |
2608 | assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); | |
2609 | ||
2610 | dt.dayOfGregorianCal = 365; | |
2611 | assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); | |
2612 | ||
2613 | dt.dayOfGregorianCal = 366; | |
2614 | assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); | |
2615 | ||
2616 | dt.dayOfGregorianCal = 0; | |
2617 | assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); | |
2618 | ||
2619 | dt.dayOfGregorianCal = -365; | |
2620 | assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); | |
2621 | ||
2622 | dt.dayOfGregorianCal = -366; | |
2623 | assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); | |
2624 | ||
2625 | dt.dayOfGregorianCal = 730_120; | |
2626 | assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); | |
2627 | ||
2628 | dt.dayOfGregorianCal = 734_137; | |
2629 | assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); | |
2630 | } | |
2631 | ||
2632 | @safe unittest | |
2633 | { | |
2634 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2635 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2636 | static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7)); | |
2637 | static assert(!__traits(compiles, idt.dayOfGregorianCal = 7)); | |
2638 | } | |
2639 | ||
2640 | ||
2641 | /++ | |
2642 | The ISO 8601 week of the year that this $(LREF DateTime) is in. | |
2643 | ||
2644 | See_Also: | |
2645 | $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) | |
2646 | +/ | |
2647 | @property ubyte isoWeek() const @safe pure nothrow | |
2648 | { | |
2649 | return _date.isoWeek; | |
2650 | } | |
2651 | ||
2652 | @safe unittest | |
2653 | { | |
2654 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2655 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2656 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2657 | assert(dt.isoWeek == 27); | |
2658 | assert(cdt.isoWeek == 27); | |
2659 | assert(idt.isoWeek == 27); | |
2660 | } | |
2661 | ||
2662 | ||
5fee5ec3 IB |
2663 | /++ |
2664 | The year of the ISO 8601 week calendar that this $(LREF DateTime) is in. | |
2665 | ||
2666 | See_Also: | |
2667 | $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) | |
2668 | +/ | |
2669 | @property short isoWeekYear() const @safe pure nothrow | |
2670 | { | |
2671 | return _date.isoWeekYear; | |
2672 | } | |
2673 | ||
2674 | ||
b4c522fa IB |
2675 | /++ |
2676 | $(LREF DateTime) for the last day in the month that this | |
2677 | $(LREF DateTime) is in. The time portion of endOfMonth is always | |
2678 | 23:59:59. | |
2679 | +/ | |
2680 | @property DateTime endOfMonth() const @safe pure nothrow | |
2681 | { | |
2682 | try | |
2683 | return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59)); | |
2684 | catch (Exception e) | |
2685 | assert(0, "DateTime constructor threw."); | |
2686 | } | |
2687 | ||
2688 | /// | |
2689 | @safe unittest | |
2690 | { | |
2691 | assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == | |
2692 | DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); | |
2693 | ||
2694 | assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == | |
2695 | DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); | |
2696 | ||
2697 | assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == | |
2698 | DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); | |
2699 | ||
2700 | assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == | |
2701 | DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); | |
2702 | } | |
2703 | ||
2704 | @safe unittest | |
2705 | { | |
2706 | // Test A.D. | |
2707 | assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59)); | |
2708 | assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59)); | |
2709 | assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59)); | |
2710 | assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59)); | |
2711 | assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59)); | |
2712 | assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59)); | |
2713 | assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59)); | |
2714 | assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); | |
2715 | assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59)); | |
2716 | assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59)); | |
2717 | assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59)); | |
2718 | assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59)); | |
2719 | assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59)); | |
2720 | ||
2721 | // Test B.C. | |
2722 | assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59)); | |
2723 | assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59)); | |
2724 | assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59)); | |
2725 | assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59)); | |
2726 | assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59)); | |
2727 | assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59)); | |
2728 | assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59)); | |
2729 | assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59)); | |
2730 | assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59)); | |
2731 | assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59)); | |
2732 | assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59)); | |
2733 | assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59)); | |
2734 | assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59)); | |
2735 | ||
2736 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2737 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2738 | assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); | |
2739 | assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); | |
2740 | } | |
2741 | ||
2742 | ||
2743 | /++ | |
2744 | The last day in the month that this $(LREF DateTime) is in. | |
2745 | +/ | |
2746 | @property ubyte daysInMonth() const @safe pure nothrow @nogc | |
2747 | { | |
2748 | return _date.daysInMonth; | |
2749 | } | |
2750 | ||
2751 | /// | |
2752 | @safe unittest | |
2753 | { | |
2754 | assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); | |
2755 | assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); | |
2756 | assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); | |
2757 | assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); | |
2758 | } | |
2759 | ||
2760 | @safe unittest | |
2761 | { | |
2762 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2763 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2764 | assert(cdt.daysInMonth == 31); | |
2765 | assert(idt.daysInMonth == 31); | |
2766 | } | |
2767 | ||
2768 | ||
2769 | /++ | |
2770 | Whether the current year is a date in A.D. | |
2771 | +/ | |
2772 | @property bool isAD() const @safe pure nothrow @nogc | |
2773 | { | |
2774 | return _date.isAD; | |
2775 | } | |
2776 | ||
2777 | /// | |
2778 | @safe unittest | |
2779 | { | |
2780 | assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); | |
2781 | assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); | |
2782 | assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); | |
2783 | assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); | |
2784 | } | |
2785 | ||
2786 | @safe unittest | |
2787 | { | |
2788 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2789 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2790 | assert(cdt.isAD); | |
2791 | assert(idt.isAD); | |
2792 | } | |
2793 | ||
2794 | ||
2795 | /++ | |
2796 | The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this | |
2797 | $(LREF DateTime) at the given time. For example, prior to noon, | |
2798 | 1996-03-31 would be the Julian day number 2_450_173, so this function | |
2799 | returns 2_450_173, while from noon onward, the julian day number would | |
2800 | be 2_450_174, so this function returns 2_450_174. | |
2801 | +/ | |
2802 | @property long julianDay() const @safe pure nothrow @nogc | |
2803 | { | |
2804 | if (_tod._hour < 12) | |
2805 | return _date.julianDay - 1; | |
2806 | else | |
2807 | return _date.julianDay; | |
2808 | } | |
2809 | ||
2810 | @safe unittest | |
2811 | { | |
2812 | assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1); | |
2813 | assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0); | |
2814 | ||
2815 | assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424); | |
2816 | assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425); | |
2817 | ||
2818 | assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425); | |
2819 | assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426); | |
2820 | ||
2821 | assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160); | |
2822 | assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161); | |
2823 | ||
2824 | assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000); | |
2825 | assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001); | |
2826 | ||
2827 | assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973); | |
2828 | assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974); | |
2829 | ||
2830 | assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173); | |
2831 | assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174); | |
2832 | ||
2833 | assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432); | |
2834 | assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433); | |
2835 | ||
2836 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2837 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2838 | assert(cdt.julianDay == 2_451_366); | |
2839 | assert(idt.julianDay == 2_451_366); | |
2840 | } | |
2841 | ||
2842 | ||
2843 | /++ | |
2844 | The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any | |
2845 | time on this date (since, the modified Julian day changes at midnight). | |
2846 | +/ | |
2847 | @property long modJulianDay() const @safe pure nothrow @nogc | |
2848 | { | |
2849 | return _date.modJulianDay; | |
2850 | } | |
2851 | ||
2852 | @safe unittest | |
2853 | { | |
2854 | assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0); | |
2855 | assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0); | |
2856 | ||
2857 | assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432); | |
2858 | assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432); | |
2859 | ||
2860 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2861 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
2862 | assert(cdt.modJulianDay == 51_365); | |
2863 | assert(idt.modJulianDay == 51_365); | |
2864 | } | |
2865 | ||
2866 | ||
2867 | /++ | |
5fee5ec3 IB |
2868 | Converts this $(LREF DateTime) to a string with the format `YYYYMMDDTHHMMSS`. |
2869 | If `writer` is set, the resulting string will be written directly to it. | |
2870 | ||
2871 | Params: | |
2872 | writer = A `char` accepting | |
2873 | $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
2874 | Returns: | |
2875 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
2876 | +/ |
2877 | string toISOString() const @safe pure nothrow | |
2878 | { | |
5fee5ec3 IB |
2879 | import std.array : appender; |
2880 | auto w = appender!string(); | |
2881 | w.reserve(18); | |
b4c522fa | 2882 | try |
5fee5ec3 | 2883 | toISOString(w); |
b4c522fa | 2884 | catch (Exception e) |
5fee5ec3 IB |
2885 | assert(0, "toISOString() threw."); |
2886 | return w.data; | |
2887 | } | |
2888 | ||
2889 | /// ditto | |
2890 | void toISOString(W)(ref W writer) const | |
2891 | if (isOutputRange!(W, char)) | |
2892 | { | |
2893 | import std.format.write : formattedWrite; | |
2894 | _date.toISOString(writer); | |
2895 | formattedWrite!("T%02d%02d%02d")( | |
2896 | writer, | |
2897 | _tod._hour, | |
2898 | _tod._minute, | |
2899 | _tod._second | |
2900 | ); | |
b4c522fa IB |
2901 | } |
2902 | ||
2903 | /// | |
2904 | @safe unittest | |
2905 | { | |
2906 | assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == | |
2907 | "20100704T070612"); | |
2908 | ||
2909 | assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == | |
2910 | "19981225T021500"); | |
2911 | ||
2912 | assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == | |
2913 | "00000105T230959"); | |
2914 | ||
2915 | assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == | |
2916 | "-00040105T000002"); | |
2917 | } | |
2918 | ||
2919 | @safe unittest | |
2920 | { | |
2921 | // Test A.D. | |
2922 | assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000"); | |
2923 | assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612"); | |
2924 | assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459"); | |
2925 | assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959"); | |
2926 | assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101"); | |
2927 | ||
2928 | // Test B.C. | |
2929 | assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204"); | |
2930 | assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000"); | |
2931 | assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612"); | |
2932 | assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459"); | |
2933 | assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959"); | |
2934 | assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101"); | |
2935 | ||
2936 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
2937 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
2938 | assert(cdt.toISOString() == "19990706T123033"); | |
2939 | assert(idt.toISOString() == "19990706T123033"); | |
2940 | } | |
2941 | ||
2942 | ||
2943 | /++ | |
2944 | Converts this $(LREF DateTime) to a string with the format | |
5fee5ec3 IB |
2945 | `YYYY-MM-DDTHH:MM:SS`. If `writer` is set, the resulting |
2946 | string will be written directly to it. | |
2947 | ||
2948 | Params: | |
2949 | writer = A `char` accepting | |
2950 | $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
2951 | Returns: | |
2952 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
2953 | +/ |
2954 | string toISOExtString() const @safe pure nothrow | |
2955 | { | |
5fee5ec3 IB |
2956 | import std.array : appender; |
2957 | auto w = appender!string(); | |
2958 | w.reserve(20); | |
b4c522fa | 2959 | try |
5fee5ec3 | 2960 | toISOExtString(w); |
b4c522fa | 2961 | catch (Exception e) |
5fee5ec3 IB |
2962 | assert(0, "toISOExtString() threw."); |
2963 | return w.data; | |
2964 | } | |
2965 | ||
2966 | /// ditto | |
2967 | void toISOExtString(W)(ref W writer) const | |
2968 | if (isOutputRange!(W, char)) | |
2969 | { | |
2970 | import std.format.write : formattedWrite; | |
2971 | _date.toISOExtString(writer); | |
2972 | formattedWrite!("T%02d:%02d:%02d")( | |
2973 | writer, | |
2974 | _tod._hour, | |
2975 | _tod._minute, | |
2976 | _tod._second | |
2977 | ); | |
b4c522fa IB |
2978 | } |
2979 | ||
2980 | /// | |
2981 | @safe unittest | |
2982 | { | |
2983 | assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == | |
2984 | "2010-07-04T07:06:12"); | |
2985 | ||
2986 | assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == | |
2987 | "1998-12-25T02:15:00"); | |
2988 | ||
2989 | assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == | |
2990 | "0000-01-05T23:09:59"); | |
2991 | ||
2992 | assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == | |
2993 | "-0004-01-05T00:00:02"); | |
2994 | } | |
2995 | ||
2996 | @safe unittest | |
2997 | { | |
2998 | // Test A.D. | |
2999 | assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); | |
3000 | assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); | |
3001 | assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); | |
3002 | assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); | |
3003 | assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); | |
3004 | ||
3005 | // Test B.C. | |
3006 | assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); | |
3007 | assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); | |
3008 | assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); | |
3009 | assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); | |
3010 | assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); | |
3011 | assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); | |
3012 | ||
3013 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
3014 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
3015 | assert(cdt.toISOExtString() == "1999-07-06T12:30:33"); | |
3016 | assert(idt.toISOExtString() == "1999-07-06T12:30:33"); | |
3017 | } | |
3018 | ||
3019 | /++ | |
3020 | Converts this $(LREF DateTime) to a string with the format | |
5fee5ec3 IB |
3021 | `YYYY-Mon-DD HH:MM:SS`. If `writer` is set, the resulting |
3022 | string will be written directly to it. | |
3023 | ||
3024 | Params: | |
3025 | writer = A `char` accepting | |
3026 | $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
3027 | Returns: | |
3028 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
3029 | +/ |
3030 | string toSimpleString() const @safe pure nothrow | |
3031 | { | |
5fee5ec3 IB |
3032 | import std.array : appender; |
3033 | auto w = appender!string(); | |
3034 | w.reserve(22); | |
b4c522fa | 3035 | try |
5fee5ec3 | 3036 | toSimpleString(w); |
b4c522fa | 3037 | catch (Exception e) |
5fee5ec3 IB |
3038 | assert(0, "toSimpleString() threw."); |
3039 | return w.data; | |
3040 | } | |
3041 | ||
3042 | /// ditto | |
3043 | void toSimpleString(W)(ref W writer) const | |
3044 | if (isOutputRange!(W, char)) | |
3045 | { | |
3046 | import std.format.write : formattedWrite; | |
3047 | _date.toSimpleString(writer); | |
3048 | formattedWrite!(" %02d:%02d:%02d")( | |
3049 | writer, | |
3050 | _tod._hour, | |
3051 | _tod._minute, | |
3052 | _tod._second | |
3053 | ); | |
b4c522fa IB |
3054 | } |
3055 | ||
3056 | /// | |
3057 | @safe unittest | |
3058 | { | |
3059 | assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == | |
3060 | "2010-Jul-04 07:06:12"); | |
3061 | ||
3062 | assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == | |
3063 | "1998-Dec-25 02:15:00"); | |
3064 | ||
3065 | assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == | |
3066 | "0000-Jan-05 23:09:59"); | |
3067 | ||
3068 | assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == | |
3069 | "-0004-Jan-05 00:00:02"); | |
3070 | } | |
3071 | ||
3072 | @safe unittest | |
3073 | { | |
3074 | // Test A.D. | |
3075 | assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); | |
3076 | assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); | |
3077 | assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); | |
3078 | assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); | |
3079 | assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); | |
3080 | ||
3081 | // Test B.C. | |
3082 | assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); | |
3083 | assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); | |
3084 | assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); | |
3085 | assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); | |
3086 | assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); | |
3087 | assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); | |
3088 | ||
3089 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
3090 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
3091 | assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33"); | |
3092 | assert(idt.toSimpleString() == "1999-Jul-06 12:30:33"); | |
3093 | } | |
3094 | ||
3095 | ||
3096 | /++ | |
3097 | Converts this $(LREF DateTime) to a string. | |
3098 | ||
3099 | This function exists to make it easy to convert a $(LREF DateTime) to a | |
3100 | string for code that does not care what the exact format is - just that | |
3101 | it presents the information in a clear manner. It also makes it easy to | |
3102 | simply convert a $(LREF DateTime) to a string when using functions such | |
3103 | as `to!string`, `format`, or `writeln` which use toString to convert | |
3104 | user-defined types. So, it is unlikely that much code will call | |
3105 | toString directly. | |
3106 | ||
3107 | The format of the string is purposefully unspecified, and code that | |
3108 | cares about the format of the string should use `toISOString`, | |
3109 | `toISOExtString`, `toSimpleString`, or some other custom formatting | |
3110 | function that explicitly generates the format that the code needs. The | |
3111 | reason is that the code is then clear about what format it's using, | |
3112 | making it less error-prone to maintain the code and interact with other | |
3113 | software that consumes the generated strings. It's for this same reason | |
3114 | that $(LREF DateTime) has no `fromString` function, whereas it does have | |
3115 | `fromISOString`, `fromISOExtString`, and `fromSimpleString`. | |
3116 | ||
3117 | The format returned by toString may or may not change in the future. | |
3118 | +/ | |
3119 | string toString() const @safe pure nothrow | |
3120 | { | |
3121 | return toSimpleString(); | |
3122 | } | |
3123 | ||
3124 | @safe unittest | |
3125 | { | |
3126 | auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
3127 | const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
3128 | immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); | |
3129 | assert(dt.toString()); | |
3130 | assert(cdt.toString()); | |
3131 | assert(idt.toString()); | |
3132 | } | |
3133 | ||
5fee5ec3 IB |
3134 | /// ditto |
3135 | void toString(W)(ref W writer) const | |
3136 | if (isOutputRange!(W, char)) | |
3137 | { | |
3138 | toSimpleString(writer); | |
3139 | } | |
b4c522fa IB |
3140 | |
3141 | /++ | |
3142 | Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS. | |
3143 | Whitespace is stripped from the given string. | |
3144 | ||
3145 | Params: | |
3146 | isoString = A string formatted in the ISO format for dates and times. | |
3147 | ||
3148 | Throws: | |
3149 | $(REF DateTimeException,std,datetime,date) if the given string is | |
3150 | not in the ISO format or if the resulting $(LREF DateTime) would not | |
3151 | be valid. | |
3152 | +/ | |
5fee5ec3 | 3153 | static DateTime fromISOString(S)(scope const S isoString) @safe pure |
b4c522fa IB |
3154 | if (isSomeString!S) |
3155 | { | |
3156 | import std.algorithm.searching : countUntil; | |
3157 | import std.exception : enforce; | |
3158 | import std.format : format; | |
3159 | import std.string : strip; | |
5fee5ec3 | 3160 | import std.utf : byCodeUnit; |
b4c522fa IB |
3161 | |
3162 | auto str = strip(isoString); | |
3163 | ||
3164 | enforce(str.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString))); | |
5fee5ec3 | 3165 | auto t = str.byCodeUnit.countUntil('T'); |
b4c522fa IB |
3166 | |
3167 | enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString))); | |
3168 | ||
3169 | immutable date = Date.fromISOString(str[0 .. t]); | |
3170 | immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]); | |
3171 | ||
3172 | return DateTime(date, tod); | |
3173 | } | |
3174 | ||
3175 | /// | |
3176 | @safe unittest | |
3177 | { | |
3178 | assert(DateTime.fromISOString("20100704T070612") == | |
3179 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3180 | ||
3181 | assert(DateTime.fromISOString("19981225T021500") == | |
3182 | DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); | |
3183 | ||
3184 | assert(DateTime.fromISOString("00000105T230959") == | |
3185 | DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); | |
3186 | ||
3187 | assert(DateTime.fromISOString("-00040105T000002") == | |
3188 | DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); | |
3189 | ||
3190 | assert(DateTime.fromISOString(" 20100704T070612 ") == | |
3191 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3192 | } | |
3193 | ||
3194 | @safe unittest | |
3195 | { | |
3196 | assertThrown!DateTimeException(DateTime.fromISOString("")); | |
3197 | assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); | |
3198 | assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); | |
3199 | assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); | |
3200 | assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); | |
3201 | assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); | |
3202 | ||
3203 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); | |
3204 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); | |
3205 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); | |
3206 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); | |
3207 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); | |
3208 | ||
3209 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); | |
3210 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); | |
3211 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); | |
3212 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); | |
3213 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); | |
3214 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); | |
3215 | ||
3216 | assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201")); | |
3217 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01")); | |
3218 | ||
5fee5ec3 | 3219 | assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); |
b4c522fa IB |
3220 | assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); |
3221 | assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3222 | assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3223 | assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3224 | assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3225 | assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3226 | } | |
3227 | ||
5fee5ec3 | 3228 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
3229 | @safe unittest |
3230 | { | |
3231 | import std.conv : to; | |
3232 | import std.meta : AliasSeq; | |
5fee5ec3 | 3233 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 3234 | { |
5fee5ec3 | 3235 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
3236 | assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16)); |
3237 | } | |
3238 | } | |
3239 | ||
3240 | ||
3241 | /++ | |
3242 | Creates a $(LREF DateTime) from a string with the format | |
3243 | YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string. | |
3244 | ||
3245 | Params: | |
3246 | isoExtString = A string formatted in the ISO Extended format for dates | |
3247 | and times. | |
3248 | ||
3249 | Throws: | |
3250 | $(REF DateTimeException,std,datetime,date) if the given string is | |
3251 | not in the ISO Extended format or if the resulting $(LREF DateTime) | |
3252 | would not be valid. | |
3253 | +/ | |
5fee5ec3 | 3254 | static DateTime fromISOExtString(S)(scope const S isoExtString) @safe pure |
b4c522fa IB |
3255 | if (isSomeString!(S)) |
3256 | { | |
3257 | import std.algorithm.searching : countUntil; | |
3258 | import std.exception : enforce; | |
3259 | import std.format : format; | |
3260 | import std.string : strip; | |
5fee5ec3 | 3261 | import std.utf : byCodeUnit; |
b4c522fa IB |
3262 | |
3263 | auto str = strip(isoExtString); | |
3264 | ||
3265 | enforce(str.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); | |
5fee5ec3 | 3266 | auto t = str.byCodeUnit.countUntil('T'); |
b4c522fa IB |
3267 | |
3268 | enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); | |
3269 | ||
3270 | immutable date = Date.fromISOExtString(str[0 .. t]); | |
3271 | immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); | |
3272 | ||
3273 | return DateTime(date, tod); | |
3274 | } | |
3275 | ||
3276 | /// | |
3277 | @safe unittest | |
3278 | { | |
3279 | assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == | |
3280 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3281 | ||
3282 | assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == | |
3283 | DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); | |
3284 | ||
3285 | assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == | |
3286 | DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); | |
3287 | ||
3288 | assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == | |
3289 | DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); | |
3290 | ||
3291 | assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == | |
3292 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3293 | } | |
3294 | ||
3295 | @safe unittest | |
3296 | { | |
3297 | assertThrown!DateTimeException(DateTime.fromISOExtString("")); | |
3298 | assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000")); | |
3299 | assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000")); | |
3300 | assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000")); | |
3301 | assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.")); | |
3302 | assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0")); | |
3303 | ||
3304 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00")); | |
3305 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); | |
3306 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); | |
3307 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00")); | |
3308 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.")); | |
3309 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0")); | |
3310 | ||
3311 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00")); | |
3312 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00")); | |
3313 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.")); | |
3314 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0")); | |
3315 | ||
3316 | assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201")); | |
3317 | assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01")); | |
3318 | ||
5fee5ec3 | 3319 | assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); |
b4c522fa IB |
3320 | assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); |
3321 | assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3322 | assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3323 | assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3324 | assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3325 | assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3326 | } | |
3327 | ||
5fee5ec3 | 3328 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
3329 | @safe unittest |
3330 | { | |
3331 | import std.conv : to; | |
3332 | import std.meta : AliasSeq; | |
5fee5ec3 | 3333 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 3334 | { |
5fee5ec3 | 3335 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
3336 | assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); |
3337 | } | |
3338 | } | |
3339 | ||
3340 | ||
3341 | /++ | |
3342 | Creates a $(LREF DateTime) from a string with the format | |
3343 | YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string. | |
3344 | ||
3345 | Params: | |
3346 | simpleString = A string formatted in the way that toSimpleString | |
3347 | formats dates and times. | |
3348 | ||
3349 | Throws: | |
3350 | $(REF DateTimeException,std,datetime,date) if the given string is | |
3351 | not in the correct format or if the resulting $(LREF DateTime) | |
3352 | would not be valid. | |
3353 | +/ | |
5fee5ec3 | 3354 | static DateTime fromSimpleString(S)(scope const S simpleString) @safe pure |
b4c522fa IB |
3355 | if (isSomeString!(S)) |
3356 | { | |
3357 | import std.algorithm.searching : countUntil; | |
3358 | import std.exception : enforce; | |
3359 | import std.format : format; | |
3360 | import std.string : strip; | |
5fee5ec3 | 3361 | import std.utf : byCodeUnit; |
b4c522fa IB |
3362 | |
3363 | auto str = strip(simpleString); | |
3364 | ||
3365 | enforce(str.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString))); | |
5fee5ec3 | 3366 | auto t = str.byCodeUnit.countUntil(' '); |
b4c522fa IB |
3367 | |
3368 | enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString))); | |
3369 | ||
3370 | immutable date = Date.fromSimpleString(str[0 .. t]); | |
3371 | immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); | |
3372 | ||
3373 | return DateTime(date, tod); | |
3374 | } | |
3375 | ||
3376 | /// | |
3377 | @safe unittest | |
3378 | { | |
3379 | assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == | |
3380 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3381 | assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == | |
3382 | DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); | |
3383 | assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == | |
3384 | DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); | |
3385 | assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == | |
3386 | DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); | |
3387 | assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == | |
3388 | DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); | |
3389 | } | |
3390 | ||
3391 | @safe unittest | |
3392 | { | |
3393 | assertThrown!DateTimeException(DateTime.fromISOString("")); | |
3394 | assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); | |
3395 | assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); | |
3396 | assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); | |
3397 | assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); | |
3398 | assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); | |
3399 | ||
3400 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); | |
3401 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); | |
3402 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); | |
3403 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); | |
3404 | assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); | |
3405 | ||
3406 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); | |
3407 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); | |
3408 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); | |
3409 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); | |
3410 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); | |
3411 | assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); | |
3412 | ||
3413 | assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201")); | |
3414 | assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201")); | |
3415 | ||
3416 | assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == | |
5fee5ec3 | 3417 | DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); |
b4c522fa IB |
3418 | assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == |
3419 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3420 | assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == | |
3421 | DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3422 | assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == | |
3423 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3424 | assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == | |
3425 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3426 | assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == | |
3427 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3428 | assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == | |
3429 | DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); | |
3430 | } | |
3431 | ||
5fee5ec3 | 3432 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
3433 | @safe unittest |
3434 | { | |
3435 | import std.conv : to; | |
3436 | import std.meta : AliasSeq; | |
5fee5ec3 | 3437 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 3438 | { |
5fee5ec3 | 3439 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
3440 | assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); |
3441 | } | |
3442 | } | |
3443 | ||
3444 | ||
3445 | /++ | |
3446 | Returns the $(LREF DateTime) farthest in the past which is representable | |
3447 | by $(LREF DateTime). | |
3448 | +/ | |
3449 | @property static DateTime min() @safe pure nothrow @nogc | |
3450 | out(result) | |
3451 | { | |
3452 | assert(result._date == Date.min); | |
3453 | assert(result._tod == TimeOfDay.min); | |
3454 | } | |
5fee5ec3 | 3455 | do |
b4c522fa IB |
3456 | { |
3457 | auto dt = DateTime.init; | |
3458 | dt._date._year = short.min; | |
3459 | dt._date._month = Month.jan; | |
3460 | dt._date._day = 1; | |
3461 | ||
3462 | return dt; | |
3463 | } | |
3464 | ||
3465 | @safe unittest | |
3466 | { | |
3467 | assert(DateTime.min.year < 0); | |
3468 | assert(DateTime.min < DateTime.max); | |
3469 | } | |
3470 | ||
3471 | ||
3472 | /++ | |
3473 | Returns the $(LREF DateTime) farthest in the future which is | |
3474 | representable by $(LREF DateTime). | |
3475 | +/ | |
3476 | @property static DateTime max() @safe pure nothrow @nogc | |
3477 | out(result) | |
3478 | { | |
3479 | assert(result._date == Date.max); | |
3480 | assert(result._tod == TimeOfDay.max); | |
3481 | } | |
5fee5ec3 | 3482 | do |
b4c522fa IB |
3483 | { |
3484 | auto dt = DateTime.init; | |
3485 | dt._date._year = short.max; | |
3486 | dt._date._month = Month.dec; | |
3487 | dt._date._day = 31; | |
3488 | dt._tod._hour = TimeOfDay.maxHour; | |
3489 | dt._tod._minute = TimeOfDay.maxMinute; | |
3490 | dt._tod._second = TimeOfDay.maxSecond; | |
3491 | ||
3492 | return dt; | |
3493 | } | |
3494 | ||
3495 | @safe unittest | |
3496 | { | |
3497 | assert(DateTime.max.year > 0); | |
3498 | assert(DateTime.max > DateTime.min); | |
3499 | } | |
3500 | ||
3501 | ||
3502 | private: | |
3503 | ||
3504 | /+ | |
3505 | Add seconds to the time of day. Negative values will subtract. If the | |
3506 | number of seconds overflows (or underflows), then the seconds will wrap, | |
3507 | increasing (or decreasing) the number of minutes accordingly. The | |
3508 | same goes for any larger units. | |
3509 | ||
3510 | Params: | |
3511 | seconds = The number of seconds to add to this $(LREF DateTime). | |
3512 | +/ | |
3513 | ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc | |
3514 | { | |
5fee5ec3 | 3515 | import core.time : convert; |
b4c522fa IB |
3516 | long hnsecs = convert!("seconds", "hnsecs")(seconds); |
3517 | hnsecs += convert!("hours", "hnsecs")(_tod._hour); | |
3518 | hnsecs += convert!("minutes", "hnsecs")(_tod._minute); | |
3519 | hnsecs += convert!("seconds", "hnsecs")(_tod._second); | |
3520 | ||
3521 | auto days = splitUnitsFromHNSecs!"days"(hnsecs); | |
3522 | ||
3523 | if (hnsecs < 0) | |
3524 | { | |
3525 | hnsecs += convert!("days", "hnsecs")(1); | |
3526 | --days; | |
3527 | } | |
3528 | ||
3529 | _date._addDays(days); | |
3530 | ||
3531 | immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); | |
3532 | immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); | |
3533 | immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); | |
3534 | ||
3535 | _tod._hour = cast(ubyte) newHours; | |
3536 | _tod._minute = cast(ubyte) newMinutes; | |
3537 | _tod._second = cast(ubyte) newSeconds; | |
3538 | ||
3539 | return this; | |
3540 | } | |
3541 | ||
3542 | @safe unittest | |
3543 | { | |
5fee5ec3 | 3544 | static void testDT(DateTime orig, int seconds, DateTime expected, size_t line = __LINE__) |
b4c522fa IB |
3545 | { |
3546 | orig._addSeconds(seconds); | |
3547 | assert(orig == expected); | |
3548 | } | |
3549 | ||
3550 | // Test A.D. | |
3551 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33)); | |
3552 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34)); | |
3553 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35)); | |
3554 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36)); | |
3555 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37)); | |
3556 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38)); | |
3557 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43)); | |
3558 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48)); | |
3559 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59)); | |
3560 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0)); | |
3561 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3)); | |
3562 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32)); | |
3563 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33)); | |
3564 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34)); | |
3565 | ||
3566 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59)); | |
3567 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0)); | |
3568 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1)); | |
3569 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0)); | |
3570 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32)); | |
3571 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33)); | |
3572 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34)); | |
3573 | testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33)); | |
3574 | testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3)); | |
3575 | ||
3576 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32)); | |
3577 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31)); | |
3578 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30)); | |
3579 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29)); | |
3580 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28)); | |
3581 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23)); | |
3582 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18)); | |
3583 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0)); | |
3584 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59)); | |
3585 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58)); | |
3586 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34)); | |
3587 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33)); | |
3588 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32)); | |
3589 | ||
3590 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0)); | |
3591 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59)); | |
3592 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33)); | |
3593 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32)); | |
3594 | testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59)); | |
3595 | testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57)); | |
3596 | ||
3597 | testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1)); | |
3598 | testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0)); | |
3599 | testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59)); | |
3600 | ||
3601 | testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1)); | |
3602 | testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0)); | |
3603 | testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59)); | |
3604 | ||
3605 | testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1)); | |
3606 | testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0)); | |
3607 | testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59)); | |
3608 | ||
3609 | testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0)); | |
3610 | testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59)); | |
3611 | testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58)); | |
3612 | ||
3613 | testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0)); | |
3614 | testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59)); | |
3615 | testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58)); | |
3616 | ||
3617 | testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1)); | |
3618 | testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0)); | |
3619 | testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59)); | |
3620 | ||
3621 | // Test B.C. | |
3622 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33)); | |
3623 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34)); | |
3624 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35)); | |
3625 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36)); | |
3626 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37)); | |
3627 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38)); | |
3628 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43)); | |
3629 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48)); | |
3630 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59)); | |
3631 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0)); | |
3632 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3)); | |
3633 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32)); | |
3634 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33)); | |
3635 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34)); | |
3636 | ||
3637 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59)); | |
3638 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0)); | |
3639 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1)); | |
3640 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0)); | |
3641 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32)); | |
3642 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33)); | |
3643 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34)); | |
3644 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33)); | |
3645 | testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3)); | |
3646 | ||
3647 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32)); | |
3648 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31)); | |
3649 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30)); | |
3650 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29)); | |
3651 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28)); | |
3652 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23)); | |
3653 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18)); | |
3654 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0)); | |
3655 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59)); | |
3656 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58)); | |
3657 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34)); | |
3658 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33)); | |
3659 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32)); | |
3660 | ||
3661 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0)); | |
3662 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59)); | |
3663 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33)); | |
3664 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32)); | |
3665 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59)); | |
3666 | testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33)); | |
3667 | testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57)); | |
3668 | ||
3669 | testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1)); | |
3670 | testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0)); | |
3671 | testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59)); | |
3672 | ||
3673 | testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1)); | |
3674 | testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0)); | |
3675 | testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59)); | |
3676 | ||
3677 | testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1)); | |
3678 | testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0)); | |
3679 | testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59)); | |
3680 | ||
3681 | testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0)); | |
3682 | testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59)); | |
3683 | testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58)); | |
3684 | ||
3685 | testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0)); | |
3686 | testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59)); | |
3687 | testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58)); | |
3688 | ||
3689 | testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1)); | |
3690 | testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0)); | |
3691 | testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59)); | |
3692 | ||
3693 | // Test Both | |
3694 | testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59)); | |
3695 | testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0)); | |
3696 | ||
3697 | testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59)); | |
3698 | testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0)); | |
3699 | ||
3700 | testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33)); | |
3701 | testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33)); | |
3702 | ||
3703 | testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50)); | |
3704 | testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33)); | |
3705 | ||
3706 | const cdt = DateTime(1999, 7, 6, 12, 30, 33); | |
3707 | immutable idt = DateTime(1999, 7, 6, 12, 30, 33); | |
3708 | static assert(!__traits(compiles, cdt._addSeconds(4))); | |
3709 | static assert(!__traits(compiles, idt._addSeconds(4))); | |
3710 | } | |
3711 | ||
3712 | ||
3713 | Date _date; | |
3714 | TimeOfDay _tod; | |
3715 | } | |
3716 | ||
5fee5ec3 IB |
3717 | /// |
3718 | @safe pure unittest | |
3719 | { | |
3720 | import core.time : days, seconds; | |
3721 | ||
3722 | auto dt = DateTime(2000, 6, 1, 10, 30, 0); | |
3723 | ||
3724 | assert(dt.date == Date(2000, 6, 1)); | |
3725 | assert(dt.timeOfDay == TimeOfDay(10, 30, 0)); | |
3726 | assert(dt.dayOfYear == 153); | |
3727 | assert(dt.dayOfWeek == DayOfWeek.thu); | |
3728 | ||
3729 | dt += 10.days + 100.seconds; | |
3730 | assert(dt == DateTime(2000, 6, 11, 10, 31, 40)); | |
3731 | ||
3732 | assert(dt.toISOExtString() == "2000-06-11T10:31:40"); | |
3733 | assert(dt.toISOString() == "20000611T103140"); | |
3734 | assert(dt.toSimpleString() == "2000-Jun-11 10:31:40"); | |
3735 | ||
3736 | assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); | |
3737 | assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0)); | |
3738 | assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); | |
3739 | } | |
b4c522fa IB |
3740 | |
3741 | /++ | |
3742 | Represents a date in the | |
3743 | $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic | |
3744 | Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years | |
3745 | are A.D. Non-positive years are B.C. | |
3746 | ||
5fee5ec3 | 3747 | Year, month, and day are kept separately internally so that `Date` is |
b4c522fa IB |
3748 | optimized for calendar-based operations. |
3749 | ||
5fee5ec3 | 3750 | `Date` uses the Proleptic Gregorian Calendar, so it assumes the Gregorian |
b4c522fa IB |
3751 | leap year calculations for its entire length. As per |
3752 | $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as | |
3753 | year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C. | |
3754 | as a positive integer with 1 B.C. being the year prior to 1 A.D. | |
3755 | ||
3756 | Year 0 is a leap year. | |
3757 | +/ | |
3758 | struct Date | |
3759 | { | |
3760 | public: | |
3761 | ||
3762 | /++ | |
3763 | Throws: | |
3764 | $(REF DateTimeException,std,datetime,date) if the resulting | |
3765 | $(LREF Date) would not be valid. | |
3766 | ||
3767 | Params: | |
3768 | year = Year of the Gregorian Calendar. Positive values are A.D. | |
3769 | Non-positive values are B.C. with year 0 being the year | |
3770 | prior to 1 A.D. | |
3771 | month = Month of the year (January is 1). | |
3772 | day = Day of the month. | |
3773 | +/ | |
3774 | this(int year, int month, int day) @safe pure | |
3775 | { | |
3776 | enforceValid!"months"(cast(Month) month); | |
3777 | enforceValid!"days"(year, cast(Month) month, day); | |
3778 | ||
3779 | _year = cast(short) year; | |
3780 | _month = cast(Month) month; | |
3781 | _day = cast(ubyte) day; | |
3782 | } | |
3783 | ||
3784 | @safe unittest | |
3785 | { | |
3786 | import std.exception : assertNotThrown; | |
3787 | assert(Date(1, 1, 1) == Date.init); | |
3788 | ||
5fee5ec3 | 3789 | static void testDate(Date date, int year, int month, int day) |
b4c522fa IB |
3790 | { |
3791 | assert(date._year == year); | |
3792 | assert(date._month == month); | |
3793 | assert(date._day == day); | |
3794 | } | |
3795 | ||
3796 | testDate(Date(1999, 1 , 1), 1999, Month.jan, 1); | |
3797 | testDate(Date(1999, 7 , 1), 1999, Month.jul, 1); | |
3798 | testDate(Date(1999, 7 , 6), 1999, Month.jul, 6); | |
3799 | ||
3800 | // Test A.D. | |
3801 | assertThrown!DateTimeException(Date(1, 0, 1)); | |
3802 | assertThrown!DateTimeException(Date(1, 1, 0)); | |
3803 | assertThrown!DateTimeException(Date(1999, 13, 1)); | |
3804 | assertThrown!DateTimeException(Date(1999, 1, 32)); | |
3805 | assertThrown!DateTimeException(Date(1999, 2, 29)); | |
3806 | assertThrown!DateTimeException(Date(2000, 2, 30)); | |
3807 | assertThrown!DateTimeException(Date(1999, 3, 32)); | |
3808 | assertThrown!DateTimeException(Date(1999, 4, 31)); | |
3809 | assertThrown!DateTimeException(Date(1999, 5, 32)); | |
3810 | assertThrown!DateTimeException(Date(1999, 6, 31)); | |
3811 | assertThrown!DateTimeException(Date(1999, 7, 32)); | |
3812 | assertThrown!DateTimeException(Date(1999, 8, 32)); | |
3813 | assertThrown!DateTimeException(Date(1999, 9, 31)); | |
3814 | assertThrown!DateTimeException(Date(1999, 10, 32)); | |
3815 | assertThrown!DateTimeException(Date(1999, 11, 31)); | |
3816 | assertThrown!DateTimeException(Date(1999, 12, 32)); | |
3817 | ||
3818 | assertNotThrown!DateTimeException(Date(1999, 1, 31)); | |
3819 | assertNotThrown!DateTimeException(Date(1999, 2, 28)); | |
3820 | assertNotThrown!DateTimeException(Date(2000, 2, 29)); | |
3821 | assertNotThrown!DateTimeException(Date(1999, 3, 31)); | |
3822 | assertNotThrown!DateTimeException(Date(1999, 4, 30)); | |
3823 | assertNotThrown!DateTimeException(Date(1999, 5, 31)); | |
3824 | assertNotThrown!DateTimeException(Date(1999, 6, 30)); | |
3825 | assertNotThrown!DateTimeException(Date(1999, 7, 31)); | |
3826 | assertNotThrown!DateTimeException(Date(1999, 8, 31)); | |
3827 | assertNotThrown!DateTimeException(Date(1999, 9, 30)); | |
3828 | assertNotThrown!DateTimeException(Date(1999, 10, 31)); | |
3829 | assertNotThrown!DateTimeException(Date(1999, 11, 30)); | |
3830 | assertNotThrown!DateTimeException(Date(1999, 12, 31)); | |
3831 | ||
3832 | // Test B.C. | |
3833 | assertNotThrown!DateTimeException(Date(0, 1, 1)); | |
3834 | assertNotThrown!DateTimeException(Date(-1, 1, 1)); | |
3835 | assertNotThrown!DateTimeException(Date(-1, 12, 31)); | |
3836 | assertNotThrown!DateTimeException(Date(-1, 2, 28)); | |
3837 | assertNotThrown!DateTimeException(Date(-4, 2, 29)); | |
3838 | ||
3839 | assertThrown!DateTimeException(Date(-1, 2, 29)); | |
3840 | assertThrown!DateTimeException(Date(-2, 2, 29)); | |
3841 | assertThrown!DateTimeException(Date(-3, 2, 29)); | |
3842 | } | |
3843 | ||
3844 | ||
3845 | /++ | |
3846 | Params: | |
3847 | day = The Xth day of the Gregorian Calendar that the constructed | |
3848 | $(LREF Date) will be for. | |
3849 | +/ | |
3850 | this(int day) @safe pure nothrow @nogc | |
3851 | { | |
3852 | if (day > 0) | |
3853 | { | |
3854 | int years = (day / daysIn400Years) * 400 + 1; | |
3855 | day %= daysIn400Years; | |
3856 | ||
3857 | { | |
3858 | immutable tempYears = day / daysIn100Years; | |
3859 | ||
3860 | if (tempYears == 4) | |
3861 | { | |
3862 | years += 300; | |
3863 | day -= daysIn100Years * 3; | |
3864 | } | |
3865 | else | |
3866 | { | |
3867 | years += tempYears * 100; | |
3868 | day %= daysIn100Years; | |
3869 | } | |
3870 | } | |
3871 | ||
3872 | years += (day / daysIn4Years) * 4; | |
3873 | day %= daysIn4Years; | |
3874 | ||
3875 | { | |
3876 | immutable tempYears = day / daysInYear; | |
3877 | ||
3878 | if (tempYears == 4) | |
3879 | { | |
3880 | years += 3; | |
3881 | day -= daysInYear * 3; | |
3882 | } | |
3883 | else | |
3884 | { | |
3885 | years += tempYears; | |
3886 | day %= daysInYear; | |
3887 | } | |
3888 | } | |
3889 | ||
3890 | if (day == 0) | |
3891 | { | |
3892 | _year = cast(short)(years - 1); | |
3893 | _month = Month.dec; | |
3894 | _day = 31; | |
3895 | } | |
3896 | else | |
3897 | { | |
3898 | _year = cast(short) years; | |
3899 | ||
3900 | setDayOfYear(day); | |
3901 | } | |
3902 | } | |
3903 | else if (day <= 0 && -day < daysInLeapYear) | |
3904 | { | |
3905 | _year = 0; | |
3906 | ||
3907 | setDayOfYear(daysInLeapYear + day); | |
3908 | } | |
3909 | else | |
3910 | { | |
3911 | day += daysInLeapYear - 1; | |
3912 | int years = (day / daysIn400Years) * 400 - 1; | |
3913 | day %= daysIn400Years; | |
3914 | ||
3915 | { | |
3916 | immutable tempYears = day / daysIn100Years; | |
3917 | ||
3918 | if (tempYears == -4) | |
3919 | { | |
3920 | years -= 300; | |
3921 | day += daysIn100Years * 3; | |
3922 | } | |
3923 | else | |
3924 | { | |
3925 | years += tempYears * 100; | |
3926 | day %= daysIn100Years; | |
3927 | } | |
3928 | } | |
3929 | ||
3930 | years += (day / daysIn4Years) * 4; | |
3931 | day %= daysIn4Years; | |
3932 | ||
3933 | { | |
3934 | immutable tempYears = day / daysInYear; | |
3935 | ||
3936 | if (tempYears == -4) | |
3937 | { | |
3938 | years -= 3; | |
3939 | day += daysInYear * 3; | |
3940 | } | |
3941 | else | |
3942 | { | |
3943 | years += tempYears; | |
3944 | day %= daysInYear; | |
3945 | } | |
3946 | } | |
3947 | ||
3948 | if (day == 0) | |
3949 | { | |
3950 | _year = cast(short)(years + 1); | |
3951 | _month = Month.jan; | |
3952 | _day = 1; | |
3953 | } | |
3954 | else | |
3955 | { | |
3956 | _year = cast(short) years; | |
3957 | immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1; | |
3958 | ||
3959 | setDayOfYear(newDoY); | |
3960 | } | |
3961 | } | |
3962 | } | |
3963 | ||
3964 | @safe unittest | |
3965 | { | |
3966 | import std.range : chain; | |
3967 | ||
3968 | // Test A.D. | |
3969 | foreach (gd; chain(testGregDaysBC, testGregDaysAD)) | |
3970 | assert(Date(gd.day) == gd.date); | |
3971 | } | |
3972 | ||
3973 | ||
3974 | /++ | |
3975 | Compares this $(LREF Date) with the given $(LREF Date). | |
3976 | ||
3977 | Returns: | |
3978 | $(BOOKTABLE, | |
3979 | $(TR $(TD this < rhs) $(TD < 0)) | |
3980 | $(TR $(TD this == rhs) $(TD 0)) | |
3981 | $(TR $(TD this > rhs) $(TD > 0)) | |
3982 | ) | |
3983 | +/ | |
5fee5ec3 | 3984 | int opCmp(Date rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
3985 | { |
3986 | if (_year < rhs._year) | |
3987 | return -1; | |
3988 | if (_year > rhs._year) | |
3989 | return 1; | |
3990 | ||
3991 | if (_month < rhs._month) | |
3992 | return -1; | |
3993 | if (_month > rhs._month) | |
3994 | return 1; | |
3995 | ||
3996 | if (_day < rhs._day) | |
3997 | return -1; | |
3998 | if (_day > rhs._day) | |
3999 | return 1; | |
4000 | ||
4001 | return 0; | |
4002 | } | |
4003 | ||
4004 | @safe unittest | |
4005 | { | |
4006 | // Test A.D. | |
4007 | assert(Date(1, 1, 1).opCmp(Date.init) == 0); | |
4008 | ||
4009 | assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0); | |
4010 | assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0); | |
4011 | assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0); | |
4012 | ||
4013 | assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0); | |
4014 | assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0); | |
4015 | ||
4016 | assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0); | |
4017 | ||
4018 | assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0); | |
4019 | assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0); | |
4020 | assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0); | |
4021 | assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0); | |
4022 | assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0); | |
4023 | assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0); | |
4024 | ||
4025 | assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0); | |
4026 | assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0); | |
4027 | assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0); | |
4028 | assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0); | |
4029 | assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0); | |
4030 | assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0); | |
4031 | ||
4032 | // Test B.C. | |
4033 | assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0); | |
4034 | assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0); | |
4035 | assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0); | |
4036 | assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0); | |
4037 | ||
4038 | assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0); | |
4039 | assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0); | |
4040 | ||
4041 | assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0); | |
4042 | ||
4043 | assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0); | |
4044 | assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0); | |
4045 | assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0); | |
4046 | assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0); | |
4047 | assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); | |
4048 | assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0); | |
4049 | ||
4050 | assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0); | |
4051 | assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0); | |
4052 | assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); | |
4053 | assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0); | |
4054 | assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0); | |
4055 | assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0); | |
4056 | ||
4057 | // Test Both | |
4058 | assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0); | |
4059 | assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0); | |
4060 | ||
4061 | assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0); | |
4062 | assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0); | |
4063 | ||
4064 | assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0); | |
4065 | assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0); | |
4066 | ||
4067 | assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0); | |
4068 | assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0); | |
4069 | ||
4070 | assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0); | |
4071 | assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0); | |
4072 | ||
4073 | auto date = Date(1999, 7, 6); | |
4074 | const cdate = Date(1999, 7, 6); | |
4075 | immutable idate = Date(1999, 7, 6); | |
4076 | assert(date.opCmp(date) == 0); | |
4077 | assert(date.opCmp(cdate) == 0); | |
4078 | assert(date.opCmp(idate) == 0); | |
4079 | assert(cdate.opCmp(date) == 0); | |
4080 | assert(cdate.opCmp(cdate) == 0); | |
4081 | assert(cdate.opCmp(idate) == 0); | |
4082 | assert(idate.opCmp(date) == 0); | |
4083 | assert(idate.opCmp(cdate) == 0); | |
4084 | assert(idate.opCmp(idate) == 0); | |
4085 | } | |
4086 | ||
4087 | ||
4088 | /++ | |
4089 | Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive | |
4090 | are B.C. | |
4091 | +/ | |
4092 | @property short year() const @safe pure nothrow @nogc | |
4093 | { | |
4094 | return _year; | |
4095 | } | |
4096 | ||
4097 | /// | |
4098 | @safe unittest | |
4099 | { | |
4100 | assert(Date(1999, 7, 6).year == 1999); | |
4101 | assert(Date(2010, 10, 4).year == 2010); | |
4102 | assert(Date(-7, 4, 5).year == -7); | |
4103 | } | |
4104 | ||
4105 | @safe unittest | |
4106 | { | |
4107 | assert(Date.init.year == 1); | |
4108 | assert(Date(1999, 7, 6).year == 1999); | |
4109 | assert(Date(-1999, 7, 6).year == -1999); | |
4110 | ||
4111 | const cdate = Date(1999, 7, 6); | |
4112 | immutable idate = Date(1999, 7, 6); | |
4113 | assert(cdate.year == 1999); | |
4114 | assert(idate.year == 1999); | |
4115 | } | |
4116 | ||
4117 | /++ | |
4118 | Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive | |
4119 | are B.C. | |
4120 | ||
4121 | Params: | |
4122 | year = The year to set this Date's year to. | |
4123 | ||
4124 | Throws: | |
4125 | $(REF DateTimeException,std,datetime,date) if the new year is not | |
4126 | a leap year and the resulting date would be on February 29th. | |
4127 | +/ | |
4128 | @property void year(int year) @safe pure | |
4129 | { | |
4130 | enforceValid!"days"(year, _month, _day); | |
4131 | _year = cast(short) year; | |
4132 | } | |
4133 | ||
4134 | /// | |
4135 | @safe unittest | |
4136 | { | |
4137 | assert(Date(1999, 7, 6).year == 1999); | |
4138 | assert(Date(2010, 10, 4).year == 2010); | |
4139 | assert(Date(-7, 4, 5).year == -7); | |
4140 | } | |
4141 | ||
4142 | @safe unittest | |
4143 | { | |
4144 | static void testDateInvalid(Date date, int year) | |
4145 | { | |
4146 | date.year = year; | |
4147 | } | |
4148 | ||
5fee5ec3 | 4149 | static void testDate(Date date, int year, Date expected) |
b4c522fa IB |
4150 | { |
4151 | date.year = year; | |
4152 | assert(date == expected); | |
4153 | } | |
4154 | ||
4155 | assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1)); | |
4156 | ||
4157 | testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1)); | |
4158 | testDate(Date(1, 1, 1), 0, Date(0, 1, 1)); | |
4159 | testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1)); | |
4160 | ||
4161 | const cdate = Date(1999, 7, 6); | |
4162 | immutable idate = Date(1999, 7, 6); | |
4163 | static assert(!__traits(compiles, cdate.year = 1999)); | |
4164 | static assert(!__traits(compiles, idate.year = 1999)); | |
4165 | } | |
4166 | ||
4167 | ||
4168 | /++ | |
4169 | Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. | |
4170 | ||
4171 | Throws: | |
5fee5ec3 | 4172 | $(REF DateTimeException,std,datetime,date) if `isAD` is true. |
b4c522fa IB |
4173 | +/ |
4174 | @property ushort yearBC() const @safe pure | |
4175 | { | |
4176 | import std.format : format; | |
4177 | ||
4178 | if (isAD) | |
4179 | throw new DateTimeException(format("Year %s is A.D.", _year)); | |
4180 | return cast(ushort)((_year * -1) + 1); | |
4181 | } | |
4182 | ||
4183 | /// | |
4184 | @safe unittest | |
4185 | { | |
4186 | assert(Date(0, 1, 1).yearBC == 1); | |
4187 | assert(Date(-1, 1, 1).yearBC == 2); | |
4188 | assert(Date(-100, 1, 1).yearBC == 101); | |
4189 | } | |
4190 | ||
4191 | @safe unittest | |
4192 | { | |
5fee5ec3 | 4193 | assertThrown!DateTimeException((Date date){date.yearBC;}(Date(1, 1, 1))); |
b4c522fa IB |
4194 | |
4195 | auto date = Date(0, 7, 6); | |
4196 | const cdate = Date(0, 7, 6); | |
4197 | immutable idate = Date(0, 7, 6); | |
4198 | assert(date.yearBC == 1); | |
4199 | assert(cdate.yearBC == 1); | |
4200 | assert(idate.yearBC == 1); | |
4201 | } | |
4202 | ||
4203 | ||
4204 | /++ | |
4205 | Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. | |
4206 | ||
4207 | Params: | |
4208 | year = The year B.C. to set this $(LREF Date)'s year to. | |
4209 | ||
4210 | Throws: | |
4211 | $(REF DateTimeException,std,datetime,date) if a non-positive value | |
4212 | is given. | |
4213 | +/ | |
4214 | @property void yearBC(int year) @safe pure | |
4215 | { | |
4216 | if (year <= 0) | |
4217 | throw new DateTimeException("The given year is not a year B.C."); | |
4218 | _year = cast(short)((year - 1) * -1); | |
4219 | } | |
4220 | ||
4221 | /// | |
4222 | @safe unittest | |
4223 | { | |
4224 | auto date = Date(2010, 1, 1); | |
4225 | date.yearBC = 1; | |
4226 | assert(date == Date(0, 1, 1)); | |
4227 | ||
4228 | date.yearBC = 10; | |
4229 | assert(date == Date(-9, 1, 1)); | |
4230 | } | |
4231 | ||
4232 | @safe unittest | |
4233 | { | |
4234 | assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1))); | |
4235 | ||
4236 | auto date = Date(0, 7, 6); | |
4237 | const cdate = Date(0, 7, 6); | |
4238 | immutable idate = Date(0, 7, 6); | |
4239 | date.yearBC = 7; | |
4240 | assert(date.yearBC == 7); | |
4241 | static assert(!__traits(compiles, cdate.yearBC = 7)); | |
4242 | static assert(!__traits(compiles, idate.yearBC = 7)); | |
4243 | } | |
4244 | ||
4245 | ||
4246 | /++ | |
4247 | Month of a Gregorian Year. | |
4248 | +/ | |
4249 | @property Month month() const @safe pure nothrow @nogc | |
4250 | { | |
4251 | return _month; | |
4252 | } | |
4253 | ||
4254 | /// | |
4255 | @safe unittest | |
4256 | { | |
4257 | assert(Date(1999, 7, 6).month == 7); | |
4258 | assert(Date(2010, 10, 4).month == 10); | |
4259 | assert(Date(-7, 4, 5).month == 4); | |
4260 | } | |
4261 | ||
4262 | @safe unittest | |
4263 | { | |
4264 | assert(Date.init.month == 1); | |
4265 | assert(Date(1999, 7, 6).month == 7); | |
4266 | assert(Date(-1999, 7, 6).month == 7); | |
4267 | ||
4268 | const cdate = Date(1999, 7, 6); | |
4269 | immutable idate = Date(1999, 7, 6); | |
4270 | assert(cdate.month == 7); | |
4271 | assert(idate.month == 7); | |
4272 | } | |
4273 | ||
4274 | /++ | |
4275 | Month of a Gregorian Year. | |
4276 | ||
4277 | Params: | |
4278 | month = The month to set this $(LREF Date)'s month to. | |
4279 | ||
4280 | Throws: | |
4281 | $(REF DateTimeException,std,datetime,date) if the given month is | |
4282 | not a valid month or if the current day would not be valid in the | |
4283 | given month. | |
4284 | +/ | |
4285 | @property void month(Month month) @safe pure | |
4286 | { | |
4287 | enforceValid!"months"(month); | |
4288 | enforceValid!"days"(_year, month, _day); | |
4289 | _month = cast(Month) month; | |
4290 | } | |
4291 | ||
4292 | @safe unittest | |
4293 | { | |
5fee5ec3 | 4294 | static void testDate(Date date, Month month, Date expected = Date.init) |
b4c522fa IB |
4295 | { |
4296 | date.month = month; | |
4297 | assert(expected != Date.init); | |
4298 | assert(date == expected); | |
4299 | } | |
4300 | ||
4301 | assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0)); | |
4302 | assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13)); | |
4303 | assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2)); | |
4304 | assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2)); | |
4305 | ||
4306 | testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1)); | |
4307 | testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1)); | |
4308 | ||
4309 | const cdate = Date(1999, 7, 6); | |
4310 | immutable idate = Date(1999, 7, 6); | |
4311 | static assert(!__traits(compiles, cdate.month = 7)); | |
4312 | static assert(!__traits(compiles, idate.month = 7)); | |
4313 | } | |
4314 | ||
4315 | ||
4316 | /++ | |
4317 | Day of a Gregorian Month. | |
4318 | +/ | |
4319 | @property ubyte day() const @safe pure nothrow @nogc | |
4320 | { | |
4321 | return _day; | |
4322 | } | |
4323 | ||
4324 | /// | |
4325 | @safe unittest | |
4326 | { | |
4327 | assert(Date(1999, 7, 6).day == 6); | |
4328 | assert(Date(2010, 10, 4).day == 4); | |
4329 | assert(Date(-7, 4, 5).day == 5); | |
4330 | } | |
4331 | ||
4332 | @safe unittest | |
4333 | { | |
4334 | import std.format : format; | |
4335 | import std.range : chain; | |
4336 | ||
4337 | static void test(Date date, int expected) | |
4338 | { | |
4339 | assert(date.day == expected, format("Value given: %s", date)); | |
4340 | } | |
4341 | ||
4342 | foreach (year; chain(testYearsBC, testYearsAD)) | |
4343 | { | |
4344 | foreach (md; testMonthDays) | |
4345 | test(Date(year, md.month, md.day), md.day); | |
4346 | } | |
4347 | ||
4348 | const cdate = Date(1999, 7, 6); | |
4349 | immutable idate = Date(1999, 7, 6); | |
4350 | assert(cdate.day == 6); | |
4351 | assert(idate.day == 6); | |
4352 | } | |
4353 | ||
4354 | /++ | |
4355 | Day of a Gregorian Month. | |
4356 | ||
4357 | Params: | |
4358 | day = The day of the month to set this $(LREF Date)'s day to. | |
4359 | ||
4360 | Throws: | |
4361 | $(REF DateTimeException,std,datetime,date) if the given day is not | |
4362 | a valid day of the current month. | |
4363 | +/ | |
4364 | @property void day(int day) @safe pure | |
4365 | { | |
4366 | enforceValid!"days"(_year, _month, day); | |
4367 | _day = cast(ubyte) day; | |
4368 | } | |
4369 | ||
4370 | @safe unittest | |
4371 | { | |
4372 | import std.exception : assertNotThrown; | |
4373 | ||
4374 | static void testDate(Date date, int day) | |
4375 | { | |
4376 | date.day = day; | |
4377 | } | |
4378 | ||
4379 | // Test A.D. | |
4380 | assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0)); | |
4381 | assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32)); | |
4382 | assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29)); | |
4383 | assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30)); | |
4384 | assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32)); | |
4385 | assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31)); | |
4386 | assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32)); | |
4387 | assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31)); | |
4388 | assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32)); | |
4389 | assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32)); | |
4390 | assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31)); | |
4391 | assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32)); | |
4392 | assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31)); | |
4393 | assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32)); | |
4394 | ||
4395 | assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31)); | |
4396 | assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28)); | |
4397 | assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29)); | |
4398 | assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31)); | |
4399 | assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30)); | |
4400 | assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31)); | |
4401 | assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30)); | |
4402 | assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31)); | |
4403 | assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31)); | |
4404 | assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30)); | |
4405 | assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31)); | |
4406 | assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30)); | |
4407 | assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31)); | |
4408 | ||
4409 | { | |
4410 | auto date = Date(1, 1, 1); | |
4411 | date.day = 6; | |
4412 | assert(date == Date(1, 1, 6)); | |
4413 | } | |
4414 | ||
4415 | // Test B.C. | |
4416 | assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0)); | |
4417 | assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32)); | |
4418 | assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29)); | |
4419 | assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30)); | |
4420 | assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32)); | |
4421 | assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31)); | |
4422 | assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32)); | |
4423 | assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31)); | |
4424 | assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32)); | |
4425 | assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32)); | |
4426 | assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31)); | |
4427 | assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32)); | |
4428 | assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31)); | |
4429 | assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32)); | |
4430 | ||
4431 | assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31)); | |
4432 | assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28)); | |
4433 | assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29)); | |
4434 | assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31)); | |
4435 | assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30)); | |
4436 | assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31)); | |
4437 | assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30)); | |
4438 | assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31)); | |
4439 | assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31)); | |
4440 | assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30)); | |
4441 | assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31)); | |
4442 | assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30)); | |
4443 | assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31)); | |
4444 | ||
4445 | { | |
4446 | auto date = Date(-1, 1, 1); | |
4447 | date.day = 6; | |
4448 | assert(date == Date(-1, 1, 6)); | |
4449 | } | |
4450 | ||
4451 | const cdate = Date(1999, 7, 6); | |
4452 | immutable idate = Date(1999, 7, 6); | |
4453 | static assert(!__traits(compiles, cdate.day = 6)); | |
4454 | static assert(!__traits(compiles, idate.day = 6)); | |
4455 | } | |
4456 | ||
4457 | ||
4458 | /++ | |
5fee5ec3 IB |
4459 | Adds the given number of years or months to this $(LREF Date), mutating |
4460 | it. A negative number will subtract. | |
b4c522fa IB |
4461 | |
4462 | Note that if day overflow is allowed, and the date with the adjusted | |
4463 | year/month overflows the number of days in the new month, then the month | |
4464 | will be incremented by one, and the day set to the number of days | |
4465 | overflowed. (e.g. if the day were 31 and the new month were June, then | |
4466 | the month would be incremented to July, and the new day would be 1). If | |
4467 | day overflow is not allowed, then the day will be set to the last valid | |
4468 | day in the month (e.g. June 31st would become June 30th). | |
4469 | ||
4470 | Params: | |
4471 | units = The type of units to add ("years" or "months"). | |
4472 | value = The number of months or years to add to this | |
4473 | $(LREF Date). | |
4474 | allowOverflow = Whether the day should be allowed to overflow, | |
4475 | causing the month to increment. | |
5fee5ec3 IB |
4476 | |
4477 | Returns: | |
4478 | A reference to the `Date` (`this`). | |
b4c522fa IB |
4479 | +/ |
4480 | @safe pure nothrow @nogc | |
4481 | ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) | |
4482 | if (units == "years") | |
4483 | { | |
4484 | _year += value; | |
4485 | ||
4486 | if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year)) | |
4487 | { | |
4488 | if (allowOverflow == AllowDayOverflow.yes) | |
4489 | { | |
4490 | _month = Month.mar; | |
4491 | _day = 1; | |
4492 | } | |
4493 | else | |
4494 | _day = 28; | |
4495 | } | |
4496 | ||
4497 | return this; | |
4498 | } | |
4499 | ||
4500 | /// | |
4501 | @safe unittest | |
4502 | { | |
4503 | auto d1 = Date(2010, 1, 1); | |
4504 | d1.add!"months"(11); | |
4505 | assert(d1 == Date(2010, 12, 1)); | |
4506 | ||
4507 | auto d2 = Date(2010, 1, 1); | |
4508 | d2.add!"months"(-11); | |
4509 | assert(d2 == Date(2009, 2, 1)); | |
4510 | ||
4511 | auto d3 = Date(2000, 2, 29); | |
4512 | d3.add!"years"(1); | |
4513 | assert(d3 == Date(2001, 3, 1)); | |
4514 | ||
4515 | auto d4 = Date(2000, 2, 29); | |
4516 | d4.add!"years"(1, AllowDayOverflow.no); | |
4517 | assert(d4 == Date(2001, 2, 28)); | |
4518 | } | |
4519 | ||
4520 | // Test add!"years"() with AllowDayOverflow.yes | |
4521 | @safe unittest | |
4522 | { | |
4523 | // Test A.D. | |
4524 | { | |
4525 | auto date = Date(1999, 7, 6); | |
4526 | date.add!"years"(7); | |
4527 | assert(date == Date(2006, 7, 6)); | |
4528 | date.add!"years"(-9); | |
4529 | assert(date == Date(1997, 7, 6)); | |
4530 | } | |
4531 | ||
4532 | { | |
4533 | auto date = Date(1999, 2, 28); | |
4534 | date.add!"years"(1); | |
4535 | assert(date == Date(2000, 2, 28)); | |
4536 | } | |
4537 | ||
4538 | { | |
4539 | auto date = Date(2000, 2, 29); | |
4540 | date.add!"years"(-1); | |
4541 | assert(date == Date(1999, 3, 1)); | |
4542 | } | |
4543 | ||
4544 | // Test B.C. | |
4545 | { | |
4546 | auto date = Date(-1999, 7, 6); | |
4547 | date.add!"years"(-7); | |
4548 | assert(date == Date(-2006, 7, 6)); | |
4549 | date.add!"years"(9); | |
4550 | assert(date == Date(-1997, 7, 6)); | |
4551 | } | |
4552 | ||
4553 | { | |
4554 | auto date = Date(-1999, 2, 28); | |
4555 | date.add!"years"(-1); | |
4556 | assert(date == Date(-2000, 2, 28)); | |
4557 | } | |
4558 | ||
4559 | { | |
4560 | auto date = Date(-2000, 2, 29); | |
4561 | date.add!"years"(1); | |
4562 | assert(date == Date(-1999, 3, 1)); | |
4563 | } | |
4564 | ||
4565 | // Test Both | |
4566 | { | |
4567 | auto date = Date(4, 7, 6); | |
4568 | date.add!"years"(-5); | |
4569 | assert(date == Date(-1, 7, 6)); | |
4570 | date.add!"years"(5); | |
4571 | assert(date == Date(4, 7, 6)); | |
4572 | } | |
4573 | ||
4574 | { | |
4575 | auto date = Date(-4, 7, 6); | |
4576 | date.add!"years"(5); | |
4577 | assert(date == Date(1, 7, 6)); | |
4578 | date.add!"years"(-5); | |
4579 | assert(date == Date(-4, 7, 6)); | |
4580 | } | |
4581 | ||
4582 | { | |
4583 | auto date = Date(4, 7, 6); | |
4584 | date.add!"years"(-8); | |
4585 | assert(date == Date(-4, 7, 6)); | |
4586 | date.add!"years"(8); | |
4587 | assert(date == Date(4, 7, 6)); | |
4588 | } | |
4589 | ||
4590 | { | |
4591 | auto date = Date(-4, 7, 6); | |
4592 | date.add!"years"(8); | |
4593 | assert(date == Date(4, 7, 6)); | |
4594 | date.add!"years"(-8); | |
4595 | assert(date == Date(-4, 7, 6)); | |
4596 | } | |
4597 | ||
4598 | { | |
4599 | auto date = Date(-4, 2, 29); | |
4600 | date.add!"years"(5); | |
4601 | assert(date == Date(1, 3, 1)); | |
4602 | } | |
4603 | ||
4604 | { | |
4605 | auto date = Date(4, 2, 29); | |
4606 | date.add!"years"(-5); | |
4607 | assert(date == Date(-1, 3, 1)); | |
4608 | } | |
4609 | ||
4610 | { | |
4611 | auto date = Date(4, 2, 29); | |
4612 | date.add!"years"(-5).add!"years"(7); | |
4613 | assert(date == Date(6, 3, 1)); | |
4614 | } | |
4615 | ||
4616 | const cdate = Date(1999, 7, 6); | |
4617 | immutable idate = Date(1999, 7, 6); | |
4618 | static assert(!__traits(compiles, cdate.add!"years"(7))); | |
4619 | static assert(!__traits(compiles, idate.add!"years"(7))); | |
4620 | } | |
4621 | ||
4622 | // Test add!"years"() with AllowDayOverflow.no | |
4623 | @safe unittest | |
4624 | { | |
4625 | // Test A.D. | |
4626 | { | |
4627 | auto date = Date(1999, 7, 6); | |
4628 | date.add!"years"(7, AllowDayOverflow.no); | |
4629 | assert(date == Date(2006, 7, 6)); | |
4630 | date.add!"years"(-9, AllowDayOverflow.no); | |
4631 | assert(date == Date(1997, 7, 6)); | |
4632 | } | |
4633 | ||
4634 | { | |
4635 | auto date = Date(1999, 2, 28); | |
4636 | date.add!"years"(1, AllowDayOverflow.no); | |
4637 | assert(date == Date(2000, 2, 28)); | |
4638 | } | |
4639 | ||
4640 | { | |
4641 | auto date = Date(2000, 2, 29); | |
4642 | date.add!"years"(-1, AllowDayOverflow.no); | |
4643 | assert(date == Date(1999, 2, 28)); | |
4644 | } | |
4645 | ||
4646 | // Test B.C. | |
4647 | { | |
4648 | auto date = Date(-1999, 7, 6); | |
4649 | date.add!"years"(-7, AllowDayOverflow.no); | |
4650 | assert(date == Date(-2006, 7, 6)); | |
4651 | date.add!"years"(9, AllowDayOverflow.no); | |
4652 | assert(date == Date(-1997, 7, 6)); | |
4653 | } | |
4654 | ||
4655 | { | |
4656 | auto date = Date(-1999, 2, 28); | |
4657 | date.add!"years"(-1, AllowDayOverflow.no); | |
4658 | assert(date == Date(-2000, 2, 28)); | |
4659 | } | |
4660 | ||
4661 | { | |
4662 | auto date = Date(-2000, 2, 29); | |
4663 | date.add!"years"(1, AllowDayOverflow.no); | |
4664 | assert(date == Date(-1999, 2, 28)); | |
4665 | } | |
4666 | ||
4667 | // Test Both | |
4668 | { | |
4669 | auto date = Date(4, 7, 6); | |
4670 | date.add!"years"(-5, AllowDayOverflow.no); | |
4671 | assert(date == Date(-1, 7, 6)); | |
4672 | date.add!"years"(5, AllowDayOverflow.no); | |
4673 | assert(date == Date(4, 7, 6)); | |
4674 | } | |
4675 | ||
4676 | { | |
4677 | auto date = Date(-4, 7, 6); | |
4678 | date.add!"years"(5, AllowDayOverflow.no); | |
4679 | assert(date == Date(1, 7, 6)); | |
4680 | date.add!"years"(-5, AllowDayOverflow.no); | |
4681 | assert(date == Date(-4, 7, 6)); | |
4682 | } | |
4683 | ||
4684 | { | |
4685 | auto date = Date(4, 7, 6); | |
4686 | date.add!"years"(-8, AllowDayOverflow.no); | |
4687 | assert(date == Date(-4, 7, 6)); | |
4688 | date.add!"years"(8, AllowDayOverflow.no); | |
4689 | assert(date == Date(4, 7, 6)); | |
4690 | } | |
4691 | ||
4692 | { | |
4693 | auto date = Date(-4, 7, 6); | |
4694 | date.add!"years"(8, AllowDayOverflow.no); | |
4695 | assert(date == Date(4, 7, 6)); | |
4696 | date.add!"years"(-8, AllowDayOverflow.no); | |
4697 | assert(date == Date(-4, 7, 6)); | |
4698 | } | |
4699 | ||
4700 | { | |
4701 | auto date = Date(-4, 2, 29); | |
4702 | date.add!"years"(5, AllowDayOverflow.no); | |
4703 | assert(date == Date(1, 2, 28)); | |
4704 | } | |
4705 | ||
4706 | { | |
4707 | auto date = Date(4, 2, 29); | |
4708 | date.add!"years"(-5, AllowDayOverflow.no); | |
4709 | assert(date == Date(-1, 2, 28)); | |
4710 | } | |
4711 | ||
4712 | { | |
4713 | auto date = Date(4, 2, 29); | |
4714 | date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); | |
4715 | assert(date == Date(6, 2, 28)); | |
4716 | } | |
4717 | } | |
4718 | ||
4719 | ||
4720 | // Shares documentation with "years" version. | |
4721 | @safe pure nothrow @nogc | |
4722 | ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) | |
4723 | if (units == "months") | |
4724 | { | |
4725 | auto years = months / 12; | |
4726 | months %= 12; | |
4727 | auto newMonth = _month + months; | |
4728 | ||
4729 | if (months < 0) | |
4730 | { | |
4731 | if (newMonth < 1) | |
4732 | { | |
4733 | newMonth += 12; | |
4734 | --years; | |
4735 | } | |
4736 | } | |
4737 | else if (newMonth > 12) | |
4738 | { | |
4739 | newMonth -= 12; | |
4740 | ++years; | |
4741 | } | |
4742 | ||
4743 | _year += years; | |
4744 | _month = cast(Month) newMonth; | |
4745 | ||
4746 | immutable currMaxDay = maxDay(_year, _month); | |
4747 | immutable overflow = _day - currMaxDay; | |
4748 | ||
4749 | if (overflow > 0) | |
4750 | { | |
4751 | if (allowOverflow == AllowDayOverflow.yes) | |
4752 | { | |
4753 | ++_month; | |
4754 | _day = cast(ubyte) overflow; | |
4755 | } | |
4756 | else | |
4757 | _day = cast(ubyte) currMaxDay; | |
4758 | } | |
4759 | ||
4760 | return this; | |
4761 | } | |
4762 | ||
4763 | // Test add!"months"() with AllowDayOverflow.yes | |
4764 | @safe unittest | |
4765 | { | |
4766 | // Test A.D. | |
4767 | { | |
4768 | auto date = Date(1999, 7, 6); | |
4769 | date.add!"months"(3); | |
4770 | assert(date == Date(1999, 10, 6)); | |
4771 | date.add!"months"(-4); | |
4772 | assert(date == Date(1999, 6, 6)); | |
4773 | } | |
4774 | ||
4775 | { | |
4776 | auto date = Date(1999, 7, 6); | |
4777 | date.add!"months"(6); | |
4778 | assert(date == Date(2000, 1, 6)); | |
4779 | date.add!"months"(-6); | |
4780 | assert(date == Date(1999, 7, 6)); | |
4781 | } | |
4782 | ||
4783 | { | |
4784 | auto date = Date(1999, 7, 6); | |
4785 | date.add!"months"(27); | |
4786 | assert(date == Date(2001, 10, 6)); | |
4787 | date.add!"months"(-28); | |
4788 | assert(date == Date(1999, 6, 6)); | |
4789 | } | |
4790 | ||
4791 | { | |
4792 | auto date = Date(1999, 5, 31); | |
4793 | date.add!"months"(1); | |
4794 | assert(date == Date(1999, 7, 1)); | |
4795 | } | |
4796 | ||
4797 | { | |
4798 | auto date = Date(1999, 5, 31); | |
4799 | date.add!"months"(-1); | |
4800 | assert(date == Date(1999, 5, 1)); | |
4801 | } | |
4802 | ||
4803 | { | |
4804 | auto date = Date(1999, 2, 28); | |
4805 | date.add!"months"(12); | |
4806 | assert(date == Date(2000, 2, 28)); | |
4807 | } | |
4808 | ||
4809 | { | |
4810 | auto date = Date(2000, 2, 29); | |
4811 | date.add!"months"(12); | |
4812 | assert(date == Date(2001, 3, 1)); | |
4813 | } | |
4814 | ||
4815 | { | |
4816 | auto date = Date(1999, 7, 31); | |
4817 | date.add!"months"(1); | |
4818 | assert(date == Date(1999, 8, 31)); | |
4819 | date.add!"months"(1); | |
4820 | assert(date == Date(1999, 10, 1)); | |
4821 | } | |
4822 | ||
4823 | { | |
4824 | auto date = Date(1998, 8, 31); | |
4825 | date.add!"months"(13); | |
4826 | assert(date == Date(1999, 10, 1)); | |
4827 | date.add!"months"(-13); | |
4828 | assert(date == Date(1998, 9, 1)); | |
4829 | } | |
4830 | ||
4831 | { | |
4832 | auto date = Date(1997, 12, 31); | |
4833 | date.add!"months"(13); | |
4834 | assert(date == Date(1999, 1, 31)); | |
4835 | date.add!"months"(-13); | |
4836 | assert(date == Date(1997, 12, 31)); | |
4837 | } | |
4838 | ||
4839 | { | |
4840 | auto date = Date(1997, 12, 31); | |
4841 | date.add!"months"(14); | |
4842 | assert(date == Date(1999, 3, 3)); | |
4843 | date.add!"months"(-14); | |
4844 | assert(date == Date(1998, 1, 3)); | |
4845 | } | |
4846 | ||
4847 | { | |
4848 | auto date = Date(1998, 12, 31); | |
4849 | date.add!"months"(14); | |
4850 | assert(date == Date(2000, 3, 2)); | |
4851 | date.add!"months"(-14); | |
4852 | assert(date == Date(1999, 1, 2)); | |
4853 | } | |
4854 | ||
4855 | { | |
4856 | auto date = Date(1999, 12, 31); | |
4857 | date.add!"months"(14); | |
4858 | assert(date == Date(2001, 3, 3)); | |
4859 | date.add!"months"(-14); | |
4860 | assert(date == Date(2000, 1, 3)); | |
4861 | } | |
4862 | ||
4863 | // Test B.C. | |
4864 | { | |
4865 | auto date = Date(-1999, 7, 6); | |
4866 | date.add!"months"(3); | |
4867 | assert(date == Date(-1999, 10, 6)); | |
4868 | date.add!"months"(-4); | |
4869 | assert(date == Date(-1999, 6, 6)); | |
4870 | } | |
4871 | ||
4872 | { | |
4873 | auto date = Date(-1999, 7, 6); | |
4874 | date.add!"months"(6); | |
4875 | assert(date == Date(-1998, 1, 6)); | |
4876 | date.add!"months"(-6); | |
4877 | assert(date == Date(-1999, 7, 6)); | |
4878 | } | |
4879 | ||
4880 | { | |
4881 | auto date = Date(-1999, 7, 6); | |
4882 | date.add!"months"(-27); | |
4883 | assert(date == Date(-2001, 4, 6)); | |
4884 | date.add!"months"(28); | |
4885 | assert(date == Date(-1999, 8, 6)); | |
4886 | } | |
4887 | ||
4888 | { | |
4889 | auto date = Date(-1999, 5, 31); | |
4890 | date.add!"months"(1); | |
4891 | assert(date == Date(-1999, 7, 1)); | |
4892 | } | |
4893 | ||
4894 | { | |
4895 | auto date = Date(-1999, 5, 31); | |
4896 | date.add!"months"(-1); | |
4897 | assert(date == Date(-1999, 5, 1)); | |
4898 | } | |
4899 | ||
4900 | { | |
4901 | auto date = Date(-1999, 2, 28); | |
4902 | date.add!"months"(-12); | |
4903 | assert(date == Date(-2000, 2, 28)); | |
4904 | } | |
4905 | ||
4906 | { | |
4907 | auto date = Date(-2000, 2, 29); | |
4908 | date.add!"months"(-12); | |
4909 | assert(date == Date(-2001, 3, 1)); | |
4910 | } | |
4911 | ||
4912 | { | |
4913 | auto date = Date(-1999, 7, 31); | |
4914 | date.add!"months"(1); | |
4915 | assert(date == Date(-1999, 8, 31)); | |
4916 | date.add!"months"(1); | |
4917 | assert(date == Date(-1999, 10, 1)); | |
4918 | } | |
4919 | ||
4920 | { | |
4921 | auto date = Date(-1998, 8, 31); | |
4922 | date.add!"months"(13); | |
4923 | assert(date == Date(-1997, 10, 1)); | |
4924 | date.add!"months"(-13); | |
4925 | assert(date == Date(-1998, 9, 1)); | |
4926 | } | |
4927 | ||
4928 | { | |
4929 | auto date = Date(-1997, 12, 31); | |
4930 | date.add!"months"(13); | |
4931 | assert(date == Date(-1995, 1, 31)); | |
4932 | date.add!"months"(-13); | |
4933 | assert(date == Date(-1997, 12, 31)); | |
4934 | } | |
4935 | ||
4936 | { | |
4937 | auto date = Date(-1997, 12, 31); | |
4938 | date.add!"months"(14); | |
4939 | assert(date == Date(-1995, 3, 3)); | |
4940 | date.add!"months"(-14); | |
4941 | assert(date == Date(-1996, 1, 3)); | |
4942 | } | |
4943 | ||
4944 | { | |
4945 | auto date = Date(-2002, 12, 31); | |
4946 | date.add!"months"(14); | |
4947 | assert(date == Date(-2000, 3, 2)); | |
4948 | date.add!"months"(-14); | |
4949 | assert(date == Date(-2001, 1, 2)); | |
4950 | } | |
4951 | ||
4952 | { | |
4953 | auto date = Date(-2001, 12, 31); | |
4954 | date.add!"months"(14); | |
4955 | assert(date == Date(-1999, 3, 3)); | |
4956 | date.add!"months"(-14); | |
4957 | assert(date == Date(-2000, 1, 3)); | |
4958 | } | |
4959 | ||
4960 | // Test Both | |
4961 | { | |
4962 | auto date = Date(1, 1, 1); | |
4963 | date.add!"months"(-1); | |
4964 | assert(date == Date(0, 12, 1)); | |
4965 | date.add!"months"(1); | |
4966 | assert(date == Date(1, 1, 1)); | |
4967 | } | |
4968 | ||
4969 | { | |
4970 | auto date = Date(4, 1, 1); | |
4971 | date.add!"months"(-48); | |
4972 | assert(date == Date(0, 1, 1)); | |
4973 | date.add!"months"(48); | |
4974 | assert(date == Date(4, 1, 1)); | |
4975 | } | |
4976 | ||
4977 | { | |
4978 | auto date = Date(4, 3, 31); | |
4979 | date.add!"months"(-49); | |
4980 | assert(date == Date(0, 3, 2)); | |
4981 | date.add!"months"(49); | |
4982 | assert(date == Date(4, 4, 2)); | |
4983 | } | |
4984 | ||
4985 | { | |
4986 | auto date = Date(4, 3, 31); | |
4987 | date.add!"months"(-85); | |
4988 | assert(date == Date(-3, 3, 3)); | |
4989 | date.add!"months"(85); | |
4990 | assert(date == Date(4, 4, 3)); | |
4991 | } | |
4992 | ||
4993 | { | |
4994 | auto date = Date(-3, 3, 31); | |
4995 | date.add!"months"(85).add!"months"(-83); | |
4996 | assert(date == Date(-3, 6, 1)); | |
4997 | } | |
4998 | ||
4999 | const cdate = Date(1999, 7, 6); | |
5000 | immutable idate = Date(1999, 7, 6); | |
5001 | static assert(!__traits(compiles, cdate.add!"months"(3))); | |
5002 | static assert(!__traits(compiles, idate.add!"months"(3))); | |
5003 | } | |
5004 | ||
5005 | // Test add!"months"() with AllowDayOverflow.no | |
5006 | @safe unittest | |
5007 | { | |
5008 | // Test A.D. | |
5009 | { | |
5010 | auto date = Date(1999, 7, 6); | |
5011 | date.add!"months"(3, AllowDayOverflow.no); | |
5012 | assert(date == Date(1999, 10, 6)); | |
5013 | date.add!"months"(-4, AllowDayOverflow.no); | |
5014 | assert(date == Date(1999, 6, 6)); | |
5015 | } | |
5016 | ||
5017 | { | |
5018 | auto date = Date(1999, 7, 6); | |
5019 | date.add!"months"(6, AllowDayOverflow.no); | |
5020 | assert(date == Date(2000, 1, 6)); | |
5021 | date.add!"months"(-6, AllowDayOverflow.no); | |
5022 | assert(date == Date(1999, 7, 6)); | |
5023 | } | |
5024 | ||
5025 | { | |
5026 | auto date = Date(1999, 7, 6); | |
5027 | date.add!"months"(27, AllowDayOverflow.no); | |
5028 | assert(date == Date(2001, 10, 6)); | |
5029 | date.add!"months"(-28, AllowDayOverflow.no); | |
5030 | assert(date == Date(1999, 6, 6)); | |
5031 | } | |
5032 | ||
5033 | { | |
5034 | auto date = Date(1999, 5, 31); | |
5035 | date.add!"months"(1, AllowDayOverflow.no); | |
5036 | assert(date == Date(1999, 6, 30)); | |
5037 | } | |
5038 | ||
5039 | { | |
5040 | auto date = Date(1999, 5, 31); | |
5041 | date.add!"months"(-1, AllowDayOverflow.no); | |
5042 | assert(date == Date(1999, 4, 30)); | |
5043 | } | |
5044 | ||
5045 | { | |
5046 | auto date = Date(1999, 2, 28); | |
5047 | date.add!"months"(12, AllowDayOverflow.no); | |
5048 | assert(date == Date(2000, 2, 28)); | |
5049 | } | |
5050 | ||
5051 | { | |
5052 | auto date = Date(2000, 2, 29); | |
5053 | date.add!"months"(12, AllowDayOverflow.no); | |
5054 | assert(date == Date(2001, 2, 28)); | |
5055 | } | |
5056 | ||
5057 | { | |
5058 | auto date = Date(1999, 7, 31); | |
5059 | date.add!"months"(1, AllowDayOverflow.no); | |
5060 | assert(date == Date(1999, 8, 31)); | |
5061 | date.add!"months"(1, AllowDayOverflow.no); | |
5062 | assert(date == Date(1999, 9, 30)); | |
5063 | } | |
5064 | ||
5065 | { | |
5066 | auto date = Date(1998, 8, 31); | |
5067 | date.add!"months"(13, AllowDayOverflow.no); | |
5068 | assert(date == Date(1999, 9, 30)); | |
5069 | date.add!"months"(-13, AllowDayOverflow.no); | |
5070 | assert(date == Date(1998, 8, 30)); | |
5071 | } | |
5072 | ||
5073 | { | |
5074 | auto date = Date(1997, 12, 31); | |
5075 | date.add!"months"(13, AllowDayOverflow.no); | |
5076 | assert(date == Date(1999, 1, 31)); | |
5077 | date.add!"months"(-13, AllowDayOverflow.no); | |
5078 | assert(date == Date(1997, 12, 31)); | |
5079 | } | |
5080 | ||
5081 | { | |
5082 | auto date = Date(1997, 12, 31); | |
5083 | date.add!"months"(14, AllowDayOverflow.no); | |
5084 | assert(date == Date(1999, 2, 28)); | |
5085 | date.add!"months"(-14, AllowDayOverflow.no); | |
5086 | assert(date == Date(1997, 12, 28)); | |
5087 | } | |
5088 | ||
5089 | { | |
5090 | auto date = Date(1998, 12, 31); | |
5091 | date.add!"months"(14, AllowDayOverflow.no); | |
5092 | assert(date == Date(2000, 2, 29)); | |
5093 | date.add!"months"(-14, AllowDayOverflow.no); | |
5094 | assert(date == Date(1998, 12, 29)); | |
5095 | } | |
5096 | ||
5097 | { | |
5098 | auto date = Date(1999, 12, 31); | |
5099 | date.add!"months"(14, AllowDayOverflow.no); | |
5100 | assert(date == Date(2001, 2, 28)); | |
5101 | date.add!"months"(-14, AllowDayOverflow.no); | |
5102 | assert(date == Date(1999, 12, 28)); | |
5103 | } | |
5104 | ||
5105 | // Test B.C. | |
5106 | { | |
5107 | auto date = Date(-1999, 7, 6); | |
5108 | date.add!"months"(3, AllowDayOverflow.no); | |
5109 | assert(date == Date(-1999, 10, 6)); | |
5110 | date.add!"months"(-4, AllowDayOverflow.no); | |
5111 | assert(date == Date(-1999, 6, 6)); | |
5112 | } | |
5113 | ||
5114 | { | |
5115 | auto date = Date(-1999, 7, 6); | |
5116 | date.add!"months"(6, AllowDayOverflow.no); | |
5117 | assert(date == Date(-1998, 1, 6)); | |
5118 | date.add!"months"(-6, AllowDayOverflow.no); | |
5119 | assert(date == Date(-1999, 7, 6)); | |
5120 | } | |
5121 | ||
5122 | { | |
5123 | auto date = Date(-1999, 7, 6); | |
5124 | date.add!"months"(-27, AllowDayOverflow.no); | |
5125 | assert(date == Date(-2001, 4, 6)); | |
5126 | date.add!"months"(28, AllowDayOverflow.no); | |
5127 | assert(date == Date(-1999, 8, 6)); | |
5128 | } | |
5129 | ||
5130 | { | |
5131 | auto date = Date(-1999, 5, 31); | |
5132 | date.add!"months"(1, AllowDayOverflow.no); | |
5133 | assert(date == Date(-1999, 6, 30)); | |
5134 | } | |
5135 | ||
5136 | { | |
5137 | auto date = Date(-1999, 5, 31); | |
5138 | date.add!"months"(-1, AllowDayOverflow.no); | |
5139 | assert(date == Date(-1999, 4, 30)); | |
5140 | } | |
5141 | ||
5142 | { | |
5143 | auto date = Date(-1999, 2, 28); | |
5144 | date.add!"months"(-12, AllowDayOverflow.no); | |
5145 | assert(date == Date(-2000, 2, 28)); | |
5146 | } | |
5147 | ||
5148 | { | |
5149 | auto date = Date(-2000, 2, 29); | |
5150 | date.add!"months"(-12, AllowDayOverflow.no); | |
5151 | assert(date == Date(-2001, 2, 28)); | |
5152 | } | |
5153 | ||
5154 | { | |
5155 | auto date = Date(-1999, 7, 31); | |
5156 | date.add!"months"(1, AllowDayOverflow.no); | |
5157 | assert(date == Date(-1999, 8, 31)); | |
5158 | date.add!"months"(1, AllowDayOverflow.no); | |
5159 | assert(date == Date(-1999, 9, 30)); | |
5160 | } | |
5161 | ||
5162 | { | |
5163 | auto date = Date(-1998, 8, 31); | |
5164 | date.add!"months"(13, AllowDayOverflow.no); | |
5165 | assert(date == Date(-1997, 9, 30)); | |
5166 | date.add!"months"(-13, AllowDayOverflow.no); | |
5167 | assert(date == Date(-1998, 8, 30)); | |
5168 | } | |
5169 | ||
5170 | { | |
5171 | auto date = Date(-1997, 12, 31); | |
5172 | date.add!"months"(13, AllowDayOverflow.no); | |
5173 | assert(date == Date(-1995, 1, 31)); | |
5174 | date.add!"months"(-13, AllowDayOverflow.no); | |
5175 | assert(date == Date(-1997, 12, 31)); | |
5176 | } | |
5177 | ||
5178 | { | |
5179 | auto date = Date(-1997, 12, 31); | |
5180 | date.add!"months"(14, AllowDayOverflow.no); | |
5181 | assert(date == Date(-1995, 2, 28)); | |
5182 | date.add!"months"(-14, AllowDayOverflow.no); | |
5183 | assert(date == Date(-1997, 12, 28)); | |
5184 | } | |
5185 | ||
5186 | { | |
5187 | auto date = Date(-2002, 12, 31); | |
5188 | date.add!"months"(14, AllowDayOverflow.no); | |
5189 | assert(date == Date(-2000, 2, 29)); | |
5190 | date.add!"months"(-14, AllowDayOverflow.no); | |
5191 | assert(date == Date(-2002, 12, 29)); | |
5192 | } | |
5193 | ||
5194 | { | |
5195 | auto date = Date(-2001, 12, 31); | |
5196 | date.add!"months"(14, AllowDayOverflow.no); | |
5197 | assert(date == Date(-1999, 2, 28)); | |
5198 | date.add!"months"(-14, AllowDayOverflow.no); | |
5199 | assert(date == Date(-2001, 12, 28)); | |
5200 | } | |
5201 | ||
5202 | // Test Both | |
5203 | { | |
5204 | auto date = Date(1, 1, 1); | |
5205 | date.add!"months"(-1, AllowDayOverflow.no); | |
5206 | assert(date == Date(0, 12, 1)); | |
5207 | date.add!"months"(1, AllowDayOverflow.no); | |
5208 | assert(date == Date(1, 1, 1)); | |
5209 | } | |
5210 | ||
5211 | { | |
5212 | auto date = Date(4, 1, 1); | |
5213 | date.add!"months"(-48, AllowDayOverflow.no); | |
5214 | assert(date == Date(0, 1, 1)); | |
5215 | date.add!"months"(48, AllowDayOverflow.no); | |
5216 | assert(date == Date(4, 1, 1)); | |
5217 | } | |
5218 | ||
5219 | { | |
5220 | auto date = Date(4, 3, 31); | |
5221 | date.add!"months"(-49, AllowDayOverflow.no); | |
5222 | assert(date == Date(0, 2, 29)); | |
5223 | date.add!"months"(49, AllowDayOverflow.no); | |
5224 | assert(date == Date(4, 3, 29)); | |
5225 | } | |
5226 | ||
5227 | { | |
5228 | auto date = Date(4, 3, 31); | |
5229 | date.add!"months"(-85, AllowDayOverflow.no); | |
5230 | assert(date == Date(-3, 2, 28)); | |
5231 | date.add!"months"(85, AllowDayOverflow.no); | |
5232 | assert(date == Date(4, 3, 28)); | |
5233 | } | |
5234 | ||
5235 | { | |
5236 | auto date = Date(-3, 3, 31); | |
5237 | date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); | |
5238 | assert(date == Date(-3, 5, 30)); | |
5239 | } | |
5240 | } | |
5241 | ||
5242 | ||
5243 | /++ | |
5fee5ec3 IB |
5244 | Adds the given number of years or months to this $(LREF Date), mutating |
5245 | it. A negative number will subtract. | |
b4c522fa IB |
5246 | |
5247 | The difference between rolling and adding is that rolling does not | |
5248 | affect larger units. Rolling a $(LREF Date) 12 months gets | |
5249 | the exact same $(LREF Date). However, the days can still be affected due | |
5250 | to the differing number of days in each month. | |
5251 | ||
5252 | Because there are no units larger than years, there is no difference | |
5253 | between adding and rolling years. | |
5254 | ||
5255 | Params: | |
5256 | units = The type of units to add ("years" or "months"). | |
5257 | value = The number of months or years to add to this | |
5258 | $(LREF Date). | |
5259 | allowOverflow = Whether the day should be allowed to overflow, | |
5260 | causing the month to increment. | |
5fee5ec3 IB |
5261 | |
5262 | Returns: | |
5263 | A reference to the `Date` (`this`). | |
b4c522fa IB |
5264 | +/ |
5265 | @safe pure nothrow @nogc | |
5266 | ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) | |
5267 | if (units == "years") | |
5268 | { | |
5269 | return add!"years"(value, allowOverflow); | |
5270 | } | |
5271 | ||
5272 | /// | |
5273 | @safe unittest | |
5274 | { | |
5275 | auto d1 = Date(2010, 1, 1); | |
5276 | d1.roll!"months"(1); | |
5277 | assert(d1 == Date(2010, 2, 1)); | |
5278 | ||
5279 | auto d2 = Date(2010, 1, 1); | |
5280 | d2.roll!"months"(-1); | |
5281 | assert(d2 == Date(2010, 12, 1)); | |
5282 | ||
5283 | auto d3 = Date(1999, 1, 29); | |
5284 | d3.roll!"months"(1); | |
5285 | assert(d3 == Date(1999, 3, 1)); | |
5286 | ||
5287 | auto d4 = Date(1999, 1, 29); | |
5288 | d4.roll!"months"(1, AllowDayOverflow.no); | |
5289 | assert(d4 == Date(1999, 2, 28)); | |
5290 | ||
5291 | auto d5 = Date(2000, 2, 29); | |
5292 | d5.roll!"years"(1); | |
5293 | assert(d5 == Date(2001, 3, 1)); | |
5294 | ||
5295 | auto d6 = Date(2000, 2, 29); | |
5296 | d6.roll!"years"(1, AllowDayOverflow.no); | |
5297 | assert(d6 == Date(2001, 2, 28)); | |
5298 | } | |
5299 | ||
5300 | @safe unittest | |
5301 | { | |
5302 | const cdate = Date(1999, 7, 6); | |
5303 | immutable idate = Date(1999, 7, 6); | |
5304 | static assert(!__traits(compiles, cdate.roll!"years"(3))); | |
5305 | static assert(!__traits(compiles, idate.rolYears(3))); | |
5306 | } | |
5307 | ||
5308 | ||
5309 | // Shares documentation with "years" version. | |
5310 | @safe pure nothrow @nogc | |
5311 | ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) | |
5312 | if (units == "months") | |
5313 | { | |
5314 | months %= 12; | |
5315 | auto newMonth = _month + months; | |
5316 | ||
5317 | if (months < 0) | |
5318 | { | |
5319 | if (newMonth < 1) | |
5320 | newMonth += 12; | |
5321 | } | |
5322 | else | |
5323 | { | |
5324 | if (newMonth > 12) | |
5325 | newMonth -= 12; | |
5326 | } | |
5327 | ||
5328 | _month = cast(Month) newMonth; | |
5329 | ||
5330 | immutable currMaxDay = maxDay(_year, _month); | |
5331 | immutable overflow = _day - currMaxDay; | |
5332 | ||
5333 | if (overflow > 0) | |
5334 | { | |
5335 | if (allowOverflow == AllowDayOverflow.yes) | |
5336 | { | |
5337 | ++_month; | |
5338 | _day = cast(ubyte) overflow; | |
5339 | } | |
5340 | else | |
5341 | _day = cast(ubyte) currMaxDay; | |
5342 | } | |
5343 | ||
5344 | return this; | |
5345 | } | |
5346 | ||
5347 | // Test roll!"months"() with AllowDayOverflow.yes | |
5348 | @safe unittest | |
5349 | { | |
5350 | // Test A.D. | |
5351 | { | |
5352 | auto date = Date(1999, 7, 6); | |
5353 | date.roll!"months"(3); | |
5354 | assert(date == Date(1999, 10, 6)); | |
5355 | date.roll!"months"(-4); | |
5356 | assert(date == Date(1999, 6, 6)); | |
5357 | } | |
5358 | ||
5359 | { | |
5360 | auto date = Date(1999, 7, 6); | |
5361 | date.roll!"months"(6); | |
5362 | assert(date == Date(1999, 1, 6)); | |
5363 | date.roll!"months"(-6); | |
5364 | assert(date == Date(1999, 7, 6)); | |
5365 | } | |
5366 | ||
5367 | { | |
5368 | auto date = Date(1999, 7, 6); | |
5369 | date.roll!"months"(27); | |
5370 | assert(date == Date(1999, 10, 6)); | |
5371 | date.roll!"months"(-28); | |
5372 | assert(date == Date(1999, 6, 6)); | |
5373 | } | |
5374 | ||
5375 | { | |
5376 | auto date = Date(1999, 5, 31); | |
5377 | date.roll!"months"(1); | |
5378 | assert(date == Date(1999, 7, 1)); | |
5379 | } | |
5380 | ||
5381 | { | |
5382 | auto date = Date(1999, 5, 31); | |
5383 | date.roll!"months"(-1); | |
5384 | assert(date == Date(1999, 5, 1)); | |
5385 | } | |
5386 | ||
5387 | { | |
5388 | auto date = Date(1999, 2, 28); | |
5389 | date.roll!"months"(12); | |
5390 | assert(date == Date(1999, 2, 28)); | |
5391 | } | |
5392 | ||
5393 | { | |
5394 | auto date = Date(2000, 2, 29); | |
5395 | date.roll!"months"(12); | |
5396 | assert(date == Date(2000, 2, 29)); | |
5397 | } | |
5398 | ||
5399 | { | |
5400 | auto date = Date(1999, 7, 31); | |
5401 | date.roll!"months"(1); | |
5402 | assert(date == Date(1999, 8, 31)); | |
5403 | date.roll!"months"(1); | |
5404 | assert(date == Date(1999, 10, 1)); | |
5405 | } | |
5406 | ||
5407 | { | |
5408 | auto date = Date(1998, 8, 31); | |
5409 | date.roll!"months"(13); | |
5410 | assert(date == Date(1998, 10, 1)); | |
5411 | date.roll!"months"(-13); | |
5412 | assert(date == Date(1998, 9, 1)); | |
5413 | } | |
5414 | ||
5415 | { | |
5416 | auto date = Date(1997, 12, 31); | |
5417 | date.roll!"months"(13); | |
5418 | assert(date == Date(1997, 1, 31)); | |
5419 | date.roll!"months"(-13); | |
5420 | assert(date == Date(1997, 12, 31)); | |
5421 | } | |
5422 | ||
5423 | { | |
5424 | auto date = Date(1997, 12, 31); | |
5425 | date.roll!"months"(14); | |
5426 | assert(date == Date(1997, 3, 3)); | |
5427 | date.roll!"months"(-14); | |
5428 | assert(date == Date(1997, 1, 3)); | |
5429 | } | |
5430 | ||
5431 | { | |
5432 | auto date = Date(1998, 12, 31); | |
5433 | date.roll!"months"(14); | |
5434 | assert(date == Date(1998, 3, 3)); | |
5435 | date.roll!"months"(-14); | |
5436 | assert(date == Date(1998, 1, 3)); | |
5437 | } | |
5438 | ||
5439 | { | |
5440 | auto date = Date(1999, 12, 31); | |
5441 | date.roll!"months"(14); | |
5442 | assert(date == Date(1999, 3, 3)); | |
5443 | date.roll!"months"(-14); | |
5444 | assert(date == Date(1999, 1, 3)); | |
5445 | } | |
5446 | ||
5447 | // Test B.C. | |
5448 | { | |
5449 | auto date = Date(-1999, 7, 6); | |
5450 | date.roll!"months"(3); | |
5451 | assert(date == Date(-1999, 10, 6)); | |
5452 | date.roll!"months"(-4); | |
5453 | assert(date == Date(-1999, 6, 6)); | |
5454 | } | |
5455 | ||
5456 | { | |
5457 | auto date = Date(-1999, 7, 6); | |
5458 | date.roll!"months"(6); | |
5459 | assert(date == Date(-1999, 1, 6)); | |
5460 | date.roll!"months"(-6); | |
5461 | assert(date == Date(-1999, 7, 6)); | |
5462 | } | |
5463 | ||
5464 | { | |
5465 | auto date = Date(-1999, 7, 6); | |
5466 | date.roll!"months"(-27); | |
5467 | assert(date == Date(-1999, 4, 6)); | |
5468 | date.roll!"months"(28); | |
5469 | assert(date == Date(-1999, 8, 6)); | |
5470 | } | |
5471 | ||
5472 | { | |
5473 | auto date = Date(-1999, 5, 31); | |
5474 | date.roll!"months"(1); | |
5475 | assert(date == Date(-1999, 7, 1)); | |
5476 | } | |
5477 | ||
5478 | { | |
5479 | auto date = Date(-1999, 5, 31); | |
5480 | date.roll!"months"(-1); | |
5481 | assert(date == Date(-1999, 5, 1)); | |
5482 | } | |
5483 | ||
5484 | { | |
5485 | auto date = Date(-1999, 2, 28); | |
5486 | date.roll!"months"(-12); | |
5487 | assert(date == Date(-1999, 2, 28)); | |
5488 | } | |
5489 | ||
5490 | { | |
5491 | auto date = Date(-2000, 2, 29); | |
5492 | date.roll!"months"(-12); | |
5493 | assert(date == Date(-2000, 2, 29)); | |
5494 | } | |
5495 | ||
5496 | { | |
5497 | auto date = Date(-1999, 7, 31); | |
5498 | date.roll!"months"(1); | |
5499 | assert(date == Date(-1999, 8, 31)); | |
5500 | date.roll!"months"(1); | |
5501 | assert(date == Date(-1999, 10, 1)); | |
5502 | } | |
5503 | ||
5504 | { | |
5505 | auto date = Date(-1998, 8, 31); | |
5506 | date.roll!"months"(13); | |
5507 | assert(date == Date(-1998, 10, 1)); | |
5508 | date.roll!"months"(-13); | |
5509 | assert(date == Date(-1998, 9, 1)); | |
5510 | } | |
5511 | ||
5512 | { | |
5513 | auto date = Date(-1997, 12, 31); | |
5514 | date.roll!"months"(13); | |
5515 | assert(date == Date(-1997, 1, 31)); | |
5516 | date.roll!"months"(-13); | |
5517 | assert(date == Date(-1997, 12, 31)); | |
5518 | } | |
5519 | ||
5520 | { | |
5521 | auto date = Date(-1997, 12, 31); | |
5522 | date.roll!"months"(14); | |
5523 | assert(date == Date(-1997, 3, 3)); | |
5524 | date.roll!"months"(-14); | |
5525 | assert(date == Date(-1997, 1, 3)); | |
5526 | } | |
5527 | ||
5528 | { | |
5529 | auto date = Date(-2002, 12, 31); | |
5530 | date.roll!"months"(14); | |
5531 | assert(date == Date(-2002, 3, 3)); | |
5532 | date.roll!"months"(-14); | |
5533 | assert(date == Date(-2002, 1, 3)); | |
5534 | } | |
5535 | ||
5536 | { | |
5537 | auto date = Date(-2001, 12, 31); | |
5538 | date.roll!"months"(14); | |
5539 | assert(date == Date(-2001, 3, 3)); | |
5540 | date.roll!"months"(-14); | |
5541 | assert(date == Date(-2001, 1, 3)); | |
5542 | } | |
5543 | ||
5544 | // Test Both | |
5545 | { | |
5546 | auto date = Date(1, 1, 1); | |
5547 | date.roll!"months"(-1); | |
5548 | assert(date == Date(1, 12, 1)); | |
5549 | date.roll!"months"(1); | |
5550 | assert(date == Date(1, 1, 1)); | |
5551 | } | |
5552 | ||
5553 | { | |
5554 | auto date = Date(4, 1, 1); | |
5555 | date.roll!"months"(-48); | |
5556 | assert(date == Date(4, 1, 1)); | |
5557 | date.roll!"months"(48); | |
5558 | assert(date == Date(4, 1, 1)); | |
5559 | } | |
5560 | ||
5561 | { | |
5562 | auto date = Date(4, 3, 31); | |
5563 | date.roll!"months"(-49); | |
5564 | assert(date == Date(4, 3, 2)); | |
5565 | date.roll!"months"(49); | |
5566 | assert(date == Date(4, 4, 2)); | |
5567 | } | |
5568 | ||
5569 | { | |
5570 | auto date = Date(4, 3, 31); | |
5571 | date.roll!"months"(-85); | |
5572 | assert(date == Date(4, 3, 2)); | |
5573 | date.roll!"months"(85); | |
5574 | assert(date == Date(4, 4, 2)); | |
5575 | } | |
5576 | ||
5577 | { | |
5578 | auto date = Date(-1, 1, 1); | |
5579 | date.roll!"months"(-1); | |
5580 | assert(date == Date(-1, 12, 1)); | |
5581 | date.roll!"months"(1); | |
5582 | assert(date == Date(-1, 1, 1)); | |
5583 | } | |
5584 | ||
5585 | { | |
5586 | auto date = Date(-4, 1, 1); | |
5587 | date.roll!"months"(-48); | |
5588 | assert(date == Date(-4, 1, 1)); | |
5589 | date.roll!"months"(48); | |
5590 | assert(date == Date(-4, 1, 1)); | |
5591 | } | |
5592 | ||
5593 | { | |
5594 | auto date = Date(-4, 3, 31); | |
5595 | date.roll!"months"(-49); | |
5596 | assert(date == Date(-4, 3, 2)); | |
5597 | date.roll!"months"(49); | |
5598 | assert(date == Date(-4, 4, 2)); | |
5599 | } | |
5600 | ||
5601 | { | |
5602 | auto date = Date(-4, 3, 31); | |
5603 | date.roll!"months"(-85); | |
5604 | assert(date == Date(-4, 3, 2)); | |
5605 | date.roll!"months"(85); | |
5606 | assert(date == Date(-4, 4, 2)); | |
5607 | } | |
5608 | ||
5609 | { | |
5610 | auto date = Date(-3, 3, 31); | |
5611 | date.roll!"months"(85).roll!"months"(-83); | |
5612 | assert(date == Date(-3, 6, 1)); | |
5613 | } | |
5614 | ||
5615 | const cdate = Date(1999, 7, 6); | |
5616 | immutable idate = Date(1999, 7, 6); | |
5617 | static assert(!__traits(compiles, cdate.roll!"months"(3))); | |
5618 | static assert(!__traits(compiles, idate.roll!"months"(3))); | |
5619 | } | |
5620 | ||
5621 | // Test roll!"months"() with AllowDayOverflow.no | |
5622 | @safe unittest | |
5623 | { | |
5624 | // Test A.D. | |
5625 | { | |
5626 | auto date = Date(1999, 7, 6); | |
5627 | date.roll!"months"(3, AllowDayOverflow.no); | |
5628 | assert(date == Date(1999, 10, 6)); | |
5629 | date.roll!"months"(-4, AllowDayOverflow.no); | |
5630 | assert(date == Date(1999, 6, 6)); | |
5631 | } | |
5632 | ||
5633 | { | |
5634 | auto date = Date(1999, 7, 6); | |
5635 | date.roll!"months"(6, AllowDayOverflow.no); | |
5636 | assert(date == Date(1999, 1, 6)); | |
5637 | date.roll!"months"(-6, AllowDayOverflow.no); | |
5638 | assert(date == Date(1999, 7, 6)); | |
5639 | } | |
5640 | ||
5641 | { | |
5642 | auto date = Date(1999, 7, 6); | |
5643 | date.roll!"months"(27, AllowDayOverflow.no); | |
5644 | assert(date == Date(1999, 10, 6)); | |
5645 | date.roll!"months"(-28, AllowDayOverflow.no); | |
5646 | assert(date == Date(1999, 6, 6)); | |
5647 | } | |
5648 | ||
5649 | { | |
5650 | auto date = Date(1999, 5, 31); | |
5651 | date.roll!"months"(1, AllowDayOverflow.no); | |
5652 | assert(date == Date(1999, 6, 30)); | |
5653 | } | |
5654 | ||
5655 | { | |
5656 | auto date = Date(1999, 5, 31); | |
5657 | date.roll!"months"(-1, AllowDayOverflow.no); | |
5658 | assert(date == Date(1999, 4, 30)); | |
5659 | } | |
5660 | ||
5661 | { | |
5662 | auto date = Date(1999, 2, 28); | |
5663 | date.roll!"months"(12, AllowDayOverflow.no); | |
5664 | assert(date == Date(1999, 2, 28)); | |
5665 | } | |
5666 | ||
5667 | { | |
5668 | auto date = Date(2000, 2, 29); | |
5669 | date.roll!"months"(12, AllowDayOverflow.no); | |
5670 | assert(date == Date(2000, 2, 29)); | |
5671 | } | |
5672 | ||
5673 | { | |
5674 | auto date = Date(1999, 7, 31); | |
5675 | date.roll!"months"(1, AllowDayOverflow.no); | |
5676 | assert(date == Date(1999, 8, 31)); | |
5677 | date.roll!"months"(1, AllowDayOverflow.no); | |
5678 | assert(date == Date(1999, 9, 30)); | |
5679 | } | |
5680 | ||
5681 | { | |
5682 | auto date = Date(1998, 8, 31); | |
5683 | date.roll!"months"(13, AllowDayOverflow.no); | |
5684 | assert(date == Date(1998, 9, 30)); | |
5685 | date.roll!"months"(-13, AllowDayOverflow.no); | |
5686 | assert(date == Date(1998, 8, 30)); | |
5687 | } | |
5688 | ||
5689 | { | |
5690 | auto date = Date(1997, 12, 31); | |
5691 | date.roll!"months"(13, AllowDayOverflow.no); | |
5692 | assert(date == Date(1997, 1, 31)); | |
5693 | date.roll!"months"(-13, AllowDayOverflow.no); | |
5694 | assert(date == Date(1997, 12, 31)); | |
5695 | } | |
5696 | ||
5697 | { | |
5698 | auto date = Date(1997, 12, 31); | |
5699 | date.roll!"months"(14, AllowDayOverflow.no); | |
5700 | assert(date == Date(1997, 2, 28)); | |
5701 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5702 | assert(date == Date(1997, 12, 28)); | |
5703 | } | |
5704 | ||
5705 | { | |
5706 | auto date = Date(1998, 12, 31); | |
5707 | date.roll!"months"(14, AllowDayOverflow.no); | |
5708 | assert(date == Date(1998, 2, 28)); | |
5709 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5710 | assert(date == Date(1998, 12, 28)); | |
5711 | } | |
5712 | ||
5713 | { | |
5714 | auto date = Date(1999, 12, 31); | |
5715 | date.roll!"months"(14, AllowDayOverflow.no); | |
5716 | assert(date == Date(1999, 2, 28)); | |
5717 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5718 | assert(date == Date(1999, 12, 28)); | |
5719 | } | |
5720 | ||
5721 | // Test B.C. | |
5722 | { | |
5723 | auto date = Date(-1999, 7, 6); | |
5724 | date.roll!"months"(3, AllowDayOverflow.no); | |
5725 | assert(date == Date(-1999, 10, 6)); | |
5726 | date.roll!"months"(-4, AllowDayOverflow.no); | |
5727 | assert(date == Date(-1999, 6, 6)); | |
5728 | } | |
5729 | ||
5730 | { | |
5731 | auto date = Date(-1999, 7, 6); | |
5732 | date.roll!"months"(6, AllowDayOverflow.no); | |
5733 | assert(date == Date(-1999, 1, 6)); | |
5734 | date.roll!"months"(-6, AllowDayOverflow.no); | |
5735 | assert(date == Date(-1999, 7, 6)); | |
5736 | } | |
5737 | ||
5738 | { | |
5739 | auto date = Date(-1999, 7, 6); | |
5740 | date.roll!"months"(-27, AllowDayOverflow.no); | |
5741 | assert(date == Date(-1999, 4, 6)); | |
5742 | date.roll!"months"(28, AllowDayOverflow.no); | |
5743 | assert(date == Date(-1999, 8, 6)); | |
5744 | } | |
5745 | ||
5746 | { | |
5747 | auto date = Date(-1999, 5, 31); | |
5748 | date.roll!"months"(1, AllowDayOverflow.no); | |
5749 | assert(date == Date(-1999, 6, 30)); | |
5750 | } | |
5751 | ||
5752 | { | |
5753 | auto date = Date(-1999, 5, 31); | |
5754 | date.roll!"months"(-1, AllowDayOverflow.no); | |
5755 | assert(date == Date(-1999, 4, 30)); | |
5756 | } | |
5757 | ||
5758 | { | |
5759 | auto date = Date(-1999, 2, 28); | |
5760 | date.roll!"months"(-12, AllowDayOverflow.no); | |
5761 | assert(date == Date(-1999, 2, 28)); | |
5762 | } | |
5763 | ||
5764 | { | |
5765 | auto date = Date(-2000, 2, 29); | |
5766 | date.roll!"months"(-12, AllowDayOverflow.no); | |
5767 | assert(date == Date(-2000, 2, 29)); | |
5768 | } | |
5769 | ||
5770 | { | |
5771 | auto date = Date(-1999, 7, 31); | |
5772 | date.roll!"months"(1, AllowDayOverflow.no); | |
5773 | assert(date == Date(-1999, 8, 31)); | |
5774 | date.roll!"months"(1, AllowDayOverflow.no); | |
5775 | assert(date == Date(-1999, 9, 30)); | |
5776 | } | |
5777 | ||
5778 | { | |
5779 | auto date = Date(-1998, 8, 31); | |
5780 | date.roll!"months"(13, AllowDayOverflow.no); | |
5781 | assert(date == Date(-1998, 9, 30)); | |
5782 | date.roll!"months"(-13, AllowDayOverflow.no); | |
5783 | assert(date == Date(-1998, 8, 30)); | |
5784 | } | |
5785 | ||
5786 | { | |
5787 | auto date = Date(-1997, 12, 31); | |
5788 | date.roll!"months"(13, AllowDayOverflow.no); | |
5789 | assert(date == Date(-1997, 1, 31)); | |
5790 | date.roll!"months"(-13, AllowDayOverflow.no); | |
5791 | assert(date == Date(-1997, 12, 31)); | |
5792 | } | |
5793 | ||
5794 | { | |
5795 | auto date = Date(-1997, 12, 31); | |
5796 | date.roll!"months"(14, AllowDayOverflow.no); | |
5797 | assert(date == Date(-1997, 2, 28)); | |
5798 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5799 | assert(date == Date(-1997, 12, 28)); | |
5800 | } | |
5801 | ||
5802 | { | |
5803 | auto date = Date(-2002, 12, 31); | |
5804 | date.roll!"months"(14, AllowDayOverflow.no); | |
5805 | assert(date == Date(-2002, 2, 28)); | |
5806 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5807 | assert(date == Date(-2002, 12, 28)); | |
5808 | } | |
5809 | ||
5810 | { | |
5811 | auto date = Date(-2001, 12, 31); | |
5812 | date.roll!"months"(14, AllowDayOverflow.no); | |
5813 | assert(date == Date(-2001, 2, 28)); | |
5814 | date.roll!"months"(-14, AllowDayOverflow.no); | |
5815 | assert(date == Date(-2001, 12, 28)); | |
5816 | } | |
5817 | ||
5818 | // Test Both | |
5819 | { | |
5820 | auto date = Date(1, 1, 1); | |
5821 | date.roll!"months"(-1, AllowDayOverflow.no); | |
5822 | assert(date == Date(1, 12, 1)); | |
5823 | date.roll!"months"(1, AllowDayOverflow.no); | |
5824 | assert(date == Date(1, 1, 1)); | |
5825 | } | |
5826 | ||
5827 | { | |
5828 | auto date = Date(4, 1, 1); | |
5829 | date.roll!"months"(-48, AllowDayOverflow.no); | |
5830 | assert(date == Date(4, 1, 1)); | |
5831 | date.roll!"months"(48, AllowDayOverflow.no); | |
5832 | assert(date == Date(4, 1, 1)); | |
5833 | } | |
5834 | ||
5835 | { | |
5836 | auto date = Date(4, 3, 31); | |
5837 | date.roll!"months"(-49, AllowDayOverflow.no); | |
5838 | assert(date == Date(4, 2, 29)); | |
5839 | date.roll!"months"(49, AllowDayOverflow.no); | |
5840 | assert(date == Date(4, 3, 29)); | |
5841 | } | |
5842 | ||
5843 | { | |
5844 | auto date = Date(4, 3, 31); | |
5845 | date.roll!"months"(-85, AllowDayOverflow.no); | |
5846 | assert(date == Date(4, 2, 29)); | |
5847 | date.roll!"months"(85, AllowDayOverflow.no); | |
5848 | assert(date == Date(4, 3, 29)); | |
5849 | } | |
5850 | ||
5851 | { | |
5852 | auto date = Date(-1, 1, 1); | |
5853 | date.roll!"months"(-1, AllowDayOverflow.no); | |
5854 | assert(date == Date(-1, 12, 1)); | |
5855 | date.roll!"months"(1, AllowDayOverflow.no); | |
5856 | assert(date == Date(-1, 1, 1)); | |
5857 | } | |
5858 | ||
5859 | { | |
5860 | auto date = Date(-4, 1, 1); | |
5861 | date.roll!"months"(-48, AllowDayOverflow.no); | |
5862 | assert(date == Date(-4, 1, 1)); | |
5863 | date.roll!"months"(48, AllowDayOverflow.no); | |
5864 | assert(date == Date(-4, 1, 1)); | |
5865 | } | |
5866 | ||
5867 | { | |
5868 | auto date = Date(-4, 3, 31); | |
5869 | date.roll!"months"(-49, AllowDayOverflow.no); | |
5870 | assert(date == Date(-4, 2, 29)); | |
5871 | date.roll!"months"(49, AllowDayOverflow.no); | |
5872 | assert(date == Date(-4, 3, 29)); | |
5873 | } | |
5874 | ||
5875 | { | |
5876 | auto date = Date(-4, 3, 31); | |
5877 | date.roll!"months"(-85, AllowDayOverflow.no); | |
5878 | assert(date == Date(-4, 2, 29)); | |
5879 | date.roll!"months"(85, AllowDayOverflow.no); | |
5880 | assert(date == Date(-4, 3, 29)); | |
5881 | } | |
5882 | ||
5883 | { | |
5884 | auto date = Date(-3, 3, 31); | |
5885 | date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); | |
5886 | assert(date == Date(-3, 5, 30)); | |
5887 | } | |
5888 | } | |
5889 | ||
5890 | ||
5891 | /++ | |
5fee5ec3 IB |
5892 | Adds the given number of units to this $(LREF Date), mutating it. A |
5893 | negative number will subtract. | |
b4c522fa IB |
5894 | |
5895 | The difference between rolling and adding is that rolling does not | |
5896 | affect larger units. For instance, rolling a $(LREF Date) one | |
5897 | year's worth of days gets the exact same $(LREF Date). | |
5898 | ||
5fee5ec3 | 5899 | The only accepted units are `"days"`. |
b4c522fa IB |
5900 | |
5901 | Params: | |
5fee5ec3 | 5902 | units = The units to add. Must be `"days"`. |
b4c522fa | 5903 | days = The number of days to add to this $(LREF Date). |
5fee5ec3 IB |
5904 | |
5905 | Returns: | |
5906 | A reference to the `Date` (`this`). | |
b4c522fa IB |
5907 | +/ |
5908 | ref Date roll(string units)(long days) @safe pure nothrow @nogc | |
5909 | if (units == "days") | |
5910 | { | |
5911 | immutable limit = maxDay(_year, _month); | |
5912 | days %= limit; | |
5913 | auto newDay = _day + days; | |
5914 | ||
5915 | if (days < 0) | |
5916 | { | |
5917 | if (newDay < 1) | |
5918 | newDay += limit; | |
5919 | } | |
5920 | else if (newDay > limit) | |
5921 | newDay -= limit; | |
5922 | ||
5923 | _day = cast(ubyte) newDay; | |
5924 | return this; | |
5925 | } | |
5926 | ||
5927 | /// | |
5928 | @safe unittest | |
5929 | { | |
5930 | auto d = Date(2010, 1, 1); | |
5931 | d.roll!"days"(1); | |
5932 | assert(d == Date(2010, 1, 2)); | |
5933 | d.roll!"days"(365); | |
5934 | assert(d == Date(2010, 1, 26)); | |
5935 | d.roll!"days"(-32); | |
5936 | assert(d == Date(2010, 1, 25)); | |
5937 | } | |
5938 | ||
5939 | @safe unittest | |
5940 | { | |
5941 | // Test A.D. | |
5942 | { | |
5943 | auto date = Date(1999, 2, 28); | |
5944 | date.roll!"days"(1); | |
5945 | assert(date == Date(1999, 2, 1)); | |
5946 | date.roll!"days"(-1); | |
5947 | assert(date == Date(1999, 2, 28)); | |
5948 | } | |
5949 | ||
5950 | { | |
5951 | auto date = Date(2000, 2, 28); | |
5952 | date.roll!"days"(1); | |
5953 | assert(date == Date(2000, 2, 29)); | |
5954 | date.roll!"days"(1); | |
5955 | assert(date == Date(2000, 2, 1)); | |
5956 | date.roll!"days"(-1); | |
5957 | assert(date == Date(2000, 2, 29)); | |
5958 | } | |
5959 | ||
5960 | { | |
5961 | auto date = Date(1999, 6, 30); | |
5962 | date.roll!"days"(1); | |
5963 | assert(date == Date(1999, 6, 1)); | |
5964 | date.roll!"days"(-1); | |
5965 | assert(date == Date(1999, 6, 30)); | |
5966 | } | |
5967 | ||
5968 | { | |
5969 | auto date = Date(1999, 7, 31); | |
5970 | date.roll!"days"(1); | |
5971 | assert(date == Date(1999, 7, 1)); | |
5972 | date.roll!"days"(-1); | |
5973 | assert(date == Date(1999, 7, 31)); | |
5974 | } | |
5975 | ||
5976 | { | |
5977 | auto date = Date(1999, 1, 1); | |
5978 | date.roll!"days"(-1); | |
5979 | assert(date == Date(1999, 1, 31)); | |
5980 | date.roll!"days"(1); | |
5981 | assert(date == Date(1999, 1, 1)); | |
5982 | } | |
5983 | ||
5984 | { | |
5985 | auto date = Date(1999, 7, 6); | |
5986 | date.roll!"days"(9); | |
5987 | assert(date == Date(1999, 7, 15)); | |
5988 | date.roll!"days"(-11); | |
5989 | assert(date == Date(1999, 7, 4)); | |
5990 | date.roll!"days"(30); | |
5991 | assert(date == Date(1999, 7, 3)); | |
5992 | date.roll!"days"(-3); | |
5993 | assert(date == Date(1999, 7, 31)); | |
5994 | } | |
5995 | ||
5996 | { | |
5997 | auto date = Date(1999, 7, 6); | |
5998 | date.roll!"days"(365); | |
5999 | assert(date == Date(1999, 7, 30)); | |
6000 | date.roll!"days"(-365); | |
6001 | assert(date == Date(1999, 7, 6)); | |
6002 | date.roll!"days"(366); | |
6003 | assert(date == Date(1999, 7, 31)); | |
6004 | date.roll!"days"(730); | |
6005 | assert(date == Date(1999, 7, 17)); | |
6006 | date.roll!"days"(-1096); | |
6007 | assert(date == Date(1999, 7, 6)); | |
6008 | } | |
6009 | ||
6010 | { | |
6011 | auto date = Date(1999, 2, 6); | |
6012 | date.roll!"days"(365); | |
6013 | assert(date == Date(1999, 2, 7)); | |
6014 | date.roll!"days"(-365); | |
6015 | assert(date == Date(1999, 2, 6)); | |
6016 | date.roll!"days"(366); | |
6017 | assert(date == Date(1999, 2, 8)); | |
6018 | date.roll!"days"(730); | |
6019 | assert(date == Date(1999, 2, 10)); | |
6020 | date.roll!"days"(-1096); | |
6021 | assert(date == Date(1999, 2, 6)); | |
6022 | } | |
6023 | ||
6024 | // Test B.C. | |
6025 | { | |
6026 | auto date = Date(-1999, 2, 28); | |
6027 | date.roll!"days"(1); | |
6028 | assert(date == Date(-1999, 2, 1)); | |
6029 | date.roll!"days"(-1); | |
6030 | assert(date == Date(-1999, 2, 28)); | |
6031 | } | |
6032 | ||
6033 | { | |
6034 | auto date = Date(-2000, 2, 28); | |
6035 | date.roll!"days"(1); | |
6036 | assert(date == Date(-2000, 2, 29)); | |
6037 | date.roll!"days"(1); | |
6038 | assert(date == Date(-2000, 2, 1)); | |
6039 | date.roll!"days"(-1); | |
6040 | assert(date == Date(-2000, 2, 29)); | |
6041 | } | |
6042 | ||
6043 | { | |
6044 | auto date = Date(-1999, 6, 30); | |
6045 | date.roll!"days"(1); | |
6046 | assert(date == Date(-1999, 6, 1)); | |
6047 | date.roll!"days"(-1); | |
6048 | assert(date == Date(-1999, 6, 30)); | |
6049 | } | |
6050 | ||
6051 | { | |
6052 | auto date = Date(-1999, 7, 31); | |
6053 | date.roll!"days"(1); | |
6054 | assert(date == Date(-1999, 7, 1)); | |
6055 | date.roll!"days"(-1); | |
6056 | assert(date == Date(-1999, 7, 31)); | |
6057 | } | |
6058 | ||
6059 | { | |
6060 | auto date = Date(-1999, 1, 1); | |
6061 | date.roll!"days"(-1); | |
6062 | assert(date == Date(-1999, 1, 31)); | |
6063 | date.roll!"days"(1); | |
6064 | assert(date == Date(-1999, 1, 1)); | |
6065 | } | |
6066 | ||
6067 | { | |
6068 | auto date = Date(-1999, 7, 6); | |
6069 | date.roll!"days"(9); | |
6070 | assert(date == Date(-1999, 7, 15)); | |
6071 | date.roll!"days"(-11); | |
6072 | assert(date == Date(-1999, 7, 4)); | |
6073 | date.roll!"days"(30); | |
6074 | assert(date == Date(-1999, 7, 3)); | |
6075 | date.roll!"days"(-3); | |
6076 | assert(date == Date(-1999, 7, 31)); | |
6077 | } | |
6078 | ||
6079 | { | |
6080 | auto date = Date(-1999, 7, 6); | |
6081 | date.roll!"days"(365); | |
6082 | assert(date == Date(-1999, 7, 30)); | |
6083 | date.roll!"days"(-365); | |
6084 | assert(date == Date(-1999, 7, 6)); | |
6085 | date.roll!"days"(366); | |
6086 | assert(date == Date(-1999, 7, 31)); | |
6087 | date.roll!"days"(730); | |
6088 | assert(date == Date(-1999, 7, 17)); | |
6089 | date.roll!"days"(-1096); | |
6090 | assert(date == Date(-1999, 7, 6)); | |
6091 | } | |
6092 | ||
6093 | // Test Both | |
6094 | { | |
6095 | auto date = Date(1, 7, 6); | |
6096 | date.roll!"days"(-365); | |
6097 | assert(date == Date(1, 7, 13)); | |
6098 | date.roll!"days"(365); | |
6099 | assert(date == Date(1, 7, 6)); | |
6100 | date.roll!"days"(-731); | |
6101 | assert(date == Date(1, 7, 19)); | |
6102 | date.roll!"days"(730); | |
6103 | assert(date == Date(1, 7, 5)); | |
6104 | } | |
6105 | ||
6106 | { | |
6107 | auto date = Date(0, 7, 6); | |
6108 | date.roll!"days"(-365); | |
6109 | assert(date == Date(0, 7, 13)); | |
6110 | date.roll!"days"(365); | |
6111 | assert(date == Date(0, 7, 6)); | |
6112 | date.roll!"days"(-731); | |
6113 | assert(date == Date(0, 7, 19)); | |
6114 | date.roll!"days"(730); | |
6115 | assert(date == Date(0, 7, 5)); | |
6116 | } | |
6117 | ||
6118 | { | |
6119 | auto date = Date(0, 7, 6); | |
6120 | date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); | |
6121 | assert(date == Date(0, 7, 8)); | |
6122 | } | |
6123 | ||
6124 | const cdate = Date(1999, 7, 6); | |
6125 | immutable idate = Date(1999, 7, 6); | |
6126 | static assert(!__traits(compiles, cdate.roll!"days"(12))); | |
6127 | static assert(!__traits(compiles, idate.roll!"days"(12))); | |
6128 | } | |
6129 | ||
5fee5ec3 | 6130 | import core.time : Duration; |
b4c522fa IB |
6131 | /++ |
6132 | Gives the result of adding or subtracting a $(REF Duration, core,time) | |
6133 | from | |
6134 | ||
6135 | The legal types of arithmetic for $(LREF Date) using this operator are | |
6136 | ||
6137 | $(BOOKTABLE, | |
6138 | $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) | |
6139 | $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) | |
6140 | ) | |
6141 | ||
6142 | Params: | |
6143 | duration = The $(REF Duration, core,time) to add to or subtract from | |
6144 | this $(LREF Date). | |
6145 | +/ | |
6146 | Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc | |
6147 | if (op == "+" || op == "-") | |
6148 | { | |
6149 | Date retval = this; | |
6150 | immutable days = duration.total!"days"; | |
6151 | mixin("return retval._addDays(" ~ op ~ "days);"); | |
6152 | } | |
6153 | ||
6154 | /// | |
6155 | @safe unittest | |
6156 | { | |
6157 | import core.time : days; | |
6158 | ||
6159 | assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); | |
6160 | assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); | |
6161 | ||
6162 | assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); | |
6163 | assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); | |
6164 | } | |
6165 | ||
6166 | @safe unittest | |
6167 | { | |
6168 | auto date = Date(1999, 7, 6); | |
6169 | ||
5fee5ec3 | 6170 | import core.time : dur; |
b4c522fa IB |
6171 | assert(date + dur!"weeks"(7) == Date(1999, 8, 24)); |
6172 | assert(date + dur!"weeks"(-7) == Date(1999, 5, 18)); | |
6173 | assert(date + dur!"days"(7) == Date(1999, 7, 13)); | |
6174 | assert(date + dur!"days"(-7) == Date(1999, 6, 29)); | |
6175 | ||
6176 | assert(date + dur!"hours"(24) == Date(1999, 7, 7)); | |
6177 | assert(date + dur!"hours"(-24) == Date(1999, 7, 5)); | |
6178 | assert(date + dur!"minutes"(1440) == Date(1999, 7, 7)); | |
6179 | assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5)); | |
6180 | assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7)); | |
6181 | assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5)); | |
6182 | assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); | |
6183 | assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); | |
6184 | assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); | |
6185 | assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); | |
6186 | assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); | |
6187 | assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); | |
6188 | ||
6189 | assert(date - dur!"weeks"(-7) == Date(1999, 8, 24)); | |
6190 | assert(date - dur!"weeks"(7) == Date(1999, 5, 18)); | |
6191 | assert(date - dur!"days"(-7) == Date(1999, 7, 13)); | |
6192 | assert(date - dur!"days"(7) == Date(1999, 6, 29)); | |
6193 | ||
6194 | assert(date - dur!"hours"(-24) == Date(1999, 7, 7)); | |
6195 | assert(date - dur!"hours"(24) == Date(1999, 7, 5)); | |
6196 | assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7)); | |
6197 | assert(date - dur!"minutes"(1440) == Date(1999, 7, 5)); | |
6198 | assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7)); | |
6199 | assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5)); | |
6200 | assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); | |
6201 | assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); | |
6202 | assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); | |
6203 | assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); | |
6204 | assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); | |
6205 | assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); | |
6206 | ||
6207 | auto duration = dur!"days"(12); | |
6208 | const cdate = Date(1999, 7, 6); | |
6209 | immutable idate = Date(1999, 7, 6); | |
6210 | assert(date + duration == Date(1999, 7, 18)); | |
6211 | assert(cdate + duration == Date(1999, 7, 18)); | |
6212 | assert(idate + duration == Date(1999, 7, 18)); | |
6213 | ||
6214 | assert(date - duration == Date(1999, 6, 24)); | |
6215 | assert(cdate - duration == Date(1999, 6, 24)); | |
6216 | assert(idate - duration == Date(1999, 6, 24)); | |
6217 | } | |
6218 | ||
b4c522fa IB |
6219 | |
6220 | /++ | |
6221 | Gives the result of adding or subtracting a $(REF Duration, core,time) | |
6222 | from this $(LREF Date), as well as assigning the result to this | |
6223 | $(LREF Date). | |
6224 | ||
6225 | The legal types of arithmetic for $(LREF Date) using this operator are | |
6226 | ||
6227 | $(BOOKTABLE, | |
6228 | $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) | |
6229 | $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) | |
6230 | ) | |
6231 | ||
6232 | Params: | |
6233 | duration = The $(REF Duration, core,time) to add to or subtract from | |
6234 | this $(LREF Date). | |
6235 | +/ | |
6236 | ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc | |
6237 | if (op == "+" || op == "-") | |
6238 | { | |
6239 | immutable days = duration.total!"days"; | |
6240 | mixin("return _addDays(" ~ op ~ "days);"); | |
6241 | } | |
6242 | ||
6243 | @safe unittest | |
6244 | { | |
5fee5ec3 | 6245 | import core.time : dur; |
b4c522fa IB |
6246 | assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24)); |
6247 | assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18)); | |
6248 | assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13)); | |
6249 | assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29)); | |
6250 | ||
6251 | assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7)); | |
6252 | assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5)); | |
6253 | assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7)); | |
6254 | assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5)); | |
6255 | assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7)); | |
6256 | assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5)); | |
6257 | assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); | |
6258 | assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); | |
6259 | assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); | |
6260 | assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); | |
6261 | assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); | |
6262 | assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); | |
6263 | ||
6264 | assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24)); | |
6265 | assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18)); | |
6266 | assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13)); | |
6267 | assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29)); | |
6268 | ||
6269 | assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7)); | |
6270 | assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5)); | |
6271 | assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7)); | |
6272 | assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5)); | |
6273 | assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7)); | |
6274 | assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5)); | |
6275 | assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); | |
6276 | assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); | |
6277 | assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); | |
6278 | assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); | |
6279 | assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); | |
6280 | assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); | |
6281 | ||
6282 | { | |
6283 | auto date = Date(0, 1, 31); | |
6284 | (date += dur!"days"(507)) += dur!"days"(-2); | |
6285 | assert(date == Date(1, 6, 19)); | |
6286 | } | |
6287 | ||
6288 | auto duration = dur!"days"(12); | |
6289 | auto date = Date(1999, 7, 6); | |
6290 | const cdate = Date(1999, 7, 6); | |
6291 | immutable idate = Date(1999, 7, 6); | |
6292 | date += duration; | |
6293 | static assert(!__traits(compiles, cdate += duration)); | |
6294 | static assert(!__traits(compiles, idate += duration)); | |
6295 | ||
6296 | date -= duration; | |
6297 | static assert(!__traits(compiles, cdate -= duration)); | |
6298 | static assert(!__traits(compiles, idate -= duration)); | |
6299 | } | |
6300 | ||
b4c522fa IB |
6301 | |
6302 | /++ | |
6303 | Gives the difference between two $(LREF Date)s. | |
6304 | ||
6305 | The legal types of arithmetic for $(LREF Date) using this operator are | |
6306 | ||
6307 | $(BOOKTABLE, | |
6308 | $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration)) | |
6309 | ) | |
6310 | +/ | |
5fee5ec3 | 6311 | Duration opBinary(string op)(Date rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
6312 | if (op == "-") |
6313 | { | |
5fee5ec3 | 6314 | import core.time : dur; |
b4c522fa IB |
6315 | return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal); |
6316 | } | |
6317 | ||
6318 | @safe unittest | |
6319 | { | |
6320 | auto date = Date(1999, 7, 6); | |
6321 | ||
5fee5ec3 | 6322 | import core.time : dur; |
b4c522fa IB |
6323 | assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365)); |
6324 | assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365)); | |
6325 | assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31)); | |
6326 | assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31)); | |
6327 | assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1)); | |
6328 | assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1)); | |
6329 | ||
6330 | const cdate = Date(1999, 7, 6); | |
6331 | immutable idate = Date(1999, 7, 6); | |
6332 | assert(date - date == Duration.zero); | |
6333 | assert(cdate - date == Duration.zero); | |
6334 | assert(idate - date == Duration.zero); | |
6335 | ||
6336 | assert(date - cdate == Duration.zero); | |
6337 | assert(cdate - cdate == Duration.zero); | |
6338 | assert(idate - cdate == Duration.zero); | |
6339 | ||
6340 | assert(date - idate == Duration.zero); | |
6341 | assert(cdate - idate == Duration.zero); | |
6342 | assert(idate - idate == Duration.zero); | |
6343 | } | |
6344 | ||
6345 | ||
6346 | /++ | |
6347 | Returns the difference between the two $(LREF Date)s in months. | |
6348 | ||
6349 | To get the difference in years, subtract the year property | |
6350 | of two $(LREF Date)s. To get the difference in days or weeks, | |
6351 | subtract the $(LREF Date)s themselves and use the | |
6352 | $(REF Duration, core,time) that results. Because converting between | |
6353 | months and smaller units requires a specific date (which | |
6354 | $(REF Duration, core,time)s don't have), getting the difference in | |
6355 | months requires some math using both the year and month properties, so | |
6356 | this is a convenience function for getting the difference in months. | |
6357 | ||
6358 | Note that the number of days in the months or how far into the month | |
6359 | either $(LREF Date) is is irrelevant. It is the difference in the month | |
6360 | property combined with the difference in years * 12. So, for instance, | |
6361 | December 31st and January 1st are one month apart just as December 1st | |
6362 | and January 31st are one month apart. | |
6363 | ||
6364 | Params: | |
6365 | rhs = The $(LREF Date) to subtract from this one. | |
6366 | +/ | |
5fee5ec3 | 6367 | int diffMonths(Date rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
6368 | { |
6369 | immutable yearDiff = _year - rhs._year; | |
6370 | immutable monthDiff = _month - rhs._month; | |
6371 | ||
6372 | return yearDiff * 12 + monthDiff; | |
6373 | } | |
6374 | ||
6375 | /// | |
6376 | @safe unittest | |
6377 | { | |
6378 | assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); | |
6379 | assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); | |
6380 | assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); | |
6381 | assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); | |
6382 | } | |
6383 | ||
6384 | @safe unittest | |
6385 | { | |
6386 | auto date = Date(1999, 7, 6); | |
6387 | ||
6388 | // Test A.D. | |
6389 | assert(date.diffMonths(Date(1998, 6, 5)) == 13); | |
6390 | assert(date.diffMonths(Date(1998, 7, 5)) == 12); | |
6391 | assert(date.diffMonths(Date(1998, 8, 5)) == 11); | |
6392 | assert(date.diffMonths(Date(1998, 9, 5)) == 10); | |
6393 | assert(date.diffMonths(Date(1998, 10, 5)) == 9); | |
6394 | assert(date.diffMonths(Date(1998, 11, 5)) == 8); | |
6395 | assert(date.diffMonths(Date(1998, 12, 5)) == 7); | |
6396 | assert(date.diffMonths(Date(1999, 1, 5)) == 6); | |
6397 | assert(date.diffMonths(Date(1999, 2, 6)) == 5); | |
6398 | assert(date.diffMonths(Date(1999, 3, 6)) == 4); | |
6399 | assert(date.diffMonths(Date(1999, 4, 6)) == 3); | |
6400 | assert(date.diffMonths(Date(1999, 5, 6)) == 2); | |
6401 | assert(date.diffMonths(Date(1999, 6, 6)) == 1); | |
6402 | assert(date.diffMonths(date) == 0); | |
6403 | assert(date.diffMonths(Date(1999, 8, 6)) == -1); | |
6404 | assert(date.diffMonths(Date(1999, 9, 6)) == -2); | |
6405 | assert(date.diffMonths(Date(1999, 10, 6)) == -3); | |
6406 | assert(date.diffMonths(Date(1999, 11, 6)) == -4); | |
6407 | assert(date.diffMonths(Date(1999, 12, 6)) == -5); | |
6408 | assert(date.diffMonths(Date(2000, 1, 6)) == -6); | |
6409 | assert(date.diffMonths(Date(2000, 2, 6)) == -7); | |
6410 | assert(date.diffMonths(Date(2000, 3, 6)) == -8); | |
6411 | assert(date.diffMonths(Date(2000, 4, 6)) == -9); | |
6412 | assert(date.diffMonths(Date(2000, 5, 6)) == -10); | |
6413 | assert(date.diffMonths(Date(2000, 6, 6)) == -11); | |
6414 | assert(date.diffMonths(Date(2000, 7, 6)) == -12); | |
6415 | assert(date.diffMonths(Date(2000, 8, 6)) == -13); | |
6416 | ||
6417 | assert(Date(1998, 6, 5).diffMonths(date) == -13); | |
6418 | assert(Date(1998, 7, 5).diffMonths(date) == -12); | |
6419 | assert(Date(1998, 8, 5).diffMonths(date) == -11); | |
6420 | assert(Date(1998, 9, 5).diffMonths(date) == -10); | |
6421 | assert(Date(1998, 10, 5).diffMonths(date) == -9); | |
6422 | assert(Date(1998, 11, 5).diffMonths(date) == -8); | |
6423 | assert(Date(1998, 12, 5).diffMonths(date) == -7); | |
6424 | assert(Date(1999, 1, 5).diffMonths(date) == -6); | |
6425 | assert(Date(1999, 2, 6).diffMonths(date) == -5); | |
6426 | assert(Date(1999, 3, 6).diffMonths(date) == -4); | |
6427 | assert(Date(1999, 4, 6).diffMonths(date) == -3); | |
6428 | assert(Date(1999, 5, 6).diffMonths(date) == -2); | |
6429 | assert(Date(1999, 6, 6).diffMonths(date) == -1); | |
6430 | assert(Date(1999, 8, 6).diffMonths(date) == 1); | |
6431 | assert(Date(1999, 9, 6).diffMonths(date) == 2); | |
6432 | assert(Date(1999, 10, 6).diffMonths(date) == 3); | |
6433 | assert(Date(1999, 11, 6).diffMonths(date) == 4); | |
6434 | assert(Date(1999, 12, 6).diffMonths(date) == 5); | |
6435 | assert(Date(2000, 1, 6).diffMonths(date) == 6); | |
6436 | assert(Date(2000, 2, 6).diffMonths(date) == 7); | |
6437 | assert(Date(2000, 3, 6).diffMonths(date) == 8); | |
6438 | assert(Date(2000, 4, 6).diffMonths(date) == 9); | |
6439 | assert(Date(2000, 5, 6).diffMonths(date) == 10); | |
6440 | assert(Date(2000, 6, 6).diffMonths(date) == 11); | |
6441 | assert(Date(2000, 7, 6).diffMonths(date) == 12); | |
6442 | assert(Date(2000, 8, 6).diffMonths(date) == 13); | |
6443 | ||
6444 | assert(date.diffMonths(Date(1999, 6, 30)) == 1); | |
6445 | assert(date.diffMonths(Date(1999, 7, 1)) == 0); | |
6446 | assert(date.diffMonths(Date(1999, 7, 6)) == 0); | |
6447 | assert(date.diffMonths(Date(1999, 7, 11)) == 0); | |
6448 | assert(date.diffMonths(Date(1999, 7, 16)) == 0); | |
6449 | assert(date.diffMonths(Date(1999, 7, 21)) == 0); | |
6450 | assert(date.diffMonths(Date(1999, 7, 26)) == 0); | |
6451 | assert(date.diffMonths(Date(1999, 7, 31)) == 0); | |
6452 | assert(date.diffMonths(Date(1999, 8, 1)) == -1); | |
6453 | ||
6454 | assert(date.diffMonths(Date(1990, 6, 30)) == 109); | |
6455 | assert(date.diffMonths(Date(1990, 7, 1)) == 108); | |
6456 | assert(date.diffMonths(Date(1990, 7, 6)) == 108); | |
6457 | assert(date.diffMonths(Date(1990, 7, 11)) == 108); | |
6458 | assert(date.diffMonths(Date(1990, 7, 16)) == 108); | |
6459 | assert(date.diffMonths(Date(1990, 7, 21)) == 108); | |
6460 | assert(date.diffMonths(Date(1990, 7, 26)) == 108); | |
6461 | assert(date.diffMonths(Date(1990, 7, 31)) == 108); | |
6462 | assert(date.diffMonths(Date(1990, 8, 1)) == 107); | |
6463 | ||
6464 | assert(Date(1999, 6, 30).diffMonths(date) == -1); | |
6465 | assert(Date(1999, 7, 1).diffMonths(date) == 0); | |
6466 | assert(Date(1999, 7, 6).diffMonths(date) == 0); | |
6467 | assert(Date(1999, 7, 11).diffMonths(date) == 0); | |
6468 | assert(Date(1999, 7, 16).diffMonths(date) == 0); | |
6469 | assert(Date(1999, 7, 21).diffMonths(date) == 0); | |
6470 | assert(Date(1999, 7, 26).diffMonths(date) == 0); | |
6471 | assert(Date(1999, 7, 31).diffMonths(date) == 0); | |
6472 | assert(Date(1999, 8, 1).diffMonths(date) == 1); | |
6473 | ||
6474 | assert(Date(1990, 6, 30).diffMonths(date) == -109); | |
6475 | assert(Date(1990, 7, 1).diffMonths(date) == -108); | |
6476 | assert(Date(1990, 7, 6).diffMonths(date) == -108); | |
6477 | assert(Date(1990, 7, 11).diffMonths(date) == -108); | |
6478 | assert(Date(1990, 7, 16).diffMonths(date) == -108); | |
6479 | assert(Date(1990, 7, 21).diffMonths(date) == -108); | |
6480 | assert(Date(1990, 7, 26).diffMonths(date) == -108); | |
6481 | assert(Date(1990, 7, 31).diffMonths(date) == -108); | |
6482 | assert(Date(1990, 8, 1).diffMonths(date) == -107); | |
6483 | ||
6484 | // Test B.C. | |
6485 | auto dateBC = Date(-1999, 7, 6); | |
6486 | ||
6487 | assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13); | |
6488 | assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12); | |
6489 | assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11); | |
6490 | assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10); | |
6491 | assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9); | |
6492 | assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8); | |
6493 | assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7); | |
6494 | assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6); | |
6495 | assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5); | |
6496 | assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4); | |
6497 | assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3); | |
6498 | assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2); | |
6499 | assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1); | |
6500 | assert(dateBC.diffMonths(dateBC) == 0); | |
6501 | assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1); | |
6502 | assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2); | |
6503 | assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3); | |
6504 | assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4); | |
6505 | assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5); | |
6506 | assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6); | |
6507 | assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7); | |
6508 | assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8); | |
6509 | assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9); | |
6510 | assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10); | |
6511 | assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11); | |
6512 | assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12); | |
6513 | assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13); | |
6514 | ||
6515 | assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13); | |
6516 | assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12); | |
6517 | assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11); | |
6518 | assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10); | |
6519 | assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9); | |
6520 | assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8); | |
6521 | assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7); | |
6522 | assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6); | |
6523 | assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5); | |
6524 | assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4); | |
6525 | assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3); | |
6526 | assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2); | |
6527 | assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1); | |
6528 | assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1); | |
6529 | assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2); | |
6530 | assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3); | |
6531 | assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4); | |
6532 | assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5); | |
6533 | assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6); | |
6534 | assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7); | |
6535 | assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8); | |
6536 | assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9); | |
6537 | assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10); | |
6538 | assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11); | |
6539 | assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12); | |
6540 | assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13); | |
6541 | ||
6542 | assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1); | |
6543 | assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0); | |
6544 | assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0); | |
6545 | assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0); | |
6546 | assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0); | |
6547 | assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0); | |
6548 | assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0); | |
6549 | assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0); | |
6550 | assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1); | |
6551 | ||
6552 | assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109); | |
6553 | assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108); | |
6554 | assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108); | |
6555 | assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108); | |
6556 | assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108); | |
6557 | assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108); | |
6558 | assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108); | |
6559 | assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108); | |
6560 | assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107); | |
6561 | ||
6562 | assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1); | |
6563 | assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0); | |
6564 | assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0); | |
6565 | assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0); | |
6566 | assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0); | |
6567 | assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0); | |
6568 | assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0); | |
6569 | assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0); | |
6570 | assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1); | |
6571 | ||
6572 | assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109); | |
6573 | assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108); | |
6574 | assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108); | |
6575 | assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108); | |
6576 | assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108); | |
6577 | assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108); | |
6578 | assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108); | |
6579 | assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108); | |
6580 | assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107); | |
6581 | ||
6582 | // Test Both | |
6583 | assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94); | |
6584 | assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94); | |
6585 | ||
6586 | const cdate = Date(1999, 7, 6); | |
6587 | immutable idate = Date(1999, 7, 6); | |
6588 | assert(date.diffMonths(date) == 0); | |
6589 | assert(cdate.diffMonths(date) == 0); | |
6590 | assert(idate.diffMonths(date) == 0); | |
6591 | ||
6592 | assert(date.diffMonths(cdate) == 0); | |
6593 | assert(cdate.diffMonths(cdate) == 0); | |
6594 | assert(idate.diffMonths(cdate) == 0); | |
6595 | ||
6596 | assert(date.diffMonths(idate) == 0); | |
6597 | assert(cdate.diffMonths(idate) == 0); | |
6598 | assert(idate.diffMonths(idate) == 0); | |
6599 | } | |
6600 | ||
6601 | ||
6602 | /++ | |
6603 | Whether this $(LREF Date) is in a leap year. | |
6604 | +/ | |
6605 | @property bool isLeapYear() const @safe pure nothrow @nogc | |
6606 | { | |
6607 | return yearIsLeapYear(_year); | |
6608 | } | |
6609 | ||
6610 | @safe unittest | |
6611 | { | |
6612 | auto date = Date(1999, 7, 6); | |
6613 | const cdate = Date(1999, 7, 6); | |
6614 | immutable idate = Date(1999, 7, 6); | |
6615 | static assert(!__traits(compiles, date.isLeapYear = true)); | |
6616 | static assert(!__traits(compiles, cdate.isLeapYear = true)); | |
6617 | static assert(!__traits(compiles, idate.isLeapYear = true)); | |
6618 | } | |
6619 | ||
6620 | ||
6621 | /++ | |
6622 | Day of the week this $(LREF Date) is on. | |
6623 | +/ | |
6624 | @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc | |
6625 | { | |
6626 | return getDayOfWeek(dayOfGregorianCal); | |
6627 | } | |
6628 | ||
6629 | @safe unittest | |
6630 | { | |
6631 | const cdate = Date(1999, 7, 6); | |
6632 | immutable idate = Date(1999, 7, 6); | |
6633 | assert(cdate.dayOfWeek == DayOfWeek.tue); | |
6634 | static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun)); | |
6635 | assert(idate.dayOfWeek == DayOfWeek.tue); | |
6636 | static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun)); | |
6637 | } | |
6638 | ||
6639 | ||
6640 | /++ | |
6641 | Day of the year this $(LREF Date) is on. | |
6642 | +/ | |
6643 | @property ushort dayOfYear() const @safe pure nothrow @nogc | |
6644 | { | |
6645 | if (_month >= Month.jan && _month <= Month.dec) | |
6646 | { | |
6647 | immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; | |
6648 | auto monthIndex = _month - Month.jan; | |
6649 | ||
6650 | return cast(ushort)(lastDay[monthIndex] + _day); | |
6651 | } | |
6652 | assert(0, "Invalid month."); | |
6653 | } | |
6654 | ||
6655 | /// | |
6656 | @safe unittest | |
6657 | { | |
6658 | assert(Date(1999, 1, 1).dayOfYear == 1); | |
6659 | assert(Date(1999, 12, 31).dayOfYear == 365); | |
6660 | assert(Date(2000, 12, 31).dayOfYear == 366); | |
6661 | } | |
6662 | ||
6663 | @safe unittest | |
6664 | { | |
6665 | import std.algorithm.iteration : filter; | |
6666 | import std.range : chain; | |
6667 | ||
6668 | foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) | |
6669 | { | |
6670 | foreach (doy; testDaysOfYear) | |
6671 | assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); | |
6672 | } | |
6673 | ||
6674 | foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) | |
6675 | { | |
6676 | foreach (doy; testDaysOfLeapYear) | |
6677 | assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); | |
6678 | } | |
6679 | ||
6680 | const cdate = Date(1999, 7, 6); | |
6681 | immutable idate = Date(1999, 7, 6); | |
6682 | assert(cdate.dayOfYear == 187); | |
6683 | assert(idate.dayOfYear == 187); | |
6684 | } | |
6685 | ||
6686 | /++ | |
6687 | Day of the year. | |
6688 | ||
6689 | Params: | |
6690 | day = The day of the year to set which day of the year this | |
6691 | $(LREF Date) is on. | |
6692 | ||
6693 | Throws: | |
6694 | $(REF DateTimeException,std,datetime,date) if the given day is an | |
6695 | invalid day of the year. | |
6696 | +/ | |
6697 | @property void dayOfYear(int day) @safe pure | |
6698 | { | |
6699 | setDayOfYear!true(day); | |
6700 | } | |
6701 | ||
6702 | private void setDayOfYear(bool useExceptions = false)(int day) | |
6703 | { | |
6704 | immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; | |
6705 | ||
6706 | bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear); | |
6707 | enum errorMsg = "Invalid day of the year."; | |
6708 | ||
6709 | static if (useExceptions) | |
6710 | { | |
6711 | if (dayOutOfRange) throw new DateTimeException(errorMsg); | |
6712 | } | |
6713 | else | |
6714 | { | |
6715 | assert(!dayOutOfRange, errorMsg); | |
6716 | } | |
6717 | ||
6718 | foreach (i; 1 .. lastDay.length) | |
6719 | { | |
6720 | if (day <= lastDay[i]) | |
6721 | { | |
6722 | _month = cast(Month)(cast(int) Month.jan + i - 1); | |
6723 | _day = cast(ubyte)(day - lastDay[i - 1]); | |
6724 | return; | |
6725 | } | |
6726 | } | |
6727 | assert(0, "Invalid day of the year."); | |
6728 | } | |
6729 | ||
6730 | @safe unittest | |
6731 | { | |
6732 | static void test(Date date, int day, MonthDay expected, size_t line = __LINE__) | |
6733 | { | |
6734 | date.dayOfYear = day; | |
6735 | assert(date.month == expected.month); | |
6736 | assert(date.day == expected.day); | |
6737 | } | |
6738 | ||
6739 | foreach (doy; testDaysOfYear) | |
6740 | { | |
6741 | test(Date(1999, 1, 1), doy.day, doy.md); | |
6742 | test(Date(-1, 1, 1), doy.day, doy.md); | |
6743 | } | |
6744 | ||
6745 | foreach (doy; testDaysOfLeapYear) | |
6746 | { | |
6747 | test(Date(2000, 1, 1), doy.day, doy.md); | |
6748 | test(Date(-4, 1, 1), doy.day, doy.md); | |
6749 | } | |
6750 | ||
6751 | const cdate = Date(1999, 7, 6); | |
6752 | immutable idate = Date(1999, 7, 6); | |
6753 | static assert(!__traits(compiles, cdate.dayOfYear = 187)); | |
6754 | static assert(!__traits(compiles, idate.dayOfYear = 187)); | |
6755 | } | |
6756 | ||
6757 | ||
6758 | /++ | |
6759 | The Xth day of the Gregorian Calendar that this $(LREF Date) is on. | |
6760 | +/ | |
6761 | @property int dayOfGregorianCal() const @safe pure nothrow @nogc | |
6762 | { | |
6763 | if (isAD) | |
6764 | { | |
6765 | if (_year == 1) | |
6766 | return dayOfYear; | |
6767 | ||
6768 | int years = _year - 1; | |
6769 | auto days = (years / 400) * daysIn400Years; | |
6770 | years %= 400; | |
6771 | ||
6772 | days += (years / 100) * daysIn100Years; | |
6773 | years %= 100; | |
6774 | ||
6775 | days += (years / 4) * daysIn4Years; | |
6776 | years %= 4; | |
6777 | ||
6778 | days += years * daysInYear; | |
6779 | ||
6780 | days += dayOfYear; | |
6781 | ||
6782 | return days; | |
6783 | } | |
6784 | else if (_year == 0) | |
6785 | return dayOfYear - daysInLeapYear; | |
6786 | else | |
6787 | { | |
6788 | int years = _year; | |
6789 | auto days = (years / 400) * daysIn400Years; | |
6790 | years %= 400; | |
6791 | ||
6792 | days += (years / 100) * daysIn100Years; | |
6793 | years %= 100; | |
6794 | ||
6795 | days += (years / 4) * daysIn4Years; | |
6796 | years %= 4; | |
6797 | ||
6798 | if (years < 0) | |
6799 | { | |
6800 | days -= daysInLeapYear; | |
6801 | ++years; | |
6802 | ||
6803 | days += years * daysInYear; | |
6804 | ||
6805 | days -= daysInYear - dayOfYear; | |
6806 | } | |
6807 | else | |
6808 | days -= daysInLeapYear - dayOfYear; | |
6809 | ||
6810 | return days; | |
6811 | } | |
6812 | } | |
6813 | ||
6814 | /// | |
6815 | @safe unittest | |
6816 | { | |
6817 | assert(Date(1, 1, 1).dayOfGregorianCal == 1); | |
6818 | assert(Date(1, 12, 31).dayOfGregorianCal == 365); | |
6819 | assert(Date(2, 1, 1).dayOfGregorianCal == 366); | |
6820 | ||
6821 | assert(Date(0, 12, 31).dayOfGregorianCal == 0); | |
6822 | assert(Date(0, 1, 1).dayOfGregorianCal == -365); | |
6823 | assert(Date(-1, 12, 31).dayOfGregorianCal == -366); | |
6824 | ||
6825 | assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); | |
6826 | assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); | |
6827 | } | |
6828 | ||
6829 | @safe unittest | |
6830 | { | |
6831 | import std.range : chain; | |
6832 | ||
6833 | foreach (gd; chain(testGregDaysBC, testGregDaysAD)) | |
6834 | assert(gd.date.dayOfGregorianCal == gd.day); | |
6835 | ||
6836 | auto date = Date(1999, 7, 6); | |
6837 | const cdate = Date(1999, 7, 6); | |
6838 | immutable idate = Date(1999, 7, 6); | |
6839 | assert(date.dayOfGregorianCal == 729_941); | |
6840 | assert(cdate.dayOfGregorianCal == 729_941); | |
6841 | assert(idate.dayOfGregorianCal == 729_941); | |
6842 | } | |
6843 | ||
6844 | /++ | |
6845 | The Xth day of the Gregorian Calendar that this $(LREF Date) is on. | |
6846 | ||
6847 | Params: | |
6848 | day = The day of the Gregorian Calendar to set this $(LREF Date) to. | |
6849 | +/ | |
6850 | @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc | |
6851 | { | |
6852 | this = Date(day); | |
6853 | } | |
6854 | ||
6855 | /// | |
6856 | @safe unittest | |
6857 | { | |
6858 | auto date = Date.init; | |
6859 | date.dayOfGregorianCal = 1; | |
6860 | assert(date == Date(1, 1, 1)); | |
6861 | ||
6862 | date.dayOfGregorianCal = 365; | |
6863 | assert(date == Date(1, 12, 31)); | |
6864 | ||
6865 | date.dayOfGregorianCal = 366; | |
6866 | assert(date == Date(2, 1, 1)); | |
6867 | ||
6868 | date.dayOfGregorianCal = 0; | |
6869 | assert(date == Date(0, 12, 31)); | |
6870 | ||
6871 | date.dayOfGregorianCal = -365; | |
6872 | assert(date == Date(-0, 1, 1)); | |
6873 | ||
6874 | date.dayOfGregorianCal = -366; | |
6875 | assert(date == Date(-1, 12, 31)); | |
6876 | ||
6877 | date.dayOfGregorianCal = 730_120; | |
6878 | assert(date == Date(2000, 1, 1)); | |
6879 | ||
6880 | date.dayOfGregorianCal = 734_137; | |
6881 | assert(date == Date(2010, 12, 31)); | |
6882 | } | |
6883 | ||
6884 | @safe unittest | |
6885 | { | |
6886 | auto date = Date(1999, 7, 6); | |
6887 | const cdate = Date(1999, 7, 6); | |
6888 | immutable idate = Date(1999, 7, 6); | |
6889 | date.dayOfGregorianCal = 187; | |
6890 | assert(date.dayOfGregorianCal == 187); | |
6891 | static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187)); | |
6892 | static assert(!__traits(compiles, idate.dayOfGregorianCal = 187)); | |
6893 | } | |
6894 | ||
6895 | ||
6896 | /++ | |
5fee5ec3 IB |
6897 | The ISO 8601 week and year of the year that this $(LREF Date) is in. |
6898 | ||
6899 | Returns: | |
6900 | An anonymous struct with the members $(D isoWeekYear) for the | |
6901 | resulting year and $(D isoWeek) for the resulting ISO week. | |
b4c522fa IB |
6902 | |
6903 | See_Also: | |
6904 | $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) | |
6905 | +/ | |
5fee5ec3 | 6906 | @property auto isoWeekAndYear() const @safe pure nothrow |
b4c522fa | 6907 | { |
5fee5ec3 IB |
6908 | struct ISOWeekAndYear { short isoWeekYear; ubyte isoWeek; } |
6909 | ||
b4c522fa IB |
6910 | immutable weekday = dayOfWeek; |
6911 | immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; | |
6912 | immutable week = (dayOfYear - adjustedWeekday + 10) / 7; | |
6913 | ||
6914 | try | |
6915 | { | |
6916 | if (week == 53) | |
6917 | { | |
6918 | switch (Date(_year + 1, 1, 1).dayOfWeek) | |
6919 | { | |
6920 | case DayOfWeek.mon: | |
6921 | case DayOfWeek.tue: | |
6922 | case DayOfWeek.wed: | |
6923 | case DayOfWeek.thu: | |
5fee5ec3 | 6924 | return ISOWeekAndYear(cast(short) (_year + 1), 1); |
b4c522fa IB |
6925 | case DayOfWeek.fri: |
6926 | case DayOfWeek.sat: | |
6927 | case DayOfWeek.sun: | |
5fee5ec3 | 6928 | return ISOWeekAndYear(_year, 53); |
b4c522fa IB |
6929 | default: |
6930 | assert(0, "Invalid ISO Week"); | |
6931 | } | |
6932 | } | |
6933 | else if (week > 0) | |
5fee5ec3 | 6934 | return ISOWeekAndYear(_year, cast(ubyte) week); |
b4c522fa | 6935 | else |
5fee5ec3 | 6936 | return Date(_year - 1, 12, 31).isoWeekAndYear; |
b4c522fa IB |
6937 | } |
6938 | catch (Exception e) | |
6939 | assert(0, "Date's constructor threw."); | |
6940 | } | |
6941 | ||
5fee5ec3 IB |
6942 | /++ |
6943 | The ISO 8601 week of the year that this $(LREF Date) is in. | |
6944 | ||
6945 | See_Also: | |
6946 | $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) | |
6947 | +/ | |
6948 | @property ubyte isoWeek() const @safe pure nothrow | |
6949 | { | |
6950 | return isoWeekAndYear().isoWeek; | |
6951 | } | |
6952 | ||
b4c522fa IB |
6953 | @safe unittest |
6954 | { | |
6955 | // Test A.D. | |
6956 | assert(Date(2009, 12, 28).isoWeek == 53); | |
6957 | assert(Date(2009, 12, 29).isoWeek == 53); | |
6958 | assert(Date(2009, 12, 30).isoWeek == 53); | |
6959 | assert(Date(2009, 12, 31).isoWeek == 53); | |
6960 | assert(Date(2010, 1, 1).isoWeek == 53); | |
6961 | assert(Date(2010, 1, 2).isoWeek == 53); | |
6962 | assert(Date(2010, 1, 3).isoWeek == 53); | |
6963 | assert(Date(2010, 1, 4).isoWeek == 1); | |
6964 | assert(Date(2010, 1, 5).isoWeek == 1); | |
6965 | assert(Date(2010, 1, 6).isoWeek == 1); | |
6966 | assert(Date(2010, 1, 7).isoWeek == 1); | |
6967 | assert(Date(2010, 1, 8).isoWeek == 1); | |
6968 | assert(Date(2010, 1, 9).isoWeek == 1); | |
6969 | assert(Date(2010, 1, 10).isoWeek == 1); | |
6970 | assert(Date(2010, 1, 11).isoWeek == 2); | |
6971 | assert(Date(2010, 12, 31).isoWeek == 52); | |
6972 | ||
6973 | assert(Date(2004, 12, 26).isoWeek == 52); | |
6974 | assert(Date(2004, 12, 27).isoWeek == 53); | |
6975 | assert(Date(2004, 12, 28).isoWeek == 53); | |
6976 | assert(Date(2004, 12, 29).isoWeek == 53); | |
6977 | assert(Date(2004, 12, 30).isoWeek == 53); | |
6978 | assert(Date(2004, 12, 31).isoWeek == 53); | |
6979 | assert(Date(2005, 1, 1).isoWeek == 53); | |
6980 | assert(Date(2005, 1, 2).isoWeek == 53); | |
6981 | ||
6982 | assert(Date(2005, 12, 31).isoWeek == 52); | |
6983 | assert(Date(2007, 1, 1).isoWeek == 1); | |
6984 | ||
6985 | assert(Date(2007, 12, 30).isoWeek == 52); | |
6986 | assert(Date(2007, 12, 31).isoWeek == 1); | |
6987 | assert(Date(2008, 1, 1).isoWeek == 1); | |
6988 | ||
6989 | assert(Date(2008, 12, 28).isoWeek == 52); | |
6990 | assert(Date(2008, 12, 29).isoWeek == 1); | |
6991 | assert(Date(2008, 12, 30).isoWeek == 1); | |
6992 | assert(Date(2008, 12, 31).isoWeek == 1); | |
6993 | assert(Date(2009, 1, 1).isoWeek == 1); | |
6994 | assert(Date(2009, 1, 2).isoWeek == 1); | |
6995 | assert(Date(2009, 1, 3).isoWeek == 1); | |
6996 | assert(Date(2009, 1, 4).isoWeek == 1); | |
6997 | ||
6998 | // Test B.C. | |
6999 | // The algorithm should work identically for both A.D. and B.C. since | |
7000 | // it doesn't really take the year into account, so B.C. testing | |
7001 | // probably isn't really needed. | |
7002 | assert(Date(0, 12, 31).isoWeek == 52); | |
7003 | assert(Date(0, 1, 4).isoWeek == 1); | |
7004 | assert(Date(0, 1, 1).isoWeek == 52); | |
7005 | ||
7006 | const cdate = Date(1999, 7, 6); | |
7007 | immutable idate = Date(1999, 7, 6); | |
7008 | assert(cdate.isoWeek == 27); | |
7009 | static assert(!__traits(compiles, cdate.isoWeek = 3)); | |
7010 | assert(idate.isoWeek == 27); | |
7011 | static assert(!__traits(compiles, idate.isoWeek = 3)); | |
7012 | } | |
7013 | ||
5fee5ec3 IB |
7014 | /++ |
7015 | The year inside the ISO 8601 week calendar that this $(LREF Date) is in. | |
7016 | ||
7017 | May differ from $(LREF year) between 28 December and 4 January. | |
7018 | ||
7019 | See_Also: | |
7020 | $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) | |
7021 | +/ | |
7022 | @property short isoWeekYear() const @safe pure nothrow | |
7023 | { | |
7024 | return isoWeekAndYear().isoWeekYear; | |
7025 | } | |
7026 | ||
7027 | @safe unittest | |
7028 | { | |
7029 | // Test A.D. | |
7030 | assert(Date(2009, 12, 28).isoWeekYear == 2009); | |
7031 | assert(Date(2009, 12, 29).isoWeekYear == 2009); | |
7032 | assert(Date(2009, 12, 30).isoWeekYear == 2009); | |
7033 | assert(Date(2009, 12, 31).isoWeekYear == 2009); | |
7034 | assert(Date(2010, 1, 1).isoWeekYear == 2009); | |
7035 | assert(Date(2010, 1, 2).isoWeekYear == 2009); | |
7036 | assert(Date(2010, 1, 3).isoWeekYear == 2009); | |
7037 | assert(Date(2010, 1, 4).isoWeekYear == 2010); | |
7038 | assert(Date(2010, 1, 5).isoWeekYear == 2010); | |
7039 | assert(Date(2010, 1, 6).isoWeekYear == 2010); | |
7040 | assert(Date(2010, 1, 7).isoWeekYear == 2010); | |
7041 | assert(Date(2010, 1, 8).isoWeekYear == 2010); | |
7042 | assert(Date(2010, 1, 9).isoWeekYear == 2010); | |
7043 | assert(Date(2010, 1, 10).isoWeekYear == 2010); | |
7044 | assert(Date(2010, 1, 11).isoWeekYear == 2010); | |
7045 | assert(Date(2010, 12, 31).isoWeekYear == 2010); | |
7046 | ||
7047 | assert(Date(2004, 12, 26).isoWeekYear == 2004); | |
7048 | assert(Date(2004, 12, 27).isoWeekYear == 2004); | |
7049 | assert(Date(2004, 12, 28).isoWeekYear == 2004); | |
7050 | assert(Date(2004, 12, 29).isoWeekYear == 2004); | |
7051 | assert(Date(2004, 12, 30).isoWeekYear == 2004); | |
7052 | assert(Date(2004, 12, 31).isoWeekYear == 2004); | |
7053 | assert(Date(2005, 1, 1).isoWeekYear == 2004); | |
7054 | assert(Date(2005, 1, 2).isoWeekYear == 2004); | |
7055 | assert(Date(2005, 1, 3).isoWeekYear == 2005); | |
7056 | ||
7057 | assert(Date(2005, 12, 31).isoWeekYear == 2005); | |
7058 | assert(Date(2007, 1, 1).isoWeekYear == 2007); | |
7059 | ||
7060 | assert(Date(2007, 12, 30).isoWeekYear == 2007); | |
7061 | assert(Date(2007, 12, 31).isoWeekYear == 2008); | |
7062 | assert(Date(2008, 1, 1).isoWeekYear == 2008); | |
7063 | ||
7064 | assert(Date(2008, 12, 28).isoWeekYear == 2008); | |
7065 | assert(Date(2008, 12, 29).isoWeekYear == 2009); | |
7066 | assert(Date(2008, 12, 30).isoWeekYear == 2009); | |
7067 | assert(Date(2008, 12, 31).isoWeekYear == 2009); | |
7068 | assert(Date(2009, 1, 1).isoWeekYear == 2009); | |
7069 | assert(Date(2009, 1, 2).isoWeekYear == 2009); | |
7070 | assert(Date(2009, 1, 3).isoWeekYear == 2009); | |
7071 | assert(Date(2009, 1, 4).isoWeekYear == 2009); | |
7072 | ||
7073 | // Test B.C. | |
7074 | assert(Date(0, 12, 31).isoWeekYear == 0); | |
7075 | assert(Date(0, 1, 4).isoWeekYear == 0); | |
7076 | assert(Date(0, 1, 1).isoWeekYear == -1); | |
7077 | ||
7078 | const cdate = Date(1999, 7, 6); | |
7079 | immutable idate = Date(1999, 7, 6); | |
7080 | assert(cdate.isoWeekYear == 1999); | |
7081 | assert(idate.isoWeekYear == 1999); | |
7082 | } | |
7083 | ||
7084 | static Date fromISOWeek(short isoWeekYear, ubyte isoWeek, DayOfWeek weekday) @safe pure nothrow @nogc | |
7085 | { | |
7086 | immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; | |
7087 | immutable dayOffset = (isoWeek - 1) * 7 + adjustedWeekday; | |
7088 | ||
7089 | Date date; | |
7090 | date._year = isoWeekYear; | |
7091 | date._month = Month.jan; | |
7092 | date._day = 3; | |
7093 | immutable startOfYear = date.dayOfWeek; | |
7094 | return date._addDays(dayOffset - startOfYear); | |
7095 | } | |
7096 | ||
7097 | @safe unittest | |
7098 | { | |
7099 | // Test -30000 days to 30000 days for matching construction <-> deconstruction | |
7100 | Date date = Date(1, 1, 1); | |
7101 | date._addDays(-30_000); | |
7102 | foreach (day; 0 .. 60_000) | |
7103 | { | |
7104 | const year = date.isoWeekYear; | |
7105 | const dow = date.dayOfWeek; | |
7106 | const isoWeek = date.isoWeek; | |
7107 | const reversed = Date.fromISOWeek(year, isoWeek, dow); | |
7108 | assert(reversed == date, date.toISOExtString ~ " != " ~ reversed.toISOExtString); | |
7109 | date = date._addDays(1); | |
7110 | } | |
7111 | } | |
7112 | ||
b4c522fa IB |
7113 | |
7114 | /++ | |
7115 | $(LREF Date) for the last day in the month that this $(LREF Date) is in. | |
7116 | +/ | |
7117 | @property Date endOfMonth() const @safe pure nothrow | |
7118 | { | |
7119 | try | |
7120 | return Date(_year, _month, maxDay(_year, _month)); | |
7121 | catch (Exception e) | |
7122 | assert(0, "Date's constructor threw."); | |
7123 | } | |
7124 | ||
7125 | /// | |
7126 | @safe unittest | |
7127 | { | |
7128 | assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); | |
7129 | assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); | |
7130 | assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); | |
7131 | assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); | |
7132 | } | |
7133 | ||
7134 | @safe unittest | |
7135 | { | |
7136 | // Test A.D. | |
7137 | assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31)); | |
7138 | assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28)); | |
7139 | assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29)); | |
7140 | assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31)); | |
7141 | assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30)); | |
7142 | assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31)); | |
7143 | assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30)); | |
7144 | assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31)); | |
7145 | assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31)); | |
7146 | assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30)); | |
7147 | assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31)); | |
7148 | assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30)); | |
7149 | assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31)); | |
7150 | ||
7151 | // Test B.C. | |
7152 | assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31)); | |
7153 | assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28)); | |
7154 | assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29)); | |
7155 | assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31)); | |
7156 | assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30)); | |
7157 | assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31)); | |
7158 | assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30)); | |
7159 | assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31)); | |
7160 | assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31)); | |
7161 | assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30)); | |
7162 | assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31)); | |
7163 | assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30)); | |
7164 | assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31)); | |
7165 | ||
7166 | const cdate = Date(1999, 7, 6); | |
7167 | immutable idate = Date(1999, 7, 6); | |
7168 | static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30))); | |
7169 | static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30))); | |
7170 | } | |
7171 | ||
7172 | ||
7173 | /++ | |
7174 | The last day in the month that this $(LREF Date) is in. | |
7175 | +/ | |
7176 | @property ubyte daysInMonth() const @safe pure nothrow @nogc | |
7177 | { | |
7178 | return maxDay(_year, _month); | |
7179 | } | |
7180 | ||
7181 | /// | |
7182 | @safe unittest | |
7183 | { | |
7184 | assert(Date(1999, 1, 6).daysInMonth == 31); | |
7185 | assert(Date(1999, 2, 7).daysInMonth == 28); | |
7186 | assert(Date(2000, 2, 7).daysInMonth == 29); | |
7187 | assert(Date(2000, 6, 4).daysInMonth == 30); | |
7188 | } | |
7189 | ||
7190 | @safe unittest | |
7191 | { | |
7192 | // Test A.D. | |
7193 | assert(Date(1999, 1, 1).daysInMonth == 31); | |
7194 | assert(Date(1999, 2, 1).daysInMonth == 28); | |
7195 | assert(Date(2000, 2, 1).daysInMonth == 29); | |
7196 | assert(Date(1999, 3, 1).daysInMonth == 31); | |
7197 | assert(Date(1999, 4, 1).daysInMonth == 30); | |
7198 | assert(Date(1999, 5, 1).daysInMonth == 31); | |
7199 | assert(Date(1999, 6, 1).daysInMonth == 30); | |
7200 | assert(Date(1999, 7, 1).daysInMonth == 31); | |
7201 | assert(Date(1999, 8, 1).daysInMonth == 31); | |
7202 | assert(Date(1999, 9, 1).daysInMonth == 30); | |
7203 | assert(Date(1999, 10, 1).daysInMonth == 31); | |
7204 | assert(Date(1999, 11, 1).daysInMonth == 30); | |
7205 | assert(Date(1999, 12, 1).daysInMonth == 31); | |
7206 | ||
7207 | // Test B.C. | |
7208 | assert(Date(-1999, 1, 1).daysInMonth == 31); | |
7209 | assert(Date(-1999, 2, 1).daysInMonth == 28); | |
7210 | assert(Date(-2000, 2, 1).daysInMonth == 29); | |
7211 | assert(Date(-1999, 3, 1).daysInMonth == 31); | |
7212 | assert(Date(-1999, 4, 1).daysInMonth == 30); | |
7213 | assert(Date(-1999, 5, 1).daysInMonth == 31); | |
7214 | assert(Date(-1999, 6, 1).daysInMonth == 30); | |
7215 | assert(Date(-1999, 7, 1).daysInMonth == 31); | |
7216 | assert(Date(-1999, 8, 1).daysInMonth == 31); | |
7217 | assert(Date(-1999, 9, 1).daysInMonth == 30); | |
7218 | assert(Date(-1999, 10, 1).daysInMonth == 31); | |
7219 | assert(Date(-1999, 11, 1).daysInMonth == 30); | |
7220 | assert(Date(-1999, 12, 1).daysInMonth == 31); | |
7221 | ||
7222 | const cdate = Date(1999, 7, 6); | |
7223 | immutable idate = Date(1999, 7, 6); | |
7224 | static assert(!__traits(compiles, cdate.daysInMonth = 30)); | |
7225 | static assert(!__traits(compiles, idate.daysInMonth = 30)); | |
7226 | } | |
7227 | ||
7228 | ||
7229 | /++ | |
7230 | Whether the current year is a date in A.D. | |
7231 | +/ | |
7232 | @property bool isAD() const @safe pure nothrow @nogc | |
7233 | { | |
7234 | return _year > 0; | |
7235 | } | |
7236 | ||
7237 | /// | |
7238 | @safe unittest | |
7239 | { | |
7240 | assert(Date(1, 1, 1).isAD); | |
7241 | assert(Date(2010, 12, 31).isAD); | |
7242 | assert(!Date(0, 12, 31).isAD); | |
7243 | assert(!Date(-2010, 1, 1).isAD); | |
7244 | } | |
7245 | ||
7246 | @safe unittest | |
7247 | { | |
7248 | assert(Date(2010, 7, 4).isAD); | |
7249 | assert(Date(1, 1, 1).isAD); | |
7250 | assert(!Date(0, 1, 1).isAD); | |
7251 | assert(!Date(-1, 1, 1).isAD); | |
7252 | assert(!Date(-2010, 7, 4).isAD); | |
7253 | ||
7254 | const cdate = Date(1999, 7, 6); | |
7255 | immutable idate = Date(1999, 7, 6); | |
7256 | assert(cdate.isAD); | |
7257 | assert(idate.isAD); | |
7258 | } | |
7259 | ||
7260 | ||
7261 | /++ | |
7262 | The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this | |
7263 | $(LREF Date) at noon (since the Julian day changes at noon). | |
7264 | +/ | |
7265 | @property long julianDay() const @safe pure nothrow @nogc | |
7266 | { | |
7267 | return dayOfGregorianCal + 1_721_425; | |
7268 | } | |
7269 | ||
7270 | @safe unittest | |
7271 | { | |
7272 | assert(Date(-4713, 11, 24).julianDay == 0); | |
7273 | assert(Date(0, 12, 31).julianDay == 1_721_425); | |
7274 | assert(Date(1, 1, 1).julianDay == 1_721_426); | |
7275 | assert(Date(1582, 10, 15).julianDay == 2_299_161); | |
7276 | assert(Date(1858, 11, 17).julianDay == 2_400_001); | |
7277 | assert(Date(1982, 1, 4).julianDay == 2_444_974); | |
7278 | assert(Date(1996, 3, 31).julianDay == 2_450_174); | |
7279 | assert(Date(2010, 8, 24).julianDay == 2_455_433); | |
7280 | ||
7281 | const cdate = Date(1999, 7, 6); | |
7282 | immutable idate = Date(1999, 7, 6); | |
7283 | assert(cdate.julianDay == 2_451_366); | |
7284 | assert(idate.julianDay == 2_451_366); | |
7285 | } | |
7286 | ||
7287 | ||
7288 | /++ | |
7289 | The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for | |
7290 | any time on this date (since, the modified Julian day changes at | |
7291 | midnight). | |
7292 | +/ | |
7293 | @property long modJulianDay() const @safe pure nothrow @nogc | |
7294 | { | |
7295 | return julianDay - 2_400_001; | |
7296 | } | |
7297 | ||
7298 | @safe unittest | |
7299 | { | |
7300 | assert(Date(1858, 11, 17).modJulianDay == 0); | |
7301 | assert(Date(2010, 8, 24).modJulianDay == 55_432); | |
7302 | ||
7303 | const cdate = Date(1999, 7, 6); | |
7304 | immutable idate = Date(1999, 7, 6); | |
7305 | assert(cdate.modJulianDay == 51_365); | |
7306 | assert(idate.modJulianDay == 51_365); | |
7307 | } | |
7308 | ||
7309 | ||
7310 | /++ | |
5fee5ec3 IB |
7311 | Converts this $(LREF Date) to a string with the format `YYYYMMDD`. |
7312 | If `writer` is set, the resulting string will be written directly | |
7313 | to it. | |
7314 | ||
7315 | Params: | |
7316 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
7317 | Returns: | |
7318 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
7319 | +/ |
7320 | string toISOString() const @safe pure nothrow | |
7321 | { | |
5fee5ec3 IB |
7322 | import std.array : appender; |
7323 | auto w = appender!string(); | |
7324 | w.reserve(8); | |
b4c522fa | 7325 | try |
5fee5ec3 | 7326 | toISOString(w); |
b4c522fa | 7327 | catch (Exception e) |
5fee5ec3 IB |
7328 | assert(0, "toISOString() threw."); |
7329 | return w.data; | |
b4c522fa IB |
7330 | } |
7331 | ||
7332 | /// | |
7333 | @safe unittest | |
7334 | { | |
7335 | assert(Date(2010, 7, 4).toISOString() == "20100704"); | |
7336 | assert(Date(1998, 12, 25).toISOString() == "19981225"); | |
7337 | assert(Date(0, 1, 5).toISOString() == "00000105"); | |
7338 | assert(Date(-4, 1, 5).toISOString() == "-00040105"); | |
7339 | } | |
7340 | ||
7341 | @safe unittest | |
7342 | { | |
7343 | // Test A.D. | |
7344 | assert(Date(9, 12, 4).toISOString() == "00091204"); | |
7345 | assert(Date(99, 12, 4).toISOString() == "00991204"); | |
7346 | assert(Date(999, 12, 4).toISOString() == "09991204"); | |
7347 | assert(Date(9999, 7, 4).toISOString() == "99990704"); | |
7348 | assert(Date(10000, 10, 20).toISOString() == "+100001020"); | |
7349 | ||
7350 | // Test B.C. | |
7351 | assert(Date(0, 12, 4).toISOString() == "00001204"); | |
7352 | assert(Date(-9, 12, 4).toISOString() == "-00091204"); | |
7353 | assert(Date(-99, 12, 4).toISOString() == "-00991204"); | |
7354 | assert(Date(-999, 12, 4).toISOString() == "-09991204"); | |
7355 | assert(Date(-9999, 7, 4).toISOString() == "-99990704"); | |
7356 | assert(Date(-10000, 10, 20).toISOString() == "-100001020"); | |
7357 | ||
7358 | const cdate = Date(1999, 7, 6); | |
7359 | immutable idate = Date(1999, 7, 6); | |
7360 | assert(cdate.toISOString() == "19990706"); | |
7361 | assert(idate.toISOString() == "19990706"); | |
7362 | } | |
7363 | ||
5fee5ec3 IB |
7364 | /// ditto |
7365 | void toISOString(W)(ref W writer) const | |
7366 | if (isOutputRange!(W, char)) | |
7367 | { | |
7368 | import std.format.write : formattedWrite; | |
7369 | if (_year >= 0) | |
7370 | { | |
7371 | if (_year < 10_000) | |
7372 | formattedWrite(writer, "%04d%02d%02d", _year, _month, _day); | |
7373 | else | |
7374 | formattedWrite(writer, "+%05d%02d%02d", _year, _month, _day); | |
7375 | } | |
7376 | else if (_year > -10_000) | |
7377 | formattedWrite(writer, "%05d%02d%02d", _year, _month, _day); | |
7378 | else | |
7379 | formattedWrite(writer, "%06d%02d%02d", _year, _month, _day); | |
7380 | } | |
7381 | ||
7382 | @safe pure unittest | |
7383 | { | |
7384 | import std.array : appender; | |
7385 | ||
7386 | auto w = appender!(char[])(); | |
7387 | Date(2010, 7, 4).toISOString(w); | |
7388 | assert(w.data == "20100704"); | |
7389 | w.clear(); | |
7390 | Date(1998, 12, 25).toISOString(w); | |
7391 | assert(w.data == "19981225"); | |
7392 | } | |
7393 | ||
b4c522fa | 7394 | /++ |
5fee5ec3 IB |
7395 | Converts this $(LREF Date) to a string with the format `YYYY-MM-DD`. |
7396 | If `writer` is set, the resulting string will be written directly | |
7397 | to it. | |
7398 | ||
7399 | Params: | |
7400 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
7401 | Returns: | |
7402 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
7403 | +/ |
7404 | string toISOExtString() const @safe pure nothrow | |
7405 | { | |
5fee5ec3 IB |
7406 | import std.array : appender; |
7407 | auto w = appender!string(); | |
7408 | w.reserve(10); | |
b4c522fa | 7409 | try |
5fee5ec3 | 7410 | toISOExtString(w); |
b4c522fa | 7411 | catch (Exception e) |
5fee5ec3 IB |
7412 | assert(0, "toISOExtString() threw."); |
7413 | return w.data; | |
b4c522fa IB |
7414 | } |
7415 | ||
7416 | /// | |
7417 | @safe unittest | |
7418 | { | |
7419 | assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); | |
7420 | assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); | |
7421 | assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); | |
7422 | assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); | |
7423 | } | |
7424 | ||
7425 | @safe unittest | |
7426 | { | |
7427 | // Test A.D. | |
7428 | assert(Date(9, 12, 4).toISOExtString() == "0009-12-04"); | |
7429 | assert(Date(99, 12, 4).toISOExtString() == "0099-12-04"); | |
7430 | assert(Date(999, 12, 4).toISOExtString() == "0999-12-04"); | |
7431 | assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04"); | |
7432 | assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20"); | |
7433 | ||
7434 | // Test B.C. | |
7435 | assert(Date(0, 12, 4).toISOExtString() == "0000-12-04"); | |
7436 | assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04"); | |
7437 | assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04"); | |
7438 | assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04"); | |
7439 | assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04"); | |
7440 | assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20"); | |
7441 | ||
7442 | const cdate = Date(1999, 7, 6); | |
7443 | immutable idate = Date(1999, 7, 6); | |
7444 | assert(cdate.toISOExtString() == "1999-07-06"); | |
7445 | assert(idate.toISOExtString() == "1999-07-06"); | |
7446 | } | |
7447 | ||
5fee5ec3 IB |
7448 | /// ditto |
7449 | void toISOExtString(W)(ref W writer) const | |
7450 | if (isOutputRange!(W, char)) | |
7451 | { | |
7452 | import std.format.write : formattedWrite; | |
7453 | if (_year >= 0) | |
7454 | { | |
7455 | if (_year < 10_000) | |
7456 | formattedWrite(writer, "%04d-%02d-%02d", _year, _month, _day); | |
7457 | else | |
7458 | formattedWrite(writer, "+%05d-%02d-%02d", _year, _month, _day); | |
7459 | } | |
7460 | else if (_year > -10_000) | |
7461 | formattedWrite(writer, "%05d-%02d-%02d", _year, _month, _day); | |
7462 | else | |
7463 | formattedWrite(writer, "%06d-%02d-%02d", _year, _month, _day); | |
7464 | } | |
7465 | ||
7466 | @safe pure unittest | |
7467 | { | |
7468 | import std.array : appender; | |
7469 | ||
7470 | auto w = appender!(char[])(); | |
7471 | Date(2010, 7, 4).toISOExtString(w); | |
7472 | assert(w.data == "2010-07-04"); | |
7473 | w.clear(); | |
7474 | Date(-4, 1, 5).toISOExtString(w); | |
7475 | assert(w.data == "-0004-01-05"); | |
7476 | } | |
7477 | ||
b4c522fa | 7478 | /++ |
5fee5ec3 IB |
7479 | Converts this $(LREF Date) to a string with the format `YYYY-Mon-DD`. |
7480 | If `writer` is set, the resulting string will be written directly | |
7481 | to it. | |
7482 | ||
7483 | Params: | |
7484 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
7485 | Returns: | |
7486 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
7487 | +/ |
7488 | string toSimpleString() const @safe pure nothrow | |
7489 | { | |
5fee5ec3 IB |
7490 | import std.array : appender; |
7491 | auto w = appender!string(); | |
7492 | w.reserve(11); | |
b4c522fa | 7493 | try |
5fee5ec3 | 7494 | toSimpleString(w); |
b4c522fa | 7495 | catch (Exception e) |
5fee5ec3 IB |
7496 | assert(0, "toSimpleString() threw."); |
7497 | return w.data; | |
b4c522fa IB |
7498 | } |
7499 | ||
7500 | /// | |
7501 | @safe unittest | |
7502 | { | |
7503 | assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); | |
7504 | assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); | |
7505 | assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); | |
7506 | assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); | |
7507 | } | |
7508 | ||
7509 | @safe unittest | |
7510 | { | |
7511 | // Test A.D. | |
7512 | assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04"); | |
7513 | assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04"); | |
7514 | assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04"); | |
7515 | assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04"); | |
7516 | assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20"); | |
7517 | ||
7518 | // Test B.C. | |
7519 | assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04"); | |
7520 | assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04"); | |
7521 | assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04"); | |
7522 | assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04"); | |
7523 | assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04"); | |
7524 | assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20"); | |
7525 | ||
7526 | const cdate = Date(1999, 7, 6); | |
7527 | immutable idate = Date(1999, 7, 6); | |
7528 | assert(cdate.toSimpleString() == "1999-Jul-06"); | |
7529 | assert(idate.toSimpleString() == "1999-Jul-06"); | |
7530 | } | |
7531 | ||
5fee5ec3 IB |
7532 | /// ditto |
7533 | void toSimpleString(W)(ref W writer) const | |
7534 | if (isOutputRange!(W, char)) | |
7535 | { | |
7536 | import std.format.write : formattedWrite; | |
7537 | if (_year >= 0) | |
7538 | { | |
7539 | if (_year < 10_000) | |
7540 | formattedWrite(writer, "%04d-%s-%02d", _year, monthToString(_month), _day); | |
7541 | else | |
7542 | formattedWrite(writer, "+%05d-%s-%02d", _year, monthToString(_month), _day); | |
7543 | } | |
7544 | else if (_year > -10_000) | |
7545 | formattedWrite(writer, "%05d-%s-%02d", _year, monthToString(_month), _day); | |
7546 | else | |
7547 | formattedWrite(writer, "%06d-%s-%02d", _year, monthToString(_month), _day); | |
7548 | } | |
7549 | ||
7550 | @safe pure unittest | |
7551 | { | |
7552 | import std.array : appender; | |
7553 | ||
7554 | auto w = appender!(char[])(); | |
7555 | Date(9, 12, 4).toSimpleString(w); | |
7556 | assert(w.data == "0009-Dec-04"); | |
7557 | w.clear(); | |
7558 | Date(-10000, 10, 20).toSimpleString(w); | |
7559 | assert(w.data == "-10000-Oct-20"); | |
7560 | } | |
b4c522fa IB |
7561 | |
7562 | /++ | |
7563 | Converts this $(LREF Date) to a string. | |
7564 | ||
7565 | This function exists to make it easy to convert a $(LREF Date) to a | |
7566 | string for code that does not care what the exact format is - just that | |
7567 | it presents the information in a clear manner. It also makes it easy to | |
7568 | simply convert a $(LREF Date) to a string when using functions such as | |
7569 | `to!string`, `format`, or `writeln` which use toString to convert | |
7570 | user-defined types. So, it is unlikely that much code will call | |
7571 | toString directly. | |
7572 | ||
7573 | The format of the string is purposefully unspecified, and code that | |
7574 | cares about the format of the string should use `toISOString`, | |
7575 | `toISOExtString`, `toSimpleString`, or some other custom formatting | |
7576 | function that explicitly generates the format that the code needs. The | |
7577 | reason is that the code is then clear about what format it's using, | |
7578 | making it less error-prone to maintain the code and interact with other | |
7579 | software that consumes the generated strings. It's for this same reason | |
7580 | $(LREF Date) has no `fromString` function, whereas it does have | |
7581 | `fromISOString`, `fromISOExtString`, and `fromSimpleString`. | |
7582 | ||
7583 | The format returned by toString may or may not change in the future. | |
7584 | +/ | |
7585 | string toString() const @safe pure nothrow | |
7586 | { | |
7587 | return toSimpleString(); | |
7588 | } | |
7589 | ||
7590 | @safe unittest | |
7591 | { | |
7592 | auto date = Date(1999, 7, 6); | |
7593 | const cdate = Date(1999, 7, 6); | |
7594 | immutable idate = Date(1999, 7, 6); | |
7595 | assert(date.toString()); | |
7596 | assert(cdate.toString()); | |
7597 | assert(idate.toString()); | |
7598 | } | |
7599 | ||
5fee5ec3 IB |
7600 | /// ditto |
7601 | void toString(W)(ref W writer) const | |
7602 | if (isOutputRange!(W, char)) | |
7603 | { | |
7604 | toSimpleString(writer); | |
7605 | } | |
b4c522fa IB |
7606 | |
7607 | /++ | |
7608 | Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace | |
7609 | is stripped from the given string. | |
7610 | ||
7611 | Params: | |
7612 | isoString = A string formatted in the ISO format for dates. | |
7613 | ||
7614 | Throws: | |
7615 | $(REF DateTimeException,std,datetime,date) if the given string is | |
7616 | not in the ISO format or if the resulting $(LREF Date) would not be | |
7617 | valid. | |
7618 | +/ | |
5fee5ec3 | 7619 | static Date fromISOString(S)(scope const S isoString) @safe pure |
b4c522fa IB |
7620 | if (isSomeString!S) |
7621 | { | |
7622 | import std.algorithm.searching : startsWith; | |
7623 | import std.conv : to, text, ConvException; | |
7624 | import std.exception : enforce; | |
7625 | import std.string : strip; | |
7626 | ||
7627 | auto str = isoString.strip; | |
7628 | ||
7629 | enforce!DateTimeException(str.length >= 8, text("Invalid ISO String: ", isoString)); | |
7630 | ||
7631 | int day, month, year; | |
7632 | auto yearStr = str[0 .. $ - 4]; | |
7633 | ||
7634 | try | |
7635 | { | |
7636 | // using conversion to uint plus cast because it checks for +/- | |
7637 | // for us quickly while throwing ConvException | |
7638 | day = cast(int) to!uint(str[$ - 2 .. $]); | |
7639 | month = cast(int) to!uint(str[$ - 4 .. $ - 2]); | |
7640 | ||
7641 | if (yearStr.length > 4) | |
7642 | { | |
7643 | enforce!DateTimeException(yearStr.startsWith('-', '+'), | |
7644 | text("Invalid ISO String: ", isoString)); | |
7645 | year = to!int(yearStr); | |
7646 | } | |
7647 | else | |
7648 | { | |
7649 | year = cast(int) to!uint(yearStr); | |
7650 | } | |
7651 | } | |
7652 | catch (ConvException) | |
7653 | { | |
7654 | throw new DateTimeException(text("Invalid ISO String: ", isoString)); | |
7655 | } | |
7656 | ||
7657 | return Date(year, month, day); | |
7658 | } | |
7659 | ||
7660 | /// | |
7661 | @safe unittest | |
7662 | { | |
7663 | assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); | |
7664 | assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); | |
7665 | assert(Date.fromISOString("00000105") == Date(0, 1, 5)); | |
7666 | assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); | |
7667 | assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); | |
7668 | } | |
7669 | ||
7670 | @safe unittest | |
7671 | { | |
7672 | assertThrown!DateTimeException(Date.fromISOString("")); | |
7673 | assertThrown!DateTimeException(Date.fromISOString("990704")); | |
7674 | assertThrown!DateTimeException(Date.fromISOString("0100704")); | |
7675 | assertThrown!DateTimeException(Date.fromISOString("2010070")); | |
7676 | assertThrown!DateTimeException(Date.fromISOString("2010070 ")); | |
7677 | assertThrown!DateTimeException(Date.fromISOString("120100704")); | |
7678 | assertThrown!DateTimeException(Date.fromISOString("-0100704")); | |
7679 | assertThrown!DateTimeException(Date.fromISOString("+0100704")); | |
7680 | assertThrown!DateTimeException(Date.fromISOString("2010070a")); | |
7681 | assertThrown!DateTimeException(Date.fromISOString("20100a04")); | |
7682 | assertThrown!DateTimeException(Date.fromISOString("2010a704")); | |
7683 | ||
7684 | assertThrown!DateTimeException(Date.fromISOString("99-07-04")); | |
7685 | assertThrown!DateTimeException(Date.fromISOString("010-07-04")); | |
7686 | assertThrown!DateTimeException(Date.fromISOString("2010-07-0")); | |
7687 | assertThrown!DateTimeException(Date.fromISOString("2010-07-0 ")); | |
7688 | assertThrown!DateTimeException(Date.fromISOString("12010-07-04")); | |
7689 | assertThrown!DateTimeException(Date.fromISOString("-010-07-04")); | |
7690 | assertThrown!DateTimeException(Date.fromISOString("+010-07-04")); | |
7691 | assertThrown!DateTimeException(Date.fromISOString("2010-07-0a")); | |
7692 | assertThrown!DateTimeException(Date.fromISOString("2010-0a-04")); | |
7693 | assertThrown!DateTimeException(Date.fromISOString("2010-a7-04")); | |
7694 | assertThrown!DateTimeException(Date.fromISOString("2010/07/04")); | |
7695 | assertThrown!DateTimeException(Date.fromISOString("2010/7/04")); | |
7696 | assertThrown!DateTimeException(Date.fromISOString("2010/7/4")); | |
7697 | assertThrown!DateTimeException(Date.fromISOString("2010/07/4")); | |
7698 | assertThrown!DateTimeException(Date.fromISOString("2010-7-04")); | |
7699 | assertThrown!DateTimeException(Date.fromISOString("2010-7-4")); | |
7700 | assertThrown!DateTimeException(Date.fromISOString("2010-07-4")); | |
7701 | ||
7702 | assertThrown!DateTimeException(Date.fromISOString("99Jul04")); | |
7703 | assertThrown!DateTimeException(Date.fromISOString("010Jul04")); | |
7704 | assertThrown!DateTimeException(Date.fromISOString("2010Jul0")); | |
7705 | assertThrown!DateTimeException(Date.fromISOString("2010Jul0 ")); | |
7706 | assertThrown!DateTimeException(Date.fromISOString("12010Jul04")); | |
7707 | assertThrown!DateTimeException(Date.fromISOString("-010Jul04")); | |
7708 | assertThrown!DateTimeException(Date.fromISOString("+010Jul04")); | |
7709 | assertThrown!DateTimeException(Date.fromISOString("2010Jul0a")); | |
7710 | assertThrown!DateTimeException(Date.fromISOString("2010Jua04")); | |
7711 | assertThrown!DateTimeException(Date.fromISOString("2010aul04")); | |
7712 | ||
7713 | assertThrown!DateTimeException(Date.fromISOString("99-Jul-04")); | |
7714 | assertThrown!DateTimeException(Date.fromISOString("010-Jul-04")); | |
7715 | assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0")); | |
7716 | assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 ")); | |
7717 | assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04")); | |
7718 | assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04")); | |
7719 | assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04")); | |
7720 | assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a")); | |
7721 | assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04")); | |
7722 | assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04")); | |
7723 | assertThrown!DateTimeException(Date.fromISOString("2010-aul-04")); | |
7724 | ||
7725 | assertThrown!DateTimeException(Date.fromISOString("2010-07-04")); | |
7726 | assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04")); | |
7727 | ||
7728 | assert(Date.fromISOString("19990706") == Date(1999, 7, 6)); | |
7729 | assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6)); | |
7730 | assert(Date.fromISOString("+019990706") == Date(1999, 7, 6)); | |
7731 | assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6)); | |
7732 | assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6)); | |
7733 | assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6)); | |
7734 | } | |
7735 | ||
5fee5ec3 | 7736 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
7737 | @safe unittest |
7738 | { | |
7739 | import std.conv : to; | |
7740 | import std.meta : AliasSeq; | |
5fee5ec3 | 7741 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 7742 | { |
5fee5ec3 | 7743 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
7744 | assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21)); |
7745 | } | |
7746 | } | |
7747 | ||
7748 | ||
7749 | /++ | |
7750 | Creates a $(LREF Date) from a string with the format YYYY-MM-DD. | |
7751 | Whitespace is stripped from the given string. | |
7752 | ||
7753 | Params: | |
7754 | isoExtString = A string formatted in the ISO Extended format for | |
7755 | dates. | |
7756 | ||
7757 | Throws: | |
7758 | $(REF DateTimeException,std,datetime,date) if the given string is | |
7759 | not in the ISO Extended format or if the resulting $(LREF Date) | |
7760 | would not be valid. | |
7761 | +/ | |
5fee5ec3 | 7762 | static Date fromISOExtString(S)(scope const S isoExtString) @safe pure |
b4c522fa IB |
7763 | if (isSomeString!(S)) |
7764 | { | |
5fee5ec3 IB |
7765 | import std.algorithm.searching : startsWith; |
7766 | import std.conv : to, ConvException; | |
b4c522fa IB |
7767 | import std.format : format; |
7768 | import std.string : strip; | |
7769 | ||
5fee5ec3 IB |
7770 | auto str = strip(isoExtString); |
7771 | short year; | |
7772 | ubyte month, day; | |
b4c522fa | 7773 | |
5fee5ec3 IB |
7774 | if (str.length < 10 || str[$-3] != '-' || str[$-6] != '-') |
7775 | throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)); | |
b4c522fa | 7776 | |
5fee5ec3 IB |
7777 | auto yearStr = str[0 .. $-6]; |
7778 | auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); | |
7779 | if ((yearStr.length > 4) != signAtBegining) | |
7780 | { | |
7781 | throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)); | |
7782 | } | |
b4c522fa | 7783 | |
5fee5ec3 | 7784 | try |
b4c522fa | 7785 | { |
5fee5ec3 IB |
7786 | day = to!ubyte(str[$-2 .. $]); |
7787 | month = to!ubyte(str[$-5 .. $-3]); | |
7788 | year = to!short(yearStr); | |
7789 | } | |
7790 | catch (ConvException) | |
7791 | { | |
7792 | throw new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString)); | |
b4c522fa | 7793 | } |
b4c522fa | 7794 | |
5fee5ec3 | 7795 | return Date(year, month, day); |
b4c522fa IB |
7796 | } |
7797 | ||
7798 | /// | |
7799 | @safe unittest | |
7800 | { | |
7801 | assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); | |
7802 | assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); | |
7803 | assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); | |
7804 | assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); | |
7805 | assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); | |
7806 | } | |
7807 | ||
7808 | @safe unittest | |
7809 | { | |
7810 | assertThrown!DateTimeException(Date.fromISOExtString("")); | |
7811 | assertThrown!DateTimeException(Date.fromISOExtString("990704")); | |
7812 | assertThrown!DateTimeException(Date.fromISOExtString("0100704")); | |
7813 | assertThrown!DateTimeException(Date.fromISOExtString("2010070")); | |
7814 | assertThrown!DateTimeException(Date.fromISOExtString("2010070 ")); | |
7815 | assertThrown!DateTimeException(Date.fromISOExtString("120100704")); | |
7816 | assertThrown!DateTimeException(Date.fromISOExtString("-0100704")); | |
7817 | assertThrown!DateTimeException(Date.fromISOExtString("+0100704")); | |
7818 | assertThrown!DateTimeException(Date.fromISOExtString("2010070a")); | |
7819 | assertThrown!DateTimeException(Date.fromISOExtString("20100a04")); | |
7820 | assertThrown!DateTimeException(Date.fromISOExtString("2010a704")); | |
7821 | ||
7822 | assertThrown!DateTimeException(Date.fromISOExtString("99-07-04")); | |
7823 | assertThrown!DateTimeException(Date.fromISOExtString("010-07-04")); | |
7824 | assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0")); | |
7825 | assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 ")); | |
7826 | assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04")); | |
7827 | assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04")); | |
7828 | assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04")); | |
7829 | assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a")); | |
7830 | assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04")); | |
7831 | assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04")); | |
7832 | assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04")); | |
7833 | assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04")); | |
7834 | assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4")); | |
7835 | assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4")); | |
7836 | assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04")); | |
7837 | assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4")); | |
7838 | assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4")); | |
7839 | ||
7840 | assertThrown!DateTimeException(Date.fromISOExtString("99Jul04")); | |
7841 | assertThrown!DateTimeException(Date.fromISOExtString("010Jul04")); | |
7842 | assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0")); | |
7843 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 ")); | |
7844 | assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04")); | |
7845 | assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04")); | |
7846 | assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04")); | |
7847 | assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a")); | |
7848 | assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04")); | |
7849 | assertThrown!DateTimeException(Date.fromISOExtString("2010aul04")); | |
7850 | ||
7851 | assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04")); | |
7852 | assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04")); | |
7853 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0")); | |
7854 | assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 ")); | |
7855 | assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04")); | |
7856 | assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04")); | |
7857 | assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04")); | |
7858 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a")); | |
7859 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04")); | |
7860 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04")); | |
7861 | assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04")); | |
7862 | ||
7863 | assertThrown!DateTimeException(Date.fromISOExtString("20100704")); | |
7864 | assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04")); | |
7865 | ||
7866 | assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6)); | |
7867 | assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6)); | |
7868 | assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6)); | |
7869 | assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6)); | |
7870 | assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6)); | |
7871 | assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6)); | |
7872 | } | |
7873 | ||
5fee5ec3 | 7874 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
7875 | @safe unittest |
7876 | { | |
7877 | import std.conv : to; | |
7878 | import std.meta : AliasSeq; | |
5fee5ec3 | 7879 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 7880 | { |
5fee5ec3 | 7881 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
7882 | assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21)); |
7883 | } | |
7884 | } | |
7885 | ||
7886 | ||
7887 | /++ | |
7888 | Creates a $(LREF Date) from a string with the format YYYY-Mon-DD. | |
7889 | Whitespace is stripped from the given string. | |
7890 | ||
7891 | Params: | |
7892 | simpleString = A string formatted in the way that toSimpleString | |
7893 | formats dates. | |
7894 | ||
7895 | Throws: | |
7896 | $(REF DateTimeException,std,datetime,date) if the given string is | |
7897 | not in the correct format or if the resulting $(LREF Date) would not | |
7898 | be valid. | |
7899 | +/ | |
5fee5ec3 | 7900 | static Date fromSimpleString(S)(scope const S simpleString) @safe pure |
b4c522fa IB |
7901 | if (isSomeString!(S)) |
7902 | { | |
5fee5ec3 IB |
7903 | import std.algorithm.searching : startsWith; |
7904 | import std.conv : to, ConvException; | |
b4c522fa IB |
7905 | import std.format : format; |
7906 | import std.string : strip; | |
7907 | ||
5fee5ec3 | 7908 | auto str = strip(simpleString); |
b4c522fa | 7909 | |
5fee5ec3 IB |
7910 | if (str.length < 11 || str[$-3] != '-' || str[$-7] != '-') |
7911 | throw new DateTimeException(format!"Invalid string format: %s"(simpleString)); | |
b4c522fa | 7912 | |
5fee5ec3 IB |
7913 | int year; |
7914 | uint day; | |
7915 | auto month = monthFromString(str[$ - 6 .. $ - 3]); | |
7916 | auto yearStr = str[0 .. $ - 7]; | |
7917 | auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); | |
7918 | if ((yearStr.length > 4) != signAtBegining) | |
7919 | { | |
7920 | throw new DateTimeException(format!"Invalid string format: %s"(simpleString)); | |
7921 | } | |
b4c522fa | 7922 | |
5fee5ec3 | 7923 | try |
b4c522fa | 7924 | { |
5fee5ec3 IB |
7925 | day = to!uint(str[$ - 2 .. $]); |
7926 | year = to!int(yearStr); | |
7927 | } | |
7928 | catch (ConvException) | |
7929 | { | |
7930 | throw new DateTimeException(format!"Invalid string format: %s"(simpleString)); | |
b4c522fa | 7931 | } |
b4c522fa | 7932 | |
5fee5ec3 | 7933 | return Date(year, month, day); |
b4c522fa IB |
7934 | } |
7935 | ||
7936 | /// | |
7937 | @safe unittest | |
7938 | { | |
7939 | assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); | |
7940 | assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); | |
7941 | assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); | |
7942 | assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); | |
7943 | assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); | |
7944 | } | |
7945 | ||
7946 | @safe unittest | |
7947 | { | |
7948 | assertThrown!DateTimeException(Date.fromSimpleString("")); | |
7949 | assertThrown!DateTimeException(Date.fromSimpleString("990704")); | |
7950 | assertThrown!DateTimeException(Date.fromSimpleString("0100704")); | |
7951 | assertThrown!DateTimeException(Date.fromSimpleString("2010070")); | |
7952 | assertThrown!DateTimeException(Date.fromSimpleString("2010070 ")); | |
7953 | assertThrown!DateTimeException(Date.fromSimpleString("120100704")); | |
7954 | assertThrown!DateTimeException(Date.fromSimpleString("-0100704")); | |
7955 | assertThrown!DateTimeException(Date.fromSimpleString("+0100704")); | |
7956 | assertThrown!DateTimeException(Date.fromSimpleString("2010070a")); | |
7957 | assertThrown!DateTimeException(Date.fromSimpleString("20100a04")); | |
7958 | assertThrown!DateTimeException(Date.fromSimpleString("2010a704")); | |
7959 | ||
7960 | assertThrown!DateTimeException(Date.fromSimpleString("99-07-04")); | |
7961 | assertThrown!DateTimeException(Date.fromSimpleString("010-07-04")); | |
7962 | assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0")); | |
7963 | assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 ")); | |
7964 | assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04")); | |
7965 | assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04")); | |
7966 | assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04")); | |
7967 | assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a")); | |
7968 | assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04")); | |
7969 | assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04")); | |
7970 | assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04")); | |
7971 | assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04")); | |
7972 | assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4")); | |
7973 | assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4")); | |
7974 | assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04")); | |
7975 | assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4")); | |
7976 | assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4")); | |
7977 | ||
7978 | assertThrown!DateTimeException(Date.fromSimpleString("99Jul04")); | |
7979 | assertThrown!DateTimeException(Date.fromSimpleString("010Jul04")); | |
7980 | assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0")); | |
7981 | assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 ")); | |
7982 | assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04")); | |
7983 | assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04")); | |
7984 | assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04")); | |
7985 | assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a")); | |
7986 | assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04")); | |
7987 | assertThrown!DateTimeException(Date.fromSimpleString("2010aul04")); | |
7988 | ||
7989 | assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04")); | |
7990 | assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04")); | |
7991 | assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0")); | |
7992 | assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 ")); | |
7993 | assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04")); | |
7994 | assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04")); | |
7995 | assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04")); | |
7996 | assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a")); | |
7997 | assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04")); | |
7998 | assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04")); | |
7999 | assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04")); | |
8000 | ||
8001 | assertThrown!DateTimeException(Date.fromSimpleString("20100704")); | |
8002 | assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04")); | |
8003 | ||
8004 | assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6)); | |
8005 | assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6)); | |
8006 | assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6)); | |
8007 | assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6)); | |
8008 | assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6)); | |
8009 | assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6)); | |
8010 | } | |
8011 | ||
5fee5ec3 | 8012 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
8013 | @safe unittest |
8014 | { | |
8015 | import std.conv : to; | |
8016 | import std.meta : AliasSeq; | |
5fee5ec3 | 8017 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 8018 | { |
5fee5ec3 | 8019 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
8020 | assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21)); |
8021 | } | |
8022 | } | |
8023 | ||
8024 | ||
8025 | /++ | |
8026 | Returns the $(LREF Date) farthest in the past which is representable by | |
8027 | $(LREF Date). | |
8028 | +/ | |
8029 | @property static Date min() @safe pure nothrow @nogc | |
8030 | { | |
8031 | auto date = Date.init; | |
8032 | date._year = short.min; | |
8033 | date._month = Month.jan; | |
8034 | date._day = 1; | |
8035 | ||
8036 | return date; | |
8037 | } | |
8038 | ||
8039 | @safe unittest | |
8040 | { | |
8041 | assert(Date.min.year < 0); | |
8042 | assert(Date.min < Date.max); | |
8043 | } | |
8044 | ||
8045 | ||
8046 | /++ | |
8047 | Returns the $(LREF Date) farthest in the future which is representable | |
8048 | by $(LREF Date). | |
8049 | +/ | |
8050 | @property static Date max() @safe pure nothrow @nogc | |
8051 | { | |
8052 | auto date = Date.init; | |
8053 | date._year = short.max; | |
8054 | date._month = Month.dec; | |
8055 | date._day = 31; | |
8056 | ||
8057 | return date; | |
8058 | } | |
8059 | ||
8060 | @safe unittest | |
8061 | { | |
8062 | assert(Date.max.year > 0); | |
8063 | assert(Date.max > Date.min); | |
8064 | } | |
8065 | ||
8066 | ||
8067 | private: | |
8068 | ||
8069 | /+ | |
8070 | Whether the given values form a valid date. | |
8071 | ||
8072 | Params: | |
8073 | year = The year to test. | |
8074 | month = The month of the Gregorian Calendar to test. | |
8075 | day = The day of the month to test. | |
8076 | +/ | |
8077 | static bool _valid(int year, int month, int day) @safe pure nothrow @nogc | |
8078 | { | |
8079 | if (!valid!"months"(month)) | |
8080 | return false; | |
8081 | return valid!"days"(year, month, day); | |
8082 | } | |
8083 | ||
8084 | ||
8085 | package: | |
8086 | ||
8087 | /+ | |
8088 | Adds the given number of days to this $(LREF Date). A negative number | |
8089 | will subtract. | |
8090 | ||
8091 | The month will be adjusted along with the day if the number of days | |
8092 | added (or subtracted) would overflow (or underflow) the current month. | |
8093 | The year will be adjusted along with the month if the increase (or | |
8094 | decrease) to the month would cause it to overflow (or underflow) the | |
8095 | current year. | |
8096 | ||
5fee5ec3 | 8097 | `_addDays(numDays)` is effectively equivalent to |
b4c522fa IB |
8098 | $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days). |
8099 | ||
8100 | Params: | |
8101 | days = The number of days to add to this Date. | |
8102 | +/ | |
8103 | ref Date _addDays(long days) return @safe pure nothrow @nogc | |
8104 | { | |
8105 | dayOfGregorianCal = cast(int)(dayOfGregorianCal + days); | |
8106 | return this; | |
8107 | } | |
8108 | ||
8109 | @safe unittest | |
8110 | { | |
8111 | // Test A.D. | |
8112 | { | |
8113 | auto date = Date(1999, 2, 28); | |
8114 | date._addDays(1); | |
8115 | assert(date == Date(1999, 3, 1)); | |
8116 | date._addDays(-1); | |
8117 | assert(date == Date(1999, 2, 28)); | |
8118 | } | |
8119 | ||
8120 | { | |
8121 | auto date = Date(2000, 2, 28); | |
8122 | date._addDays(1); | |
8123 | assert(date == Date(2000, 2, 29)); | |
8124 | date._addDays(1); | |
8125 | assert(date == Date(2000, 3, 1)); | |
8126 | date._addDays(-1); | |
8127 | assert(date == Date(2000, 2, 29)); | |
8128 | } | |
8129 | ||
8130 | { | |
8131 | auto date = Date(1999, 6, 30); | |
8132 | date._addDays(1); | |
8133 | assert(date == Date(1999, 7, 1)); | |
8134 | date._addDays(-1); | |
8135 | assert(date == Date(1999, 6, 30)); | |
8136 | } | |
8137 | ||
8138 | { | |
8139 | auto date = Date(1999, 7, 31); | |
8140 | date._addDays(1); | |
8141 | assert(date == Date(1999, 8, 1)); | |
8142 | date._addDays(-1); | |
8143 | assert(date == Date(1999, 7, 31)); | |
8144 | } | |
8145 | ||
8146 | { | |
8147 | auto date = Date(1999, 1, 1); | |
8148 | date._addDays(-1); | |
8149 | assert(date == Date(1998, 12, 31)); | |
8150 | date._addDays(1); | |
8151 | assert(date == Date(1999, 1, 1)); | |
8152 | } | |
8153 | ||
8154 | { | |
8155 | auto date = Date(1999, 7, 6); | |
8156 | date._addDays(9); | |
8157 | assert(date == Date(1999, 7, 15)); | |
8158 | date._addDays(-11); | |
8159 | assert(date == Date(1999, 7, 4)); | |
8160 | date._addDays(30); | |
8161 | assert(date == Date(1999, 8, 3)); | |
8162 | date._addDays(-3); | |
8163 | assert(date == Date(1999, 7, 31)); | |
8164 | } | |
8165 | ||
8166 | { | |
8167 | auto date = Date(1999, 7, 6); | |
8168 | date._addDays(365); | |
8169 | assert(date == Date(2000, 7, 5)); | |
8170 | date._addDays(-365); | |
8171 | assert(date == Date(1999, 7, 6)); | |
8172 | date._addDays(366); | |
8173 | assert(date == Date(2000, 7, 6)); | |
8174 | date._addDays(730); | |
8175 | assert(date == Date(2002, 7, 6)); | |
8176 | date._addDays(-1096); | |
8177 | assert(date == Date(1999, 7, 6)); | |
8178 | } | |
8179 | ||
8180 | // Test B.C. | |
8181 | { | |
8182 | auto date = Date(-1999, 2, 28); | |
8183 | date._addDays(1); | |
8184 | assert(date == Date(-1999, 3, 1)); | |
8185 | date._addDays(-1); | |
8186 | assert(date == Date(-1999, 2, 28)); | |
8187 | } | |
8188 | ||
8189 | { | |
8190 | auto date = Date(-2000, 2, 28); | |
8191 | date._addDays(1); | |
8192 | assert(date == Date(-2000, 2, 29)); | |
8193 | date._addDays(1); | |
8194 | assert(date == Date(-2000, 3, 1)); | |
8195 | date._addDays(-1); | |
8196 | assert(date == Date(-2000, 2, 29)); | |
8197 | } | |
8198 | ||
8199 | { | |
8200 | auto date = Date(-1999, 6, 30); | |
8201 | date._addDays(1); | |
8202 | assert(date == Date(-1999, 7, 1)); | |
8203 | date._addDays(-1); | |
8204 | assert(date == Date(-1999, 6, 30)); | |
8205 | } | |
8206 | ||
8207 | { | |
8208 | auto date = Date(-1999, 7, 31); | |
8209 | date._addDays(1); | |
8210 | assert(date == Date(-1999, 8, 1)); | |
8211 | date._addDays(-1); | |
8212 | assert(date == Date(-1999, 7, 31)); | |
8213 | } | |
8214 | ||
8215 | { | |
8216 | auto date = Date(-1999, 1, 1); | |
8217 | date._addDays(-1); | |
8218 | assert(date == Date(-2000, 12, 31)); | |
8219 | date._addDays(1); | |
8220 | assert(date == Date(-1999, 1, 1)); | |
8221 | } | |
8222 | ||
8223 | { | |
8224 | auto date = Date(-1999, 7, 6); | |
8225 | date._addDays(9); | |
8226 | assert(date == Date(-1999, 7, 15)); | |
8227 | date._addDays(-11); | |
8228 | assert(date == Date(-1999, 7, 4)); | |
8229 | date._addDays(30); | |
8230 | assert(date == Date(-1999, 8, 3)); | |
8231 | date._addDays(-3); | |
8232 | } | |
8233 | ||
8234 | { | |
8235 | auto date = Date(-1999, 7, 6); | |
8236 | date._addDays(365); | |
8237 | assert(date == Date(-1998, 7, 6)); | |
8238 | date._addDays(-365); | |
8239 | assert(date == Date(-1999, 7, 6)); | |
8240 | date._addDays(366); | |
8241 | assert(date == Date(-1998, 7, 7)); | |
8242 | date._addDays(730); | |
8243 | assert(date == Date(-1996, 7, 6)); | |
8244 | date._addDays(-1096); | |
8245 | assert(date == Date(-1999, 7, 6)); | |
8246 | } | |
8247 | ||
8248 | // Test Both | |
8249 | { | |
8250 | auto date = Date(1, 7, 6); | |
8251 | date._addDays(-365); | |
8252 | assert(date == Date(0, 7, 6)); | |
8253 | date._addDays(365); | |
8254 | assert(date == Date(1, 7, 6)); | |
8255 | date._addDays(-731); | |
8256 | assert(date == Date(-1, 7, 6)); | |
8257 | date._addDays(730); | |
8258 | assert(date == Date(1, 7, 5)); | |
8259 | } | |
8260 | ||
8261 | const cdate = Date(1999, 7, 6); | |
8262 | immutable idate = Date(1999, 7, 6); | |
8263 | static assert(!__traits(compiles, cdate._addDays(12))); | |
8264 | static assert(!__traits(compiles, idate._addDays(12))); | |
8265 | } | |
8266 | ||
8267 | ||
8268 | @safe pure invariant() | |
8269 | { | |
8270 | import std.format : format; | |
8271 | assert(valid!"months"(_month), | |
8272 | format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); | |
8273 | assert(valid!"days"(_year, _month, _day), | |
8274 | format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); | |
8275 | } | |
8276 | ||
8277 | short _year = 1; | |
8278 | Month _month = Month.jan; | |
8279 | ubyte _day = 1; | |
8280 | } | |
8281 | ||
5fee5ec3 IB |
8282 | /// |
8283 | @safe pure unittest | |
8284 | { | |
8285 | import core.time : days; | |
8286 | ||
8287 | auto d = Date(2000, 6, 1); | |
8288 | ||
8289 | assert(d.dayOfYear == 153); | |
8290 | assert(d.dayOfWeek == DayOfWeek.thu); | |
8291 | ||
8292 | d += 10.days; | |
8293 | assert(d == Date(2000, 6, 11)); | |
8294 | ||
8295 | assert(d.toISOExtString() == "2000-06-11"); | |
8296 | assert(d.toISOString() == "20000611"); | |
8297 | assert(d.toSimpleString() == "2000-Jun-11"); | |
8298 | ||
8299 | assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1)); | |
8300 | assert(Date.fromISOString("20180101") == Date(2018, 1, 1)); | |
8301 | assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1)); | |
8302 | } | |
8303 | ||
b4c522fa IB |
8304 | |
8305 | /++ | |
8306 | Represents a time of day with hours, minutes, and seconds. It uses 24 hour | |
8307 | time. | |
8308 | +/ | |
8309 | struct TimeOfDay | |
8310 | { | |
8311 | public: | |
8312 | ||
8313 | /++ | |
8314 | Params: | |
8315 | hour = Hour of the day [0 - 24$(RPAREN). | |
8316 | minute = Minute of the hour [0 - 60$(RPAREN). | |
8317 | second = Second of the minute [0 - 60$(RPAREN). | |
8318 | ||
8319 | Throws: | |
8320 | $(REF DateTimeException,std,datetime,date) if the resulting | |
8321 | $(LREF TimeOfDay) would be not be valid. | |
8322 | +/ | |
8323 | this(int hour, int minute, int second = 0) @safe pure | |
8324 | { | |
8325 | enforceValid!"hours"(hour); | |
8326 | enforceValid!"minutes"(minute); | |
8327 | enforceValid!"seconds"(second); | |
8328 | ||
8329 | _hour = cast(ubyte) hour; | |
8330 | _minute = cast(ubyte) minute; | |
8331 | _second = cast(ubyte) second; | |
8332 | } | |
8333 | ||
8334 | @safe unittest | |
8335 | { | |
8336 | assert(TimeOfDay(0, 0) == TimeOfDay.init); | |
8337 | ||
8338 | { | |
8339 | auto tod = TimeOfDay(0, 0); | |
8340 | assert(tod._hour == 0); | |
8341 | assert(tod._minute == 0); | |
8342 | assert(tod._second == 0); | |
8343 | } | |
8344 | ||
8345 | { | |
8346 | auto tod = TimeOfDay(12, 30, 33); | |
8347 | assert(tod._hour == 12); | |
8348 | assert(tod._minute == 30); | |
8349 | assert(tod._second == 33); | |
8350 | } | |
8351 | ||
8352 | { | |
8353 | auto tod = TimeOfDay(23, 59, 59); | |
8354 | assert(tod._hour == 23); | |
8355 | assert(tod._minute == 59); | |
8356 | assert(tod._second == 59); | |
8357 | } | |
8358 | ||
8359 | assertThrown!DateTimeException(TimeOfDay(24, 0, 0)); | |
8360 | assertThrown!DateTimeException(TimeOfDay(0, 60, 0)); | |
8361 | assertThrown!DateTimeException(TimeOfDay(0, 0, 60)); | |
8362 | } | |
8363 | ||
8364 | ||
8365 | /++ | |
8366 | Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay). | |
8367 | ||
8368 | Returns: | |
8369 | $(BOOKTABLE, | |
8370 | $(TR $(TD this < rhs) $(TD < 0)) | |
8371 | $(TR $(TD this == rhs) $(TD 0)) | |
8372 | $(TR $(TD this > rhs) $(TD > 0)) | |
8373 | ) | |
8374 | +/ | |
5fee5ec3 | 8375 | int opCmp(TimeOfDay rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
8376 | { |
8377 | if (_hour < rhs._hour) | |
8378 | return -1; | |
8379 | if (_hour > rhs._hour) | |
8380 | return 1; | |
8381 | ||
8382 | if (_minute < rhs._minute) | |
8383 | return -1; | |
8384 | if (_minute > rhs._minute) | |
8385 | return 1; | |
8386 | ||
8387 | if (_second < rhs._second) | |
8388 | return -1; | |
8389 | if (_second > rhs._second) | |
8390 | return 1; | |
8391 | ||
8392 | return 0; | |
8393 | } | |
8394 | ||
8395 | @safe unittest | |
8396 | { | |
8397 | assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0); | |
8398 | ||
8399 | assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0); | |
8400 | assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0); | |
8401 | assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0); | |
8402 | assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); | |
8403 | ||
8404 | assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0); | |
8405 | assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0); | |
8406 | ||
8407 | assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0); | |
8408 | assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); | |
8409 | ||
8410 | assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); | |
8411 | assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); | |
8412 | assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0); | |
8413 | assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); | |
8414 | assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0); | |
8415 | assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0); | |
8416 | ||
8417 | assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); | |
8418 | assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0); | |
8419 | assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0); | |
8420 | assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); | |
8421 | ||
8422 | assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); | |
8423 | assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0); | |
8424 | ||
8425 | const ctod = TimeOfDay(12, 30, 33); | |
8426 | immutable itod = TimeOfDay(12, 30, 33); | |
8427 | assert(ctod.opCmp(itod) == 0); | |
8428 | assert(itod.opCmp(ctod) == 0); | |
8429 | } | |
8430 | ||
8431 | ||
8432 | /++ | |
8433 | Hours past midnight. | |
8434 | +/ | |
8435 | @property ubyte hour() const @safe pure nothrow @nogc | |
8436 | { | |
8437 | return _hour; | |
8438 | } | |
8439 | ||
8440 | @safe unittest | |
8441 | { | |
8442 | assert(TimeOfDay.init.hour == 0); | |
8443 | assert(TimeOfDay(12, 0, 0).hour == 12); | |
8444 | ||
8445 | const ctod = TimeOfDay(12, 0, 0); | |
8446 | immutable itod = TimeOfDay(12, 0, 0); | |
8447 | assert(ctod.hour == 12); | |
8448 | assert(itod.hour == 12); | |
8449 | } | |
8450 | ||
8451 | ||
8452 | /++ | |
8453 | Hours past midnight. | |
8454 | ||
8455 | Params: | |
8456 | hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to. | |
8457 | ||
8458 | Throws: | |
8459 | $(REF DateTimeException,std,datetime,date) if the given hour would | |
8460 | result in an invalid $(LREF TimeOfDay). | |
8461 | +/ | |
8462 | @property void hour(int hour) @safe pure | |
8463 | { | |
8464 | enforceValid!"hours"(hour); | |
8465 | _hour = cast(ubyte) hour; | |
8466 | } | |
8467 | ||
8468 | @safe unittest | |
8469 | { | |
8470 | assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}()); | |
8471 | ||
8472 | auto tod = TimeOfDay(0, 0, 0); | |
8473 | tod.hour = 12; | |
8474 | assert(tod == TimeOfDay(12, 0, 0)); | |
8475 | ||
8476 | const ctod = TimeOfDay(0, 0, 0); | |
8477 | immutable itod = TimeOfDay(0, 0, 0); | |
8478 | static assert(!__traits(compiles, ctod.hour = 12)); | |
8479 | static assert(!__traits(compiles, itod.hour = 12)); | |
8480 | } | |
8481 | ||
8482 | ||
8483 | /++ | |
8484 | Minutes past the hour. | |
8485 | +/ | |
8486 | @property ubyte minute() const @safe pure nothrow @nogc | |
8487 | { | |
8488 | return _minute; | |
8489 | } | |
8490 | ||
8491 | @safe unittest | |
8492 | { | |
8493 | assert(TimeOfDay.init.minute == 0); | |
8494 | assert(TimeOfDay(0, 30, 0).minute == 30); | |
8495 | ||
8496 | const ctod = TimeOfDay(0, 30, 0); | |
8497 | immutable itod = TimeOfDay(0, 30, 0); | |
8498 | assert(ctod.minute == 30); | |
8499 | assert(itod.minute == 30); | |
8500 | } | |
8501 | ||
8502 | ||
8503 | /++ | |
8504 | Minutes past the hour. | |
8505 | ||
8506 | Params: | |
8507 | minute = The minute to set this $(LREF TimeOfDay)'s minute to. | |
8508 | ||
8509 | Throws: | |
8510 | $(REF DateTimeException,std,datetime,date) if the given minute | |
8511 | would result in an invalid $(LREF TimeOfDay). | |
8512 | +/ | |
8513 | @property void minute(int minute) @safe pure | |
8514 | { | |
8515 | enforceValid!"minutes"(minute); | |
8516 | _minute = cast(ubyte) minute; | |
8517 | } | |
8518 | ||
8519 | @safe unittest | |
8520 | { | |
8521 | assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}()); | |
8522 | ||
8523 | auto tod = TimeOfDay(0, 0, 0); | |
8524 | tod.minute = 30; | |
8525 | assert(tod == TimeOfDay(0, 30, 0)); | |
8526 | ||
8527 | const ctod = TimeOfDay(0, 0, 0); | |
8528 | immutable itod = TimeOfDay(0, 0, 0); | |
8529 | static assert(!__traits(compiles, ctod.minute = 30)); | |
8530 | static assert(!__traits(compiles, itod.minute = 30)); | |
8531 | } | |
8532 | ||
8533 | ||
8534 | /++ | |
8535 | Seconds past the minute. | |
8536 | +/ | |
8537 | @property ubyte second() const @safe pure nothrow @nogc | |
8538 | { | |
8539 | return _second; | |
8540 | } | |
8541 | ||
8542 | @safe unittest | |
8543 | { | |
8544 | assert(TimeOfDay.init.second == 0); | |
8545 | assert(TimeOfDay(0, 0, 33).second == 33); | |
8546 | ||
8547 | const ctod = TimeOfDay(0, 0, 33); | |
8548 | immutable itod = TimeOfDay(0, 0, 33); | |
8549 | assert(ctod.second == 33); | |
8550 | assert(itod.second == 33); | |
8551 | } | |
8552 | ||
8553 | ||
8554 | /++ | |
8555 | Seconds past the minute. | |
8556 | ||
8557 | Params: | |
8558 | second = The second to set this $(LREF TimeOfDay)'s second to. | |
8559 | ||
8560 | Throws: | |
8561 | $(REF DateTimeException,std,datetime,date) if the given second | |
8562 | would result in an invalid $(LREF TimeOfDay). | |
8563 | +/ | |
8564 | @property void second(int second) @safe pure | |
8565 | { | |
8566 | enforceValid!"seconds"(second); | |
8567 | _second = cast(ubyte) second; | |
8568 | } | |
8569 | ||
8570 | @safe unittest | |
8571 | { | |
8572 | assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}()); | |
8573 | ||
8574 | auto tod = TimeOfDay(0, 0, 0); | |
8575 | tod.second = 33; | |
8576 | assert(tod == TimeOfDay(0, 0, 33)); | |
8577 | ||
8578 | const ctod = TimeOfDay(0, 0, 0); | |
8579 | immutable itod = TimeOfDay(0, 0, 0); | |
8580 | static assert(!__traits(compiles, ctod.second = 33)); | |
8581 | static assert(!__traits(compiles, itod.second = 33)); | |
8582 | } | |
8583 | ||
8584 | ||
8585 | /++ | |
5fee5ec3 IB |
8586 | Adds the given number of units to this $(LREF TimeOfDay), mutating it. A |
8587 | negative number will subtract. | |
b4c522fa IB |
8588 | |
8589 | The difference between rolling and adding is that rolling does not | |
8590 | affect larger units. For instance, rolling a $(LREF TimeOfDay) | |
8591 | one hours's worth of minutes gets the exact same | |
8592 | $(LREF TimeOfDay). | |
8593 | ||
5fee5ec3 | 8594 | Accepted units are `"hours"`, `"minutes"`, and `"seconds"`. |
b4c522fa IB |
8595 | |
8596 | Params: | |
8597 | units = The units to add. | |
8598 | value = The number of $(D_PARAM units) to add to this | |
8599 | $(LREF TimeOfDay). | |
5fee5ec3 IB |
8600 | |
8601 | Returns: | |
8602 | A reference to the `TimeOfDay` (`this`). | |
b4c522fa IB |
8603 | +/ |
8604 | ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc | |
8605 | if (units == "hours") | |
8606 | { | |
5fee5ec3 | 8607 | import core.time : dur; |
b4c522fa IB |
8608 | return this += dur!"hours"(value); |
8609 | } | |
8610 | ||
8611 | /// | |
8612 | @safe unittest | |
8613 | { | |
8614 | auto tod1 = TimeOfDay(7, 12, 0); | |
8615 | tod1.roll!"hours"(1); | |
8616 | assert(tod1 == TimeOfDay(8, 12, 0)); | |
8617 | ||
8618 | auto tod2 = TimeOfDay(7, 12, 0); | |
8619 | tod2.roll!"hours"(-1); | |
8620 | assert(tod2 == TimeOfDay(6, 12, 0)); | |
8621 | ||
8622 | auto tod3 = TimeOfDay(23, 59, 0); | |
8623 | tod3.roll!"minutes"(1); | |
8624 | assert(tod3 == TimeOfDay(23, 0, 0)); | |
8625 | ||
8626 | auto tod4 = TimeOfDay(0, 0, 0); | |
8627 | tod4.roll!"minutes"(-1); | |
8628 | assert(tod4 == TimeOfDay(0, 59, 0)); | |
8629 | ||
8630 | auto tod5 = TimeOfDay(23, 59, 59); | |
8631 | tod5.roll!"seconds"(1); | |
8632 | assert(tod5 == TimeOfDay(23, 59, 0)); | |
8633 | ||
8634 | auto tod6 = TimeOfDay(0, 0, 0); | |
8635 | tod6.roll!"seconds"(-1); | |
8636 | assert(tod6 == TimeOfDay(0, 0, 59)); | |
8637 | } | |
8638 | ||
8639 | @safe unittest | |
8640 | { | |
8641 | auto tod = TimeOfDay(12, 27, 2); | |
8642 | tod.roll!"hours"(22).roll!"hours"(-7); | |
8643 | assert(tod == TimeOfDay(3, 27, 2)); | |
8644 | ||
8645 | const ctod = TimeOfDay(0, 0, 0); | |
8646 | immutable itod = TimeOfDay(0, 0, 0); | |
8647 | static assert(!__traits(compiles, ctod.roll!"hours"(53))); | |
8648 | static assert(!__traits(compiles, itod.roll!"hours"(53))); | |
8649 | } | |
8650 | ||
8651 | ||
5fee5ec3 | 8652 | /// ditto |
b4c522fa IB |
8653 | ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc |
8654 | if (units == "minutes" || units == "seconds") | |
8655 | { | |
8656 | import std.format : format; | |
8657 | ||
8658 | enum memberVarStr = units[0 .. $ - 1]; | |
8659 | value %= 60; | |
8660 | mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr)); | |
8661 | ||
8662 | if (value < 0) | |
8663 | { | |
8664 | if (newVal < 0) | |
8665 | newVal += 60; | |
8666 | } | |
8667 | else if (newVal >= 60) | |
8668 | newVal -= 60; | |
8669 | ||
8670 | mixin(format("_%s = cast(ubyte) newVal;", memberVarStr)); | |
8671 | return this; | |
8672 | } | |
8673 | ||
8674 | // Test roll!"minutes"(). | |
8675 | @safe unittest | |
8676 | { | |
5fee5ec3 | 8677 | static void testTOD(TimeOfDay orig, int minutes, TimeOfDay expected, size_t line = __LINE__) |
b4c522fa IB |
8678 | { |
8679 | orig.roll!"minutes"(minutes); | |
8680 | assert(orig == expected); | |
8681 | } | |
8682 | ||
8683 | testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); | |
8684 | testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33)); | |
8685 | testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33)); | |
8686 | testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33)); | |
8687 | testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33)); | |
8688 | testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33)); | |
8689 | testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33)); | |
8690 | testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33)); | |
8691 | testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33)); | |
8692 | testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33)); | |
8693 | testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33)); | |
8694 | testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); | |
8695 | testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33)); | |
8696 | testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33)); | |
8697 | testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33)); | |
8698 | ||
8699 | testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33)); | |
8700 | testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33)); | |
8701 | testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33)); | |
8702 | testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33)); | |
8703 | testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33)); | |
8704 | testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33)); | |
8705 | testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33)); | |
8706 | testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33)); | |
8707 | ||
8708 | testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33)); | |
8709 | testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33)); | |
8710 | testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33)); | |
8711 | testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33)); | |
8712 | testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33)); | |
8713 | testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33)); | |
8714 | testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33)); | |
8715 | testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33)); | |
8716 | testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33)); | |
8717 | testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33)); | |
8718 | testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); | |
8719 | testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33)); | |
8720 | testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33)); | |
8721 | testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33)); | |
8722 | ||
8723 | testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33)); | |
8724 | testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33)); | |
8725 | testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33)); | |
8726 | testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33)); | |
8727 | testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33)); | |
8728 | testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33)); | |
8729 | testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33)); | |
8730 | testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33)); | |
8731 | ||
8732 | testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33)); | |
8733 | testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33)); | |
8734 | testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33)); | |
8735 | ||
8736 | testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33)); | |
8737 | testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33)); | |
8738 | testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33)); | |
8739 | ||
8740 | testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33)); | |
8741 | testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33)); | |
8742 | testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33)); | |
8743 | ||
8744 | testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33)); | |
8745 | testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33)); | |
8746 | testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33)); | |
8747 | ||
8748 | auto tod = TimeOfDay(12, 27, 2); | |
8749 | tod.roll!"minutes"(97).roll!"minutes"(-102); | |
8750 | assert(tod == TimeOfDay(12, 22, 2)); | |
8751 | ||
8752 | const ctod = TimeOfDay(0, 0, 0); | |
8753 | immutable itod = TimeOfDay(0, 0, 0); | |
8754 | static assert(!__traits(compiles, ctod.roll!"minutes"(7))); | |
8755 | static assert(!__traits(compiles, itod.roll!"minutes"(7))); | |
8756 | } | |
8757 | ||
8758 | // Test roll!"seconds"(). | |
8759 | @safe unittest | |
8760 | { | |
5fee5ec3 | 8761 | static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) |
b4c522fa IB |
8762 | { |
8763 | orig.roll!"seconds"(seconds); | |
8764 | assert(orig == expected); | |
8765 | } | |
8766 | ||
8767 | testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); | |
8768 | testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); | |
8769 | testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); | |
8770 | testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); | |
8771 | testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); | |
8772 | testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); | |
8773 | testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); | |
8774 | testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); | |
8775 | testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); | |
8776 | testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0)); | |
8777 | testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3)); | |
8778 | testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32)); | |
8779 | testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); | |
8780 | testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34)); | |
8781 | ||
8782 | testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59)); | |
8783 | testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0)); | |
8784 | testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1)); | |
8785 | testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0)); | |
8786 | testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32)); | |
8787 | testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33)); | |
8788 | testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34)); | |
8789 | testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33)); | |
8790 | ||
8791 | testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); | |
8792 | testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); | |
8793 | testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); | |
8794 | testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); | |
8795 | testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); | |
8796 | testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); | |
8797 | testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); | |
8798 | testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); | |
8799 | testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59)); | |
8800 | testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58)); | |
8801 | testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34)); | |
8802 | testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); | |
8803 | testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32)); | |
8804 | ||
8805 | testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); | |
8806 | testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); | |
8807 | testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59)); | |
8808 | ||
8809 | testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); | |
8810 | testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); | |
8811 | testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59)); | |
8812 | ||
8813 | testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); | |
8814 | testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); | |
8815 | testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59)); | |
8816 | ||
8817 | testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0)); | |
8818 | testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); | |
8819 | testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); | |
8820 | ||
8821 | auto tod = TimeOfDay(12, 27, 2); | |
8822 | tod.roll!"seconds"(105).roll!"seconds"(-77); | |
8823 | assert(tod == TimeOfDay(12, 27, 30)); | |
8824 | ||
8825 | const ctod = TimeOfDay(0, 0, 0); | |
8826 | immutable itod = TimeOfDay(0, 0, 0); | |
8827 | static assert(!__traits(compiles, ctod.roll!"seconds"(7))); | |
8828 | static assert(!__traits(compiles, itod.roll!"seconds"(7))); | |
8829 | } | |
8830 | ||
8831 | ||
5fee5ec3 | 8832 | import core.time : Duration; |
b4c522fa IB |
8833 | /++ |
8834 | Gives the result of adding or subtracting a $(REF Duration, core,time) | |
8835 | from this $(LREF TimeOfDay). | |
8836 | ||
8837 | The legal types of arithmetic for $(LREF TimeOfDay) using this operator | |
8838 | are | |
8839 | ||
8840 | $(BOOKTABLE, | |
8841 | $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) | |
8842 | $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) | |
8843 | ) | |
8844 | ||
8845 | Params: | |
8846 | duration = The $(REF Duration, core,time) to add to or subtract from | |
8847 | this $(LREF TimeOfDay). | |
8848 | +/ | |
8849 | TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc | |
8850 | if (op == "+" || op == "-") | |
8851 | { | |
8852 | TimeOfDay retval = this; | |
8853 | immutable seconds = duration.total!"seconds"; | |
8854 | mixin("return retval._addSeconds(" ~ op ~ "seconds);"); | |
8855 | } | |
8856 | ||
8857 | /// | |
8858 | @safe unittest | |
8859 | { | |
8860 | import core.time : hours, minutes, seconds; | |
8861 | ||
8862 | assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); | |
8863 | assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); | |
8864 | assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); | |
8865 | assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); | |
8866 | ||
8867 | assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); | |
8868 | assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); | |
8869 | assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); | |
8870 | assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); | |
8871 | } | |
8872 | ||
8873 | @safe unittest | |
8874 | { | |
8875 | auto tod = TimeOfDay(12, 30, 33); | |
8876 | ||
5fee5ec3 | 8877 | import core.time : dur; |
b4c522fa IB |
8878 | assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33)); |
8879 | assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); | |
8880 | assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); | |
8881 | assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); | |
8882 | assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); | |
8883 | assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); | |
8884 | ||
8885 | assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); | |
8886 | assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); | |
8887 | assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); | |
8888 | assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); | |
8889 | assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); | |
8890 | assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); | |
8891 | ||
8892 | assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); | |
8893 | assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33)); | |
8894 | assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); | |
8895 | assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); | |
8896 | assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); | |
8897 | assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); | |
8898 | ||
8899 | assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); | |
8900 | assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); | |
8901 | assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); | |
8902 | assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); | |
8903 | assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); | |
8904 | assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); | |
8905 | ||
8906 | auto duration = dur!"hours"(11); | |
8907 | const ctod = TimeOfDay(12, 30, 33); | |
8908 | immutable itod = TimeOfDay(12, 30, 33); | |
8909 | assert(tod + duration == TimeOfDay(23, 30, 33)); | |
8910 | assert(ctod + duration == TimeOfDay(23, 30, 33)); | |
8911 | assert(itod + duration == TimeOfDay(23, 30, 33)); | |
8912 | ||
8913 | assert(tod - duration == TimeOfDay(1, 30, 33)); | |
8914 | assert(ctod - duration == TimeOfDay(1, 30, 33)); | |
8915 | assert(itod - duration == TimeOfDay(1, 30, 33)); | |
8916 | } | |
8917 | ||
b4c522fa IB |
8918 | |
8919 | /++ | |
8920 | Gives the result of adding or subtracting a $(REF Duration, core,time) | |
8921 | from this $(LREF TimeOfDay), as well as assigning the result to this | |
8922 | $(LREF TimeOfDay). | |
8923 | ||
8924 | The legal types of arithmetic for $(LREF TimeOfDay) using this operator | |
8925 | are | |
8926 | ||
8927 | $(BOOKTABLE, | |
8928 | $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) | |
8929 | $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) | |
8930 | ) | |
8931 | ||
8932 | Params: | |
8933 | duration = The $(REF Duration, core,time) to add to or subtract from | |
8934 | this $(LREF TimeOfDay). | |
8935 | +/ | |
8936 | ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc | |
8937 | if (op == "+" || op == "-") | |
8938 | { | |
8939 | immutable seconds = duration.total!"seconds"; | |
8940 | mixin("return _addSeconds(" ~ op ~ "seconds);"); | |
8941 | } | |
8942 | ||
8943 | @safe unittest | |
8944 | { | |
5fee5ec3 | 8945 | import core.time : dur; |
b4c522fa IB |
8946 | auto duration = dur!"hours"(12); |
8947 | ||
8948 | assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33)); | |
8949 | assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); | |
8950 | assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); | |
8951 | assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); | |
8952 | assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); | |
8953 | assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); | |
8954 | ||
8955 | assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); | |
8956 | assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); | |
8957 | assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); | |
8958 | assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); | |
8959 | assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); | |
8960 | assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); | |
8961 | ||
8962 | assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); | |
8963 | assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33)); | |
8964 | assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); | |
8965 | assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); | |
8966 | assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); | |
8967 | assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); | |
8968 | ||
8969 | assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); | |
8970 | assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); | |
8971 | assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); | |
8972 | assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); | |
8973 | assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); | |
8974 | assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); | |
8975 | ||
8976 | auto tod = TimeOfDay(19, 17, 22); | |
8977 | (tod += dur!"seconds"(9)) += dur!"seconds"(-7292); | |
8978 | assert(tod == TimeOfDay(17, 15, 59)); | |
8979 | ||
8980 | const ctod = TimeOfDay(12, 33, 30); | |
8981 | immutable itod = TimeOfDay(12, 33, 30); | |
8982 | static assert(!__traits(compiles, ctod += duration)); | |
8983 | static assert(!__traits(compiles, itod += duration)); | |
8984 | static assert(!__traits(compiles, ctod -= duration)); | |
8985 | static assert(!__traits(compiles, itod -= duration)); | |
8986 | } | |
8987 | ||
b4c522fa IB |
8988 | |
8989 | /++ | |
8990 | Gives the difference between two $(LREF TimeOfDay)s. | |
8991 | ||
8992 | The legal types of arithmetic for $(LREF TimeOfDay) using this operator | |
8993 | are | |
8994 | ||
8995 | $(BOOKTABLE, | |
8996 | $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration)) | |
8997 | ) | |
8998 | ||
8999 | Params: | |
9000 | rhs = The $(LREF TimeOfDay) to subtract from this one. | |
9001 | +/ | |
5fee5ec3 | 9002 | Duration opBinary(string op)(TimeOfDay rhs) const @safe pure nothrow @nogc |
b4c522fa IB |
9003 | if (op == "-") |
9004 | { | |
9005 | immutable lhsSec = _hour * 3600 + _minute * 60 + _second; | |
9006 | immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second; | |
9007 | ||
5fee5ec3 | 9008 | import core.time : dur; |
b4c522fa IB |
9009 | return dur!"seconds"(lhsSec - rhsSec); |
9010 | } | |
9011 | ||
9012 | @safe unittest | |
9013 | { | |
9014 | auto tod = TimeOfDay(12, 30, 33); | |
9015 | ||
5fee5ec3 | 9016 | import core.time : dur; |
b4c522fa IB |
9017 | assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061)); |
9018 | assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061)); | |
9019 | assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200)); | |
9020 | assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200)); | |
9021 | assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240)); | |
9022 | assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240)); | |
9023 | assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1)); | |
9024 | assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1)); | |
9025 | ||
9026 | const ctod = TimeOfDay(12, 30, 33); | |
9027 | immutable itod = TimeOfDay(12, 30, 33); | |
9028 | assert(tod - tod == Duration.zero); | |
9029 | assert(ctod - tod == Duration.zero); | |
9030 | assert(itod - tod == Duration.zero); | |
9031 | ||
9032 | assert(tod - ctod == Duration.zero); | |
9033 | assert(ctod - ctod == Duration.zero); | |
9034 | assert(itod - ctod == Duration.zero); | |
9035 | ||
9036 | assert(tod - itod == Duration.zero); | |
9037 | assert(ctod - itod == Duration.zero); | |
9038 | assert(itod - itod == Duration.zero); | |
9039 | } | |
9040 | ||
9041 | ||
9042 | /++ | |
5fee5ec3 IB |
9043 | Converts this $(LREF TimeOfDay) to a string with the format `HHMMSS`. |
9044 | If `writer` is set, the resulting string will be written directly to it. | |
9045 | ||
9046 | Params: | |
9047 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
9048 | Returns: | |
9049 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
9050 | +/ |
9051 | string toISOString() const @safe pure nothrow | |
9052 | { | |
5fee5ec3 IB |
9053 | import std.array : appender; |
9054 | auto w = appender!string(); | |
9055 | w.reserve(6); | |
b4c522fa | 9056 | try |
5fee5ec3 | 9057 | toISOString(w); |
b4c522fa | 9058 | catch (Exception e) |
5fee5ec3 IB |
9059 | assert(0, "toISOString() threw."); |
9060 | return w.data; | |
9061 | } | |
9062 | ||
9063 | /// ditto | |
9064 | void toISOString(W)(ref W writer) const | |
9065 | if (isOutputRange!(W, char)) | |
9066 | { | |
9067 | import std.format.write : formattedWrite; | |
9068 | formattedWrite(writer, "%02d%02d%02d", _hour, _minute, _second); | |
b4c522fa IB |
9069 | } |
9070 | ||
9071 | /// | |
9072 | @safe unittest | |
9073 | { | |
9074 | assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); | |
9075 | assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); | |
9076 | } | |
9077 | ||
9078 | @safe unittest | |
9079 | { | |
9080 | auto tod = TimeOfDay(12, 30, 33); | |
9081 | const ctod = TimeOfDay(12, 30, 33); | |
9082 | immutable itod = TimeOfDay(12, 30, 33); | |
9083 | assert(tod.toISOString() == "123033"); | |
9084 | assert(ctod.toISOString() == "123033"); | |
9085 | assert(itod.toISOString() == "123033"); | |
9086 | } | |
9087 | ||
9088 | ||
9089 | /++ | |
5fee5ec3 IB |
9090 | Converts this $(LREF TimeOfDay) to a string with the format `HH:MM:SS`. |
9091 | If `writer` is set, the resulting string will be written directly to it. | |
9092 | ||
9093 | Params: | |
9094 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
9095 | Returns: | |
9096 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
9097 | +/ |
9098 | string toISOExtString() const @safe pure nothrow | |
9099 | { | |
5fee5ec3 IB |
9100 | import std.array : appender; |
9101 | auto w = appender!string(); | |
9102 | w.reserve(8); | |
b4c522fa | 9103 | try |
5fee5ec3 | 9104 | toISOExtString(w); |
b4c522fa | 9105 | catch (Exception e) |
5fee5ec3 IB |
9106 | assert(0, "toISOExtString() threw."); |
9107 | return w.data; | |
9108 | } | |
9109 | ||
9110 | /// ditto | |
9111 | void toISOExtString(W)(ref W writer) const | |
9112 | if (isOutputRange!(W, char)) | |
9113 | { | |
9114 | import std.format.write : formattedWrite; | |
9115 | formattedWrite(writer, "%02d:%02d:%02d", _hour, _minute, _second); | |
b4c522fa IB |
9116 | } |
9117 | ||
9118 | /// | |
9119 | @safe unittest | |
9120 | { | |
9121 | assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); | |
9122 | assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); | |
9123 | } | |
9124 | ||
9125 | @safe unittest | |
9126 | { | |
9127 | auto tod = TimeOfDay(12, 30, 33); | |
9128 | const ctod = TimeOfDay(12, 30, 33); | |
9129 | immutable itod = TimeOfDay(12, 30, 33); | |
9130 | assert(tod.toISOExtString() == "12:30:33"); | |
9131 | assert(ctod.toISOExtString() == "12:30:33"); | |
9132 | assert(itod.toISOExtString() == "12:30:33"); | |
9133 | } | |
9134 | ||
9135 | ||
9136 | /++ | |
9137 | Converts this TimeOfDay to a string. | |
9138 | ||
9139 | This function exists to make it easy to convert a $(LREF TimeOfDay) to a | |
9140 | string for code that does not care what the exact format is - just that | |
9141 | it presents the information in a clear manner. It also makes it easy to | |
9142 | simply convert a $(LREF TimeOfDay) to a string when using functions such | |
9143 | as `to!string`, `format`, or `writeln` which use toString to convert | |
9144 | user-defined types. So, it is unlikely that much code will call | |
9145 | toString directly. | |
9146 | ||
9147 | The format of the string is purposefully unspecified, and code that | |
9148 | cares about the format of the string should use `toISOString`, | |
9149 | `toISOExtString`, or some other custom formatting function that | |
9150 | explicitly generates the format that the code needs. The reason is that | |
9151 | the code is then clear about what format it's using, making it less | |
9152 | error-prone to maintain the code and interact with other software that | |
9153 | consumes the generated strings. It's for this same reason that | |
9154 | $(LREF TimeOfDay) has no `fromString` function, whereas it does have | |
9155 | `fromISOString` and `fromISOExtString`. | |
9156 | ||
9157 | The format returned by toString may or may not change in the future. | |
5fee5ec3 IB |
9158 | |
9159 | Params: | |
9160 | writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) | |
9161 | Returns: | |
9162 | A `string` when not using an output range; `void` otherwise. | |
b4c522fa IB |
9163 | +/ |
9164 | string toString() const @safe pure nothrow | |
9165 | { | |
9166 | return toISOExtString(); | |
9167 | } | |
9168 | ||
5fee5ec3 IB |
9169 | /// ditto |
9170 | void toString(W)(ref W writer) const | |
9171 | if (isOutputRange!(W, char)) | |
9172 | { | |
9173 | toISOExtString(writer); | |
9174 | } | |
9175 | ||
b4c522fa IB |
9176 | @safe unittest |
9177 | { | |
9178 | auto tod = TimeOfDay(12, 30, 33); | |
9179 | const ctod = TimeOfDay(12, 30, 33); | |
9180 | immutable itod = TimeOfDay(12, 30, 33); | |
9181 | assert(tod.toString()); | |
9182 | assert(ctod.toString()); | |
9183 | assert(itod.toString()); | |
9184 | } | |
9185 | ||
9186 | ||
9187 | /++ | |
9188 | Creates a $(LREF TimeOfDay) from a string with the format HHMMSS. | |
9189 | Whitespace is stripped from the given string. | |
9190 | ||
9191 | Params: | |
9192 | isoString = A string formatted in the ISO format for times. | |
9193 | ||
9194 | Throws: | |
9195 | $(REF DateTimeException,std,datetime,date) if the given string is | |
9196 | not in the ISO format or if the resulting $(LREF TimeOfDay) would | |
9197 | not be valid. | |
9198 | +/ | |
5fee5ec3 | 9199 | static TimeOfDay fromISOString(S)(scope const S isoString) @safe pure |
b4c522fa IB |
9200 | if (isSomeString!S) |
9201 | { | |
9202 | import std.conv : to, text, ConvException; | |
9203 | import std.exception : enforce; | |
9204 | import std.string : strip; | |
9205 | ||
9206 | int hours, minutes, seconds; | |
9207 | auto str = strip(isoString); | |
9208 | ||
9209 | enforce!DateTimeException(str.length == 6, text("Invalid ISO String: ", isoString)); | |
9210 | ||
9211 | try | |
9212 | { | |
9213 | // cast to int from uint is used because it checks for | |
9214 | // non digits without extra loops | |
9215 | hours = cast(int) to!uint(str[0 .. 2]); | |
9216 | minutes = cast(int) to!uint(str[2 .. 4]); | |
9217 | seconds = cast(int) to!uint(str[4 .. $]); | |
9218 | } | |
9219 | catch (ConvException) | |
9220 | { | |
9221 | throw new DateTimeException(text("Invalid ISO String: ", isoString)); | |
9222 | } | |
9223 | ||
9224 | return TimeOfDay(hours, minutes, seconds); | |
9225 | } | |
9226 | ||
9227 | /// | |
9228 | @safe unittest | |
9229 | { | |
9230 | assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); | |
9231 | assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); | |
9232 | assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); | |
9233 | } | |
9234 | ||
9235 | @safe unittest | |
9236 | { | |
9237 | assertThrown!DateTimeException(TimeOfDay.fromISOString("")); | |
9238 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0")); | |
9239 | assertThrown!DateTimeException(TimeOfDay.fromISOString("00")); | |
9240 | assertThrown!DateTimeException(TimeOfDay.fromISOString("000")); | |
9241 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0000")); | |
9242 | assertThrown!DateTimeException(TimeOfDay.fromISOString("00000")); | |
9243 | assertThrown!DateTimeException(TimeOfDay.fromISOString("13033")); | |
9244 | assertThrown!DateTimeException(TimeOfDay.fromISOString("1277")); | |
9245 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12707")); | |
9246 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12070")); | |
9247 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a")); | |
9248 | assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3")); | |
9249 | assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33")); | |
9250 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033")); | |
9251 | assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033")); | |
9252 | assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033")); | |
9253 | assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330")); | |
9254 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033")); | |
9255 | assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033")); | |
9256 | assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033")); | |
9257 | assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am")); | |
9258 | assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm")); | |
9259 | ||
9260 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0::")); | |
9261 | assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:")); | |
9262 | assertThrown!DateTimeException(TimeOfDay.fromISOString("::0")); | |
9263 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0")); | |
9264 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00")); | |
9265 | assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0")); | |
9266 | assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0")); | |
9267 | assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0")); | |
9268 | assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00")); | |
9269 | assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33")); | |
9270 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7")); | |
9271 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07")); | |
9272 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0")); | |
9273 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a")); | |
9274 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3")); | |
9275 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33")); | |
9276 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33")); | |
9277 | assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33")); | |
9278 | assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33")); | |
9279 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30")); | |
9280 | assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30")); | |
9281 | assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33")); | |
9282 | assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33")); | |
9283 | assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33")); | |
9284 | assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33")); | |
9285 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am")); | |
9286 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm")); | |
9287 | ||
9288 | assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33")); | |
9289 | ||
9290 | assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17)); | |
9291 | assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12)); | |
9292 | assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7)); | |
9293 | assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17)); | |
9294 | assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17)); | |
9295 | assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17)); | |
9296 | } | |
9297 | ||
5fee5ec3 | 9298 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
9299 | @safe unittest |
9300 | { | |
9301 | import std.conv : to; | |
9302 | import std.meta : AliasSeq; | |
5fee5ec3 | 9303 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 9304 | { |
5fee5ec3 | 9305 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
9306 | assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16)); |
9307 | } | |
9308 | } | |
9309 | ||
9310 | ||
9311 | /++ | |
9312 | Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS. | |
9313 | Whitespace is stripped from the given string. | |
9314 | ||
9315 | Params: | |
9316 | isoExtString = A string formatted in the ISO Extended format for | |
9317 | times. | |
9318 | ||
9319 | Throws: | |
9320 | $(REF DateTimeException,std,datetime,date) if the given string is | |
9321 | not in the ISO Extended format or if the resulting $(LREF TimeOfDay) | |
9322 | would not be valid. | |
9323 | +/ | |
5fee5ec3 | 9324 | static TimeOfDay fromISOExtString(S)(scope const S isoExtString) @safe pure |
b4c522fa IB |
9325 | if (isSomeString!S) |
9326 | { | |
5fee5ec3 | 9327 | import std.conv : ConvException, text, to; |
b4c522fa IB |
9328 | import std.string : strip; |
9329 | ||
5fee5ec3 IB |
9330 | auto str = strip(isoExtString); |
9331 | int hours, minutes, seconds; | |
b4c522fa | 9332 | |
5fee5ec3 IB |
9333 | if (str.length != 8 || str[2] != ':' || str[5] != ':') |
9334 | throw new DateTimeException(text("Invalid ISO Extended String: ", isoExtString)); | |
b4c522fa | 9335 | |
5fee5ec3 IB |
9336 | try |
9337 | { | |
9338 | // cast to int from uint is used because it checks for | |
9339 | // non digits without extra loops | |
9340 | hours = cast(int) to!uint(str[0 .. 2]); | |
9341 | minutes = cast(int) to!uint(str[3 .. 5]); | |
9342 | seconds = cast(int) to!uint(str[6 .. $]); | |
9343 | } | |
9344 | catch (ConvException) | |
9345 | { | |
9346 | throw new DateTimeException(text("Invalid ISO Extended String: ", isoExtString)); | |
9347 | } | |
b4c522fa | 9348 | |
5fee5ec3 | 9349 | return TimeOfDay(hours, minutes, seconds); |
b4c522fa IB |
9350 | } |
9351 | ||
9352 | /// | |
9353 | @safe unittest | |
9354 | { | |
9355 | assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); | |
9356 | assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); | |
9357 | assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); | |
9358 | } | |
9359 | ||
9360 | @safe unittest | |
9361 | { | |
9362 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("")); | |
9363 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0")); | |
9364 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00")); | |
9365 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000")); | |
9366 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000")); | |
9367 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000")); | |
9368 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033")); | |
9369 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277")); | |
9370 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707")); | |
9371 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070")); | |
9372 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a")); | |
9373 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3")); | |
9374 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33")); | |
9375 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033")); | |
9376 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033")); | |
9377 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033")); | |
9378 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330")); | |
9379 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033")); | |
9380 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033")); | |
9381 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033")); | |
9382 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am")); | |
9383 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm")); | |
9384 | ||
9385 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::")); | |
9386 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:")); | |
9387 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0")); | |
9388 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0")); | |
9389 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00")); | |
9390 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0")); | |
9391 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0")); | |
9392 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0")); | |
9393 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00")); | |
9394 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33")); | |
9395 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7")); | |
9396 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07")); | |
9397 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0")); | |
9398 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a")); | |
9399 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3")); | |
9400 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33")); | |
9401 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33")); | |
9402 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33")); | |
9403 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33")); | |
9404 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30")); | |
9405 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30")); | |
9406 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33")); | |
9407 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33")); | |
9408 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33")); | |
9409 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33")); | |
9410 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am")); | |
9411 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm")); | |
9412 | ||
9413 | assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033")); | |
9414 | ||
9415 | assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17)); | |
9416 | assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12)); | |
9417 | assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7)); | |
9418 | assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17)); | |
9419 | assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17)); | |
9420 | assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17)); | |
9421 | } | |
9422 | ||
5fee5ec3 | 9423 | // https://issues.dlang.org/show_bug.cgi?id=17801 |
b4c522fa IB |
9424 | @safe unittest |
9425 | { | |
9426 | import std.conv : to; | |
9427 | import std.meta : AliasSeq; | |
5fee5ec3 | 9428 | static foreach (C; AliasSeq!(char, wchar, dchar)) |
b4c522fa | 9429 | { |
5fee5ec3 | 9430 | static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) |
b4c522fa IB |
9431 | assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16)); |
9432 | } | |
9433 | } | |
9434 | ||
9435 | ||
9436 | /++ | |
9437 | Returns midnight. | |
9438 | +/ | |
9439 | @property static TimeOfDay min() @safe pure nothrow @nogc | |
9440 | { | |
9441 | return TimeOfDay.init; | |
9442 | } | |
9443 | ||
9444 | @safe unittest | |
9445 | { | |
9446 | assert(TimeOfDay.min.hour == 0); | |
9447 | assert(TimeOfDay.min.minute == 0); | |
9448 | assert(TimeOfDay.min.second == 0); | |
9449 | assert(TimeOfDay.min < TimeOfDay.max); | |
9450 | } | |
9451 | ||
9452 | ||
9453 | /++ | |
9454 | Returns one second short of midnight. | |
9455 | +/ | |
9456 | @property static TimeOfDay max() @safe pure nothrow @nogc | |
9457 | { | |
9458 | auto tod = TimeOfDay.init; | |
9459 | tod._hour = maxHour; | |
9460 | tod._minute = maxMinute; | |
9461 | tod._second = maxSecond; | |
9462 | ||
9463 | return tod; | |
9464 | } | |
9465 | ||
9466 | @safe unittest | |
9467 | { | |
9468 | assert(TimeOfDay.max.hour == 23); | |
9469 | assert(TimeOfDay.max.minute == 59); | |
9470 | assert(TimeOfDay.max.second == 59); | |
9471 | assert(TimeOfDay.max > TimeOfDay.min); | |
9472 | } | |
9473 | ||
9474 | ||
9475 | private: | |
9476 | ||
9477 | /+ | |
9478 | Add seconds to the time of day. Negative values will subtract. If the | |
9479 | number of seconds overflows (or underflows), then the seconds will wrap, | |
9480 | increasing (or decreasing) the number of minutes accordingly. If the | |
9481 | number of minutes overflows (or underflows), then the minutes will wrap. | |
9482 | If the number of minutes overflows(or underflows), then the hour will | |
9483 | wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30). | |
9484 | ||
9485 | Params: | |
9486 | seconds = The number of seconds to add to this TimeOfDay. | |
9487 | +/ | |
9488 | ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc | |
9489 | { | |
5fee5ec3 | 9490 | import core.time : convert; |
b4c522fa IB |
9491 | long hnsecs = convert!("seconds", "hnsecs")(seconds); |
9492 | hnsecs += convert!("hours", "hnsecs")(_hour); | |
9493 | hnsecs += convert!("minutes", "hnsecs")(_minute); | |
9494 | hnsecs += convert!("seconds", "hnsecs")(_second); | |
9495 | ||
9496 | hnsecs %= convert!("days", "hnsecs")(1); | |
9497 | ||
9498 | if (hnsecs < 0) | |
9499 | hnsecs += convert!("days", "hnsecs")(1); | |
9500 | ||
9501 | immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); | |
9502 | immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); | |
9503 | immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); | |
9504 | ||
9505 | _hour = cast(ubyte) newHours; | |
9506 | _minute = cast(ubyte) newMinutes; | |
9507 | _second = cast(ubyte) newSeconds; | |
9508 | ||
9509 | return this; | |
9510 | } | |
9511 | ||
9512 | @safe unittest | |
9513 | { | |
5fee5ec3 | 9514 | static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) |
b4c522fa IB |
9515 | { |
9516 | orig._addSeconds(seconds); | |
9517 | assert(orig == expected); | |
9518 | } | |
9519 | ||
9520 | testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); | |
9521 | testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); | |
9522 | testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); | |
9523 | testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); | |
9524 | testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); | |
9525 | testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); | |
9526 | testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); | |
9527 | testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); | |
9528 | testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); | |
9529 | testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0)); | |
9530 | testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3)); | |
9531 | testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32)); | |
9532 | testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33)); | |
9533 | testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34)); | |
9534 | ||
9535 | testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59)); | |
9536 | testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0)); | |
9537 | testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1)); | |
9538 | testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0)); | |
9539 | testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32)); | |
9540 | testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33)); | |
9541 | testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34)); | |
9542 | testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33)); | |
9543 | ||
9544 | testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); | |
9545 | testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); | |
9546 | testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); | |
9547 | testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); | |
9548 | testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); | |
9549 | testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); | |
9550 | testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); | |
9551 | testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); | |
9552 | testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59)); | |
9553 | testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58)); | |
9554 | testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34)); | |
9555 | testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33)); | |
9556 | testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32)); | |
9557 | ||
9558 | testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0)); | |
9559 | testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59)); | |
9560 | testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33)); | |
9561 | testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32)); | |
9562 | testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59)); | |
9563 | testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33)); | |
9564 | ||
9565 | testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); | |
9566 | testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); | |
9567 | testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59)); | |
9568 | ||
9569 | testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); | |
9570 | testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); | |
9571 | testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59)); | |
9572 | ||
9573 | testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); | |
9574 | testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); | |
9575 | testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59)); | |
9576 | ||
9577 | testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0)); | |
9578 | testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); | |
9579 | testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); | |
9580 | ||
9581 | const ctod = TimeOfDay(0, 0, 0); | |
9582 | immutable itod = TimeOfDay(0, 0, 0); | |
9583 | static assert(!__traits(compiles, ctod._addSeconds(7))); | |
9584 | static assert(!__traits(compiles, itod._addSeconds(7))); | |
9585 | } | |
9586 | ||
9587 | ||
9588 | /+ | |
9589 | Whether the given values form a valid $(LREF TimeOfDay). | |
9590 | +/ | |
9591 | static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc | |
9592 | { | |
9593 | return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second); | |
9594 | } | |
9595 | ||
9596 | ||
9597 | @safe pure invariant() | |
9598 | { | |
9599 | import std.format : format; | |
9600 | assert(_valid(_hour, _minute, _second), | |
9601 | format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second)); | |
9602 | } | |
9603 | ||
9604 | ||
9605 | package: | |
9606 | ||
9607 | ubyte _hour; | |
9608 | ubyte _minute; | |
9609 | ubyte _second; | |
9610 | ||
9611 | enum ubyte maxHour = 24 - 1; | |
9612 | enum ubyte maxMinute = 60 - 1; | |
9613 | enum ubyte maxSecond = 60 - 1; | |
9614 | } | |
9615 | ||
5fee5ec3 IB |
9616 | /// |
9617 | @safe pure unittest | |
9618 | { | |
9619 | import core.time : minutes, seconds; | |
9620 | ||
9621 | auto t = TimeOfDay(12, 30, 0); | |
9622 | ||
9623 | t += 10.minutes + 100.seconds; | |
9624 | assert(t == TimeOfDay(12, 41, 40)); | |
9625 | ||
9626 | assert(t.toISOExtString() == "12:41:40"); | |
9627 | assert(t.toISOString() == "124140"); | |
9628 | ||
9629 | assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0)); | |
9630 | assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0)); | |
9631 | } | |
b4c522fa IB |
9632 | |
9633 | /++ | |
9634 | Returns whether the given value is valid for the given unit type when in a | |
9635 | time point. Naturally, a duration is not held to a particular range, but | |
9636 | the values in a time point are (e.g. a month must be in the range of | |
9637 | 1 - 12 inclusive). | |
9638 | ||
9639 | Params: | |
9640 | units = The units of time to validate. | |
9641 | value = The number to validate. | |
9642 | +/ | |
9643 | bool valid(string units)(int value) @safe pure nothrow @nogc | |
9644 | if (units == "months" || | |
9645 | units == "hours" || | |
9646 | units == "minutes" || | |
9647 | units == "seconds") | |
9648 | { | |
9649 | static if (units == "months") | |
9650 | return value >= Month.jan && value <= Month.dec; | |
9651 | else static if (units == "hours") | |
9652 | return value >= 0 && value <= 23; | |
9653 | else static if (units == "minutes") | |
9654 | return value >= 0 && value <= 59; | |
9655 | else static if (units == "seconds") | |
9656 | return value >= 0 && value <= 59; | |
9657 | } | |
9658 | ||
9659 | /// | |
9660 | @safe unittest | |
9661 | { | |
9662 | assert(valid!"hours"(12)); | |
9663 | assert(!valid!"hours"(32)); | |
9664 | assert(valid!"months"(12)); | |
9665 | assert(!valid!"months"(13)); | |
9666 | } | |
9667 | ||
9668 | /++ | |
9669 | Returns whether the given day is valid for the given year and month. | |
9670 | ||
9671 | Params: | |
9672 | units = The units of time to validate. | |
9673 | year = The year of the day to validate. | |
9674 | month = The month of the day to validate (January is 1). | |
9675 | day = The day to validate. | |
9676 | +/ | |
9677 | bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc | |
9678 | if (units == "days") | |
9679 | { | |
9680 | return day > 0 && day <= maxDay(year, month); | |
9681 | } | |
9682 | ||
9683 | /// | |
9684 | @safe pure nothrow @nogc unittest | |
9685 | { | |
9686 | assert(valid!"days"(2016, 2, 29)); | |
9687 | assert(!valid!"days"(2016, 2, 30)); | |
9688 | assert(valid!"days"(2017, 2, 20)); | |
9689 | assert(!valid!"days"(2017, 2, 29)); | |
9690 | } | |
9691 | ||
9692 | ||
9693 | /++ | |
9694 | Params: | |
9695 | units = The units of time to validate. | |
9696 | value = The number to validate. | |
9697 | file = The file that the $(LREF DateTimeException) will list if thrown. | |
9698 | line = The line number that the $(LREF DateTimeException) will list if | |
9699 | thrown. | |
9700 | ||
9701 | Throws: | |
5fee5ec3 | 9702 | $(LREF DateTimeException) if `valid!units(value)` is false. |
b4c522fa IB |
9703 | +/ |
9704 | void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure | |
9705 | if (units == "months" || | |
9706 | units == "hours" || | |
9707 | units == "minutes" || | |
9708 | units == "seconds") | |
9709 | { | |
9710 | import std.format : format; | |
9711 | ||
9712 | static if (units == "months") | |
9713 | { | |
9714 | if (!valid!units(value)) | |
9715 | throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line); | |
9716 | } | |
9717 | else static if (units == "hours") | |
9718 | { | |
9719 | if (!valid!units(value)) | |
9720 | throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line); | |
9721 | } | |
9722 | else static if (units == "minutes") | |
9723 | { | |
9724 | if (!valid!units(value)) | |
9725 | throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line); | |
9726 | } | |
9727 | else static if (units == "seconds") | |
9728 | { | |
9729 | if (!valid!units(value)) | |
9730 | throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line); | |
9731 | } | |
9732 | } | |
9733 | ||
5fee5ec3 IB |
9734 | /// |
9735 | @safe pure unittest | |
9736 | { | |
9737 | import std.exception : assertThrown, assertNotThrown; | |
9738 | ||
9739 | assertNotThrown(enforceValid!"months"(10)); | |
9740 | assertNotThrown(enforceValid!"seconds"(40)); | |
9741 | ||
9742 | assertThrown!DateTimeException(enforceValid!"months"(0)); | |
9743 | assertThrown!DateTimeException(enforceValid!"hours"(24)); | |
9744 | assertThrown!DateTimeException(enforceValid!"minutes"(60)); | |
9745 | assertThrown!DateTimeException(enforceValid!"seconds"(60)); | |
9746 | } | |
9747 | ||
b4c522fa IB |
9748 | |
9749 | /++ | |
5fee5ec3 IB |
9750 | Because the validity of the day number depends on both on the year |
9751 | and month of which the day is occurring, take all three variables | |
9752 | to validate the day. | |
9753 | ||
b4c522fa IB |
9754 | Params: |
9755 | units = The units of time to validate. | |
9756 | year = The year of the day to validate. | |
9757 | month = The month of the day to validate. | |
9758 | day = The day to validate. | |
9759 | file = The file that the $(LREF DateTimeException) will list if thrown. | |
9760 | line = The line number that the $(LREF DateTimeException) will list if | |
9761 | thrown. | |
9762 | ||
9763 | Throws: | |
9764 | $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false. | |
9765 | +/ | |
9766 | void enforceValid(string units) | |
9767 | (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure | |
9768 | if (units == "days") | |
9769 | { | |
9770 | import std.format : format; | |
9771 | if (!valid!"days"(year, month, day)) | |
9772 | throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line); | |
9773 | } | |
9774 | ||
5fee5ec3 IB |
9775 | /// |
9776 | @safe pure unittest | |
9777 | { | |
9778 | import std.exception : assertThrown, assertNotThrown; | |
9779 | ||
9780 | assertNotThrown(enforceValid!"days"(2000, Month.jan, 1)); | |
9781 | // leap year | |
9782 | assertNotThrown(enforceValid!"days"(2000, Month.feb, 29)); | |
9783 | ||
9784 | assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29)); | |
9785 | assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32)); | |
9786 | assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31)); | |
9787 | } | |
9788 | ||
b4c522fa IB |
9789 | |
9790 | /++ | |
9791 | Returns the number of days from the current day of the week to the given | |
9792 | day of the week. If they are the same, then the result is 0. | |
9793 | ||
9794 | Params: | |
9795 | currDoW = The current day of the week. | |
9796 | dow = The day of the week to get the number of days to. | |
9797 | +/ | |
9798 | int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc | |
9799 | { | |
9800 | if (currDoW == dow) | |
9801 | return 0; | |
9802 | if (currDoW < dow) | |
9803 | return dow - currDoW; | |
9804 | return DayOfWeek.sat - currDoW + dow + 1; | |
9805 | } | |
9806 | ||
9807 | /// | |
9808 | @safe pure nothrow @nogc unittest | |
9809 | { | |
9810 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); | |
9811 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); | |
9812 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); | |
9813 | } | |
9814 | ||
9815 | @safe unittest | |
9816 | { | |
9817 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0); | |
9818 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1); | |
9819 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2); | |
9820 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3); | |
9821 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4); | |
9822 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5); | |
9823 | assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6); | |
9824 | ||
9825 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); | |
9826 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); | |
9827 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1); | |
9828 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); | |
9829 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3); | |
9830 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4); | |
9831 | assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5); | |
9832 | ||
9833 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5); | |
9834 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6); | |
9835 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0); | |
9836 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1); | |
9837 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2); | |
9838 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3); | |
9839 | assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4); | |
9840 | ||
9841 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4); | |
9842 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5); | |
9843 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6); | |
9844 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0); | |
9845 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1); | |
9846 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2); | |
9847 | assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3); | |
9848 | ||
9849 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3); | |
9850 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4); | |
9851 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5); | |
9852 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6); | |
9853 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0); | |
9854 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1); | |
9855 | assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2); | |
9856 | ||
9857 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2); | |
9858 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3); | |
9859 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4); | |
9860 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5); | |
9861 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6); | |
9862 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0); | |
9863 | assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1); | |
9864 | ||
9865 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1); | |
9866 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2); | |
9867 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3); | |
9868 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4); | |
9869 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5); | |
9870 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6); | |
9871 | assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0); | |
9872 | } | |
9873 | ||
9874 | ||
9875 | /++ | |
9876 | Returns the number of months from the current months of the year to the | |
9877 | given month of the year. If they are the same, then the result is 0. | |
9878 | ||
9879 | Params: | |
9880 | currMonth = The current month of the year. | |
9881 | month = The month of the year to get the number of months to. | |
9882 | +/ | |
9883 | int monthsToMonth(int currMonth, int month) @safe pure | |
9884 | { | |
9885 | enforceValid!"months"(currMonth); | |
9886 | enforceValid!"months"(month); | |
9887 | ||
9888 | if (currMonth == month) | |
9889 | return 0; | |
9890 | if (currMonth < month) | |
9891 | return month - currMonth; | |
9892 | return Month.dec - currMonth + month; | |
9893 | } | |
9894 | ||
9895 | /// | |
9896 | @safe pure unittest | |
9897 | { | |
9898 | assert(monthsToMonth(Month.jan, Month.jan) == 0); | |
9899 | assert(monthsToMonth(Month.jan, Month.dec) == 11); | |
9900 | assert(monthsToMonth(Month.jul, Month.oct) == 3); | |
9901 | } | |
9902 | ||
9903 | @safe unittest | |
9904 | { | |
9905 | assert(monthsToMonth(Month.jan, Month.jan) == 0); | |
9906 | assert(monthsToMonth(Month.jan, Month.feb) == 1); | |
9907 | assert(monthsToMonth(Month.jan, Month.mar) == 2); | |
9908 | assert(monthsToMonth(Month.jan, Month.apr) == 3); | |
9909 | assert(monthsToMonth(Month.jan, Month.may) == 4); | |
9910 | assert(monthsToMonth(Month.jan, Month.jun) == 5); | |
9911 | assert(monthsToMonth(Month.jan, Month.jul) == 6); | |
9912 | assert(monthsToMonth(Month.jan, Month.aug) == 7); | |
9913 | assert(monthsToMonth(Month.jan, Month.sep) == 8); | |
9914 | assert(monthsToMonth(Month.jan, Month.oct) == 9); | |
9915 | assert(monthsToMonth(Month.jan, Month.nov) == 10); | |
9916 | assert(monthsToMonth(Month.jan, Month.dec) == 11); | |
9917 | ||
9918 | assert(monthsToMonth(Month.may, Month.jan) == 8); | |
9919 | assert(monthsToMonth(Month.may, Month.feb) == 9); | |
9920 | assert(monthsToMonth(Month.may, Month.mar) == 10); | |
9921 | assert(monthsToMonth(Month.may, Month.apr) == 11); | |
9922 | assert(monthsToMonth(Month.may, Month.may) == 0); | |
9923 | assert(monthsToMonth(Month.may, Month.jun) == 1); | |
9924 | assert(monthsToMonth(Month.may, Month.jul) == 2); | |
9925 | assert(monthsToMonth(Month.may, Month.aug) == 3); | |
9926 | assert(monthsToMonth(Month.may, Month.sep) == 4); | |
9927 | assert(monthsToMonth(Month.may, Month.oct) == 5); | |
9928 | assert(monthsToMonth(Month.may, Month.nov) == 6); | |
9929 | assert(monthsToMonth(Month.may, Month.dec) == 7); | |
9930 | ||
9931 | assert(monthsToMonth(Month.oct, Month.jan) == 3); | |
9932 | assert(monthsToMonth(Month.oct, Month.feb) == 4); | |
9933 | assert(monthsToMonth(Month.oct, Month.mar) == 5); | |
9934 | assert(monthsToMonth(Month.oct, Month.apr) == 6); | |
9935 | assert(monthsToMonth(Month.oct, Month.may) == 7); | |
9936 | assert(monthsToMonth(Month.oct, Month.jun) == 8); | |
9937 | assert(monthsToMonth(Month.oct, Month.jul) == 9); | |
9938 | assert(monthsToMonth(Month.oct, Month.aug) == 10); | |
9939 | assert(monthsToMonth(Month.oct, Month.sep) == 11); | |
9940 | assert(monthsToMonth(Month.oct, Month.oct) == 0); | |
9941 | assert(monthsToMonth(Month.oct, Month.nov) == 1); | |
9942 | assert(monthsToMonth(Month.oct, Month.dec) == 2); | |
9943 | ||
9944 | assert(monthsToMonth(Month.dec, Month.jan) == 1); | |
9945 | assert(monthsToMonth(Month.dec, Month.feb) == 2); | |
9946 | assert(monthsToMonth(Month.dec, Month.mar) == 3); | |
9947 | assert(monthsToMonth(Month.dec, Month.apr) == 4); | |
9948 | assert(monthsToMonth(Month.dec, Month.may) == 5); | |
9949 | assert(monthsToMonth(Month.dec, Month.jun) == 6); | |
9950 | assert(monthsToMonth(Month.dec, Month.jul) == 7); | |
9951 | assert(monthsToMonth(Month.dec, Month.aug) == 8); | |
9952 | assert(monthsToMonth(Month.dec, Month.sep) == 9); | |
9953 | assert(monthsToMonth(Month.dec, Month.oct) == 10); | |
9954 | assert(monthsToMonth(Month.dec, Month.nov) == 11); | |
9955 | assert(monthsToMonth(Month.dec, Month.dec) == 0); | |
9956 | } | |
9957 | ||
9958 | ||
9959 | /++ | |
9960 | Whether the given Gregorian Year is a leap year. | |
9961 | ||
9962 | Params: | |
9963 | year = The year to to be tested. | |
9964 | +/ | |
9965 | bool yearIsLeapYear(int year) @safe pure nothrow @nogc | |
9966 | { | |
9967 | if (year % 400 == 0) | |
9968 | return true; | |
9969 | if (year % 100 == 0) | |
9970 | return false; | |
9971 | return year % 4 == 0; | |
9972 | } | |
9973 | ||
9974 | /// | |
9975 | @safe unittest | |
9976 | { | |
9977 | foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) | |
9978 | { | |
9979 | assert(!yearIsLeapYear(year)); | |
9980 | assert(!yearIsLeapYear(-year)); | |
9981 | } | |
9982 | ||
9983 | foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) | |
9984 | { | |
9985 | assert(yearIsLeapYear(year)); | |
9986 | assert(yearIsLeapYear(-year)); | |
9987 | } | |
9988 | } | |
9989 | ||
9990 | @safe unittest | |
9991 | { | |
9992 | import std.format : format; | |
9993 | foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999, | |
9994 | 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011]) | |
9995 | { | |
9996 | assert(!yearIsLeapYear(year), format("year: %s.", year)); | |
9997 | assert(!yearIsLeapYear(-year), format("year: %s.", year)); | |
9998 | } | |
9999 | ||
10000 | foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) | |
10001 | { | |
10002 | assert(yearIsLeapYear(year), format("year: %s.", year)); | |
10003 | assert(yearIsLeapYear(-year), format("year: %s.", year)); | |
10004 | } | |
10005 | } | |
10006 | ||
10007 | ||
10008 | /++ | |
10009 | Whether the given type defines all of the necessary functions for it to | |
10010 | function as a time point. | |
10011 | ||
5fee5ec3 IB |
10012 | 1. `T` must define a static property named `min` which is the smallest |
10013 | value of `T` as `Unqual!T`. | |
b4c522fa | 10014 | |
5fee5ec3 IB |
10015 | 2. `T` must define a static property named `max` which is the largest |
10016 | value of `T` as `Unqual!T`. | |
b4c522fa | 10017 | |
5fee5ec3 IB |
10018 | 3. `T` must define an `opBinary` for addition and subtraction that |
10019 | accepts $(REF Duration, core,time) and returns `Unqual!T`. | |
b4c522fa | 10020 | |
5fee5ec3 | 10021 | 4. `T` must define an `opOpAssign` for addition and subtraction that |
b4c522fa IB |
10022 | accepts $(REF Duration, core,time) and returns $(D ref Unqual!T). |
10023 | ||
5fee5ec3 IB |
10024 | 5. `T` must define a `opBinary` for subtraction which accepts `T` |
10025 | and returns $(REF Duration, core,time). | |
b4c522fa IB |
10026 | +/ |
10027 | template isTimePoint(T) | |
10028 | { | |
10029 | import core.time : Duration; | |
10030 | import std.traits : FunctionAttribute, functionAttributes, Unqual; | |
10031 | ||
10032 | enum isTimePoint = hasMin && | |
10033 | hasMax && | |
10034 | hasOverloadedOpBinaryWithDuration && | |
10035 | hasOverloadedOpAssignWithDuration && | |
10036 | hasOverloadedOpBinaryWithSelf && | |
10037 | !is(U == Duration); | |
10038 | ||
10039 | private: | |
10040 | ||
10041 | alias U = Unqual!T; | |
10042 | ||
10043 | enum hasMin = __traits(hasMember, T, "min") && | |
10044 | is(typeof(T.min) == U) && | |
10045 | is(typeof({static assert(__traits(isStaticFunction, T.min));})); | |
10046 | ||
10047 | enum hasMax = __traits(hasMember, T, "max") && | |
10048 | is(typeof(T.max) == U) && | |
10049 | is(typeof({static assert(__traits(isStaticFunction, T.max));})); | |
10050 | ||
10051 | enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) && | |
10052 | is(typeof(T.init - Duration.init) == U); | |
10053 | ||
10054 | enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) && | |
10055 | is(typeof(U.init -= Duration.init) == U) && | |
10056 | is(typeof( | |
10057 | { | |
9fa27ed0 IB |
10058 | alias add = U.opOpAssign!"+"; |
10059 | alias sub = U.opOpAssign!"-"; | |
b4c522fa IB |
10060 | alias FA = FunctionAttribute; |
10061 | static assert((functionAttributes!add & FA.ref_) != 0); | |
10062 | static assert((functionAttributes!sub & FA.ref_) != 0); | |
10063 | })); | |
10064 | ||
10065 | enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration); | |
10066 | } | |
10067 | ||
10068 | /// | |
10069 | @safe unittest | |
10070 | { | |
10071 | import core.time : Duration; | |
10072 | import std.datetime.interval : Interval; | |
10073 | import std.datetime.systime : SysTime; | |
10074 | ||
10075 | static assert(isTimePoint!Date); | |
10076 | static assert(isTimePoint!DateTime); | |
10077 | static assert(isTimePoint!SysTime); | |
10078 | static assert(isTimePoint!TimeOfDay); | |
10079 | ||
10080 | static assert(!isTimePoint!int); | |
10081 | static assert(!isTimePoint!Duration); | |
10082 | static assert(!isTimePoint!(Interval!SysTime)); | |
10083 | } | |
10084 | ||
10085 | @safe unittest | |
10086 | { | |
10087 | import core.time; | |
10088 | import std.datetime.interval; | |
10089 | import std.datetime.systime; | |
10090 | import std.meta : AliasSeq; | |
10091 | ||
5fee5ec3 | 10092 | static foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay)) |
b4c522fa IB |
10093 | { |
10094 | static assert(isTimePoint!(const TP), TP.stringof); | |
10095 | static assert(isTimePoint!(immutable TP), TP.stringof); | |
10096 | } | |
10097 | ||
5fee5ec3 | 10098 | static foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date)) |
b4c522fa IB |
10099 | static assert(!isTimePoint!T, T.stringof); |
10100 | } | |
10101 | ||
10102 | ||
10103 | /++ | |
10104 | Whether all of the given strings are valid units of time. | |
10105 | ||
5fee5ec3 | 10106 | `"nsecs"` is not considered a valid unit of time. Nothing in std.datetime |
b4c522fa IB |
10107 | can handle precision greater than hnsecs, and the few functions in core.time |
10108 | which deal with "nsecs" deal with it explicitly. | |
10109 | +/ | |
10110 | bool validTimeUnits(string[] units...) @safe pure nothrow @nogc | |
10111 | { | |
10112 | import std.algorithm.searching : canFind; | |
10113 | foreach (str; units) | |
10114 | { | |
10115 | if (!canFind(timeStrings[], str)) | |
10116 | return false; | |
10117 | } | |
10118 | return true; | |
10119 | } | |
10120 | ||
10121 | /// | |
10122 | @safe @nogc nothrow unittest | |
10123 | { | |
10124 | assert(validTimeUnits("msecs", "seconds", "minutes")); | |
10125 | assert(validTimeUnits("days", "weeks", "months")); | |
10126 | assert(!validTimeUnits("ms", "seconds", "minutes")); | |
10127 | } | |
10128 | ||
10129 | ||
10130 | /++ | |
5fee5ec3 IB |
10131 | Compares two time unit strings. `"years"` are the largest units and |
10132 | `"hnsecs"` are the smallest. | |
b4c522fa IB |
10133 | |
10134 | Returns: | |
10135 | $(BOOKTABLE, | |
10136 | $(TR $(TD this < rhs) $(TD < 0)) | |
10137 | $(TR $(TD this == rhs) $(TD 0)) | |
10138 | $(TR $(TD this > rhs) $(TD > 0)) | |
10139 | ) | |
10140 | ||
10141 | Throws: | |
10142 | $(LREF DateTimeException) if either of the given strings is not a valid | |
10143 | time unit string. | |
10144 | +/ | |
10145 | int cmpTimeUnits(string lhs, string rhs) @safe pure | |
10146 | { | |
10147 | import std.algorithm.searching : countUntil; | |
10148 | import std.exception : enforce; | |
10149 | import std.format : format; | |
10150 | ||
5fee5ec3 IB |
10151 | immutable indexOfLHS = countUntil(timeStrings, lhs); |
10152 | immutable indexOfRHS = countUntil(timeStrings, rhs); | |
b4c522fa | 10153 | |
5fee5ec3 IB |
10154 | enforce!DateTimeException(indexOfLHS != -1, format("%s is not a valid TimeString", lhs)); |
10155 | enforce!DateTimeException(indexOfRHS != -1, format("%s is not a valid TimeString", rhs)); | |
b4c522fa IB |
10156 | |
10157 | if (indexOfLHS < indexOfRHS) | |
10158 | return -1; | |
10159 | if (indexOfLHS > indexOfRHS) | |
10160 | return 1; | |
10161 | ||
10162 | return 0; | |
10163 | } | |
10164 | ||
10165 | /// | |
10166 | @safe pure unittest | |
10167 | { | |
5fee5ec3 IB |
10168 | import std.exception : assertThrown; |
10169 | ||
b4c522fa IB |
10170 | assert(cmpTimeUnits("hours", "hours") == 0); |
10171 | assert(cmpTimeUnits("hours", "weeks") < 0); | |
10172 | assert(cmpTimeUnits("months", "seconds") > 0); | |
5fee5ec3 IB |
10173 | |
10174 | assertThrown!DateTimeException(cmpTimeUnits("month", "second")); | |
b4c522fa IB |
10175 | } |
10176 | ||
10177 | @safe unittest | |
10178 | { | |
10179 | foreach (i, outerUnits; timeStrings) | |
10180 | { | |
10181 | assert(cmpTimeUnits(outerUnits, outerUnits) == 0); | |
10182 | ||
10183 | // For some reason, $ won't compile. | |
10184 | foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length]) | |
10185 | assert(cmpTimeUnits(outerUnits, innerUnits) == -1); | |
10186 | } | |
10187 | ||
10188 | foreach (i, outerUnits; timeStrings) | |
10189 | { | |
10190 | foreach (innerUnits; timeStrings[0 .. i]) | |
10191 | assert(cmpTimeUnits(outerUnits, innerUnits) == 1); | |
10192 | } | |
10193 | } | |
10194 | ||
10195 | ||
10196 | /++ | |
5fee5ec3 IB |
10197 | Compares two time unit strings at compile time. `"years"` are the largest |
10198 | units and `"hnsecs"` are the smallest. | |
b4c522fa | 10199 | |
5fee5ec3 IB |
10200 | This template is used instead of `cmpTimeUnits` because exceptions |
10201 | can't be thrown at compile time and `cmpTimeUnits` must enforce that | |
b4c522fa IB |
10202 | the strings it's given are valid time unit strings. This template uses a |
10203 | template constraint instead. | |
10204 | ||
10205 | Returns: | |
10206 | $(BOOKTABLE, | |
10207 | $(TR $(TD this < rhs) $(TD < 0)) | |
10208 | $(TR $(TD this == rhs) $(TD 0)) | |
10209 | $(TR $(TD this > rhs) $(TD > 0)) | |
10210 | ) | |
10211 | +/ | |
10212 | template CmpTimeUnits(string lhs, string rhs) | |
10213 | if (validTimeUnits(lhs, rhs)) | |
10214 | { | |
10215 | enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs); | |
10216 | } | |
10217 | ||
5fee5ec3 IB |
10218 | /// |
10219 | @safe pure unittest | |
10220 | { | |
10221 | static assert(CmpTimeUnits!("years", "weeks") > 0); | |
10222 | static assert(CmpTimeUnits!("days", "days") == 0); | |
10223 | static assert(CmpTimeUnits!("seconds", "hours") < 0); | |
10224 | } | |
b4c522fa IB |
10225 | |
10226 | // Helper function for CmpTimeUnits. | |
10227 | private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc | |
10228 | { | |
10229 | import std.algorithm.searching : countUntil; | |
10230 | auto tstrings = timeStrings; | |
10231 | immutable indexOfLHS = countUntil(tstrings, lhs); | |
10232 | immutable indexOfRHS = countUntil(tstrings, rhs); | |
10233 | ||
10234 | if (indexOfLHS < indexOfRHS) | |
10235 | return -1; | |
10236 | if (indexOfLHS > indexOfRHS) | |
10237 | return 1; | |
10238 | ||
10239 | return 0; | |
10240 | } | |
10241 | ||
10242 | @safe unittest | |
10243 | { | |
5fee5ec3 | 10244 | static foreach (i; 0 .. timeStrings.length) |
b4c522fa | 10245 | { |
5fee5ec3 | 10246 | static assert(CmpTimeUnits!(timeStrings[i], timeStrings[i]) == 0); |
b4c522fa | 10247 | |
5fee5ec3 IB |
10248 | static foreach (next; timeStrings[i + 1 .. $]) |
10249 | static assert(CmpTimeUnits!(timeStrings[i], next) == -1); | |
b4c522fa | 10250 | |
5fee5ec3 IB |
10251 | static foreach (prev; timeStrings[0 .. i]) |
10252 | static assert(CmpTimeUnits!(timeStrings[i], prev) == 1); | |
b4c522fa | 10253 | } |
b4c522fa IB |
10254 | } |
10255 | ||
10256 | ||
10257 | package: | |
10258 | ||
10259 | ||
10260 | /+ | |
10261 | Array of the short (three letter) names of each month. | |
10262 | +/ | |
10263 | immutable string[12] _monthNames = ["Jan", | |
10264 | "Feb", | |
10265 | "Mar", | |
10266 | "Apr", | |
10267 | "May", | |
10268 | "Jun", | |
10269 | "Jul", | |
10270 | "Aug", | |
10271 | "Sep", | |
10272 | "Oct", | |
10273 | "Nov", | |
10274 | "Dec"]; | |
10275 | ||
10276 | /+ | |
10277 | The maximum valid Day in the given month in the given year. | |
10278 | ||
10279 | Params: | |
10280 | year = The year to get the day for. | |
10281 | month = The month of the Gregorian Calendar to get the day for. | |
10282 | +/ | |
10283 | ubyte maxDay(int year, int month) @safe pure nothrow @nogc | |
10284 | in | |
10285 | { | |
10286 | assert(valid!"months"(month)); | |
10287 | } | |
5fee5ec3 | 10288 | do |
b4c522fa IB |
10289 | { |
10290 | switch (month) | |
10291 | { | |
10292 | case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec: | |
10293 | return 31; | |
10294 | case Month.feb: | |
10295 | return yearIsLeapYear(year) ? 29 : 28; | |
10296 | case Month.apr, Month.jun, Month.sep, Month.nov: | |
10297 | return 30; | |
10298 | default: | |
10299 | assert(0, "Invalid month."); | |
10300 | } | |
10301 | } | |
10302 | ||
10303 | @safe unittest | |
10304 | { | |
10305 | // Test A.D. | |
10306 | assert(maxDay(1999, 1) == 31); | |
10307 | assert(maxDay(1999, 2) == 28); | |
10308 | assert(maxDay(1999, 3) == 31); | |
10309 | assert(maxDay(1999, 4) == 30); | |
10310 | assert(maxDay(1999, 5) == 31); | |
10311 | assert(maxDay(1999, 6) == 30); | |
10312 | assert(maxDay(1999, 7) == 31); | |
10313 | assert(maxDay(1999, 8) == 31); | |
10314 | assert(maxDay(1999, 9) == 30); | |
10315 | assert(maxDay(1999, 10) == 31); | |
10316 | assert(maxDay(1999, 11) == 30); | |
10317 | assert(maxDay(1999, 12) == 31); | |
10318 | ||
10319 | assert(maxDay(2000, 1) == 31); | |
10320 | assert(maxDay(2000, 2) == 29); | |
10321 | assert(maxDay(2000, 3) == 31); | |
10322 | assert(maxDay(2000, 4) == 30); | |
10323 | assert(maxDay(2000, 5) == 31); | |
10324 | assert(maxDay(2000, 6) == 30); | |
10325 | assert(maxDay(2000, 7) == 31); | |
10326 | assert(maxDay(2000, 8) == 31); | |
10327 | assert(maxDay(2000, 9) == 30); | |
10328 | assert(maxDay(2000, 10) == 31); | |
10329 | assert(maxDay(2000, 11) == 30); | |
10330 | assert(maxDay(2000, 12) == 31); | |
10331 | ||
10332 | // Test B.C. | |
10333 | assert(maxDay(-1999, 1) == 31); | |
10334 | assert(maxDay(-1999, 2) == 28); | |
10335 | assert(maxDay(-1999, 3) == 31); | |
10336 | assert(maxDay(-1999, 4) == 30); | |
10337 | assert(maxDay(-1999, 5) == 31); | |
10338 | assert(maxDay(-1999, 6) == 30); | |
10339 | assert(maxDay(-1999, 7) == 31); | |
10340 | assert(maxDay(-1999, 8) == 31); | |
10341 | assert(maxDay(-1999, 9) == 30); | |
10342 | assert(maxDay(-1999, 10) == 31); | |
10343 | assert(maxDay(-1999, 11) == 30); | |
10344 | assert(maxDay(-1999, 12) == 31); | |
10345 | ||
10346 | assert(maxDay(-2000, 1) == 31); | |
10347 | assert(maxDay(-2000, 2) == 29); | |
10348 | assert(maxDay(-2000, 3) == 31); | |
10349 | assert(maxDay(-2000, 4) == 30); | |
10350 | assert(maxDay(-2000, 5) == 31); | |
10351 | assert(maxDay(-2000, 6) == 30); | |
10352 | assert(maxDay(-2000, 7) == 31); | |
10353 | assert(maxDay(-2000, 8) == 31); | |
10354 | assert(maxDay(-2000, 9) == 30); | |
10355 | assert(maxDay(-2000, 10) == 31); | |
10356 | assert(maxDay(-2000, 11) == 30); | |
10357 | assert(maxDay(-2000, 12) == 31); | |
10358 | } | |
10359 | ||
10360 | /+ | |
10361 | Splits out a particular unit from hnsecs and gives the value for that | |
10362 | unit and the remaining hnsecs. It really shouldn't be used unless unless | |
10363 | all units larger than the given units have already been split out. | |
10364 | ||
10365 | Params: | |
10366 | units = The units to split out. | |
10367 | hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left | |
10368 | after splitting out the given units. | |
10369 | ||
10370 | Returns: | |
10371 | The number of the given units from converting hnsecs to those units. | |
10372 | +/ | |
10373 | long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc | |
10374 | if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) | |
10375 | { | |
10376 | import core.time : convert; | |
10377 | immutable value = convert!("hnsecs", units)(hnsecs); | |
10378 | hnsecs -= convert!(units, "hnsecs")(value); | |
10379 | return value; | |
10380 | } | |
10381 | ||
10382 | @safe unittest | |
10383 | { | |
10384 | auto hnsecs = 2595000000007L; | |
10385 | immutable days = splitUnitsFromHNSecs!"days"(hnsecs); | |
10386 | assert(days == 3); | |
10387 | assert(hnsecs == 3000000007); | |
10388 | ||
10389 | immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); | |
10390 | assert(minutes == 5); | |
10391 | assert(hnsecs == 7); | |
10392 | } | |
10393 | ||
10394 | ||
10395 | /+ | |
10396 | Returns the day of the week for the given day of the Gregorian Calendar. | |
10397 | ||
10398 | Params: | |
10399 | day = The day of the Gregorian Calendar for which to get the day of | |
10400 | the week. | |
10401 | +/ | |
10402 | DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc | |
10403 | { | |
10404 | // January 1st, 1 A.D. was a Monday | |
10405 | if (day >= 0) | |
10406 | return cast(DayOfWeek)(day % 7); | |
10407 | else | |
10408 | { | |
10409 | immutable dow = cast(DayOfWeek)((day % 7) + 7); | |
10410 | ||
10411 | if (dow == 7) | |
10412 | return DayOfWeek.sun; | |
10413 | else | |
10414 | return dow; | |
10415 | } | |
10416 | } | |
10417 | ||
10418 | @safe unittest | |
10419 | { | |
10420 | import std.datetime.systime : SysTime; | |
10421 | ||
10422 | // Test A.D. | |
10423 | assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon); | |
10424 | assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue); | |
10425 | assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed); | |
10426 | assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu); | |
10427 | assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri); | |
10428 | assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat); | |
10429 | assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun); | |
10430 | assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon); | |
10431 | assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue); | |
10432 | assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue); | |
10433 | assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed); | |
10434 | assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu); | |
10435 | assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); | |
10436 | assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); | |
10437 | assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun); | |
10438 | assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon); | |
10439 | assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue); | |
10440 | assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed); | |
10441 | assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu); | |
10442 | assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri); | |
10443 | assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat); | |
10444 | assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun); | |
10445 | ||
10446 | // Test B.C. | |
10447 | assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun); | |
10448 | assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat); | |
10449 | assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri); | |
10450 | assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu); | |
10451 | assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed); | |
10452 | assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue); | |
10453 | assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon); | |
10454 | assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun); | |
10455 | assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat); | |
10456 | } | |
10457 | ||
10458 | ||
10459 | private: | |
10460 | ||
10461 | enum daysInYear = 365; // The number of days in a non-leap year. | |
10462 | enum daysInLeapYear = 366; // The numbef or days in a leap year. | |
10463 | enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years. | |
10464 | enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years. | |
10465 | enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years. | |
10466 | ||
10467 | /+ | |
10468 | Array of integers representing the last days of each month in a year. | |
10469 | +/ | |
10470 | immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; | |
10471 | ||
10472 | /+ | |
10473 | Array of integers representing the last days of each month in a leap year. | |
10474 | +/ | |
10475 | immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; | |
10476 | ||
10477 | ||
10478 | /+ | |
10479 | Returns the string representation of the given month. | |
10480 | +/ | |
10481 | string monthToString(Month month) @safe pure | |
10482 | { | |
10483 | import std.format : format; | |
10484 | assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month)); | |
10485 | return _monthNames[month - Month.jan]; | |
10486 | } | |
10487 | ||
10488 | @safe unittest | |
10489 | { | |
10490 | assert(monthToString(Month.jan) == "Jan"); | |
10491 | assert(monthToString(Month.feb) == "Feb"); | |
10492 | assert(monthToString(Month.mar) == "Mar"); | |
10493 | assert(monthToString(Month.apr) == "Apr"); | |
10494 | assert(monthToString(Month.may) == "May"); | |
10495 | assert(monthToString(Month.jun) == "Jun"); | |
10496 | assert(monthToString(Month.jul) == "Jul"); | |
10497 | assert(monthToString(Month.aug) == "Aug"); | |
10498 | assert(monthToString(Month.sep) == "Sep"); | |
10499 | assert(monthToString(Month.oct) == "Oct"); | |
10500 | assert(monthToString(Month.nov) == "Nov"); | |
10501 | assert(monthToString(Month.dec) == "Dec"); | |
10502 | } | |
10503 | ||
10504 | ||
10505 | /+ | |
10506 | Returns the Month corresponding to the given string. | |
10507 | ||
10508 | Params: | |
10509 | monthStr = The string representation of the month to get the Month for. | |
10510 | ||
10511 | Throws: | |
10512 | $(REF DateTimeException,std,datetime,date) if the given month is not a | |
10513 | valid month string. | |
10514 | +/ | |
5fee5ec3 IB |
10515 | Month monthFromString(T)(T monthStr) @safe pure |
10516 | if (isSomeString!T) | |
b4c522fa IB |
10517 | { |
10518 | import std.format : format; | |
10519 | switch (monthStr) | |
10520 | { | |
10521 | case "Jan": | |
10522 | return Month.jan; | |
10523 | case "Feb": | |
10524 | return Month.feb; | |
10525 | case "Mar": | |
10526 | return Month.mar; | |
10527 | case "Apr": | |
10528 | return Month.apr; | |
10529 | case "May": | |
10530 | return Month.may; | |
10531 | case "Jun": | |
10532 | return Month.jun; | |
10533 | case "Jul": | |
10534 | return Month.jul; | |
10535 | case "Aug": | |
10536 | return Month.aug; | |
10537 | case "Sep": | |
10538 | return Month.sep; | |
10539 | case "Oct": | |
10540 | return Month.oct; | |
10541 | case "Nov": | |
10542 | return Month.nov; | |
10543 | case "Dec": | |
10544 | return Month.dec; | |
10545 | default: | |
5fee5ec3 | 10546 | throw new DateTimeException(format!"Invalid month %s"(monthStr)); |
b4c522fa IB |
10547 | } |
10548 | } | |
10549 | ||
10550 | @safe unittest | |
10551 | { | |
5fee5ec3 | 10552 | import std.conv : to; |
b4c522fa IB |
10553 | import std.traits : EnumMembers; |
10554 | foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY", | |
10555 | "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"]) | |
10556 | { | |
5fee5ec3 | 10557 | assertThrown!DateTimeException(monthFromString(badStr), badStr); |
b4c522fa IB |
10558 | } |
10559 | ||
10560 | foreach (month; EnumMembers!Month) | |
10561 | { | |
5fee5ec3 | 10562 | assert(monthFromString(monthToString(month)) == month, month.to!string); |
b4c522fa IB |
10563 | } |
10564 | } | |
10565 | ||
10566 | ||
5fee5ec3 IB |
10567 | // NOTE: all the non-simple array literals are wrapped in functions, because |
10568 | // otherwise importing causes re-evaluation of the static initializers using | |
10569 | // CTFE with unittests enabled | |
10570 | version (StdUnittest) | |
b4c522fa | 10571 | { |
5fee5ec3 | 10572 | private @safe: |
b4c522fa IB |
10573 | // All of these helper arrays are sorted in ascending order. |
10574 | auto testYearsBC = [-1999, -1200, -600, -4, -1, 0]; | |
10575 | auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012]; | |
10576 | ||
10577 | // I'd use a Tuple, but I get forward reference errors if I try. | |
10578 | struct MonthDay | |
10579 | { | |
10580 | Month month; | |
10581 | short day; | |
10582 | ||
10583 | this(int m, short d) | |
10584 | { | |
10585 | month = cast(Month) m; | |
10586 | day = d; | |
10587 | } | |
10588 | } | |
10589 | ||
5fee5ec3 IB |
10590 | MonthDay[] testMonthDays() |
10591 | { | |
10592 | static MonthDay[] result = [MonthDay(1, 1), | |
b4c522fa IB |
10593 | MonthDay(1, 2), |
10594 | MonthDay(3, 17), | |
10595 | MonthDay(7, 4), | |
10596 | MonthDay(10, 27), | |
10597 | MonthDay(12, 30), | |
10598 | MonthDay(12, 31)]; | |
5fee5ec3 IB |
10599 | return result; |
10600 | } | |
b4c522fa IB |
10601 | |
10602 | auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31]; | |
10603 | ||
5fee5ec3 IB |
10604 | TimeOfDay[] testTODs() |
10605 | { | |
10606 | static result = [TimeOfDay(0, 0, 0), | |
b4c522fa IB |
10607 | TimeOfDay(0, 0, 1), |
10608 | TimeOfDay(0, 1, 0), | |
10609 | TimeOfDay(1, 0, 0), | |
10610 | TimeOfDay(13, 13, 13), | |
10611 | TimeOfDay(23, 59, 59)]; | |
5fee5ec3 IB |
10612 | return result; |
10613 | } | |
b4c522fa IB |
10614 | |
10615 | auto testHours = [0, 1, 12, 22, 23]; | |
10616 | auto testMinSecs = [0, 1, 30, 58, 59]; | |
10617 | ||
10618 | // Throwing exceptions is incredibly expensive, so we want to use a smaller | |
10619 | // set of values for tests using assertThrown. | |
5fee5ec3 IB |
10620 | TimeOfDay[] testTODsThrown() |
10621 | { | |
10622 | static result = [TimeOfDay(0, 0, 0), | |
b4c522fa IB |
10623 | TimeOfDay(13, 13, 13), |
10624 | TimeOfDay(23, 59, 59)]; | |
5fee5ec3 IB |
10625 | return result; |
10626 | } | |
b4c522fa IB |
10627 | |
10628 | Date[] testDatesBC; | |
10629 | Date[] testDatesAD; | |
10630 | ||
10631 | DateTime[] testDateTimesBC; | |
10632 | DateTime[] testDateTimesAD; | |
10633 | ||
10634 | // I'd use a Tuple, but I get forward reference errors if I try. | |
10635 | struct GregDay { int day; Date date; } | |
5fee5ec3 IB |
10636 | GregDay[] testGregDaysBC() |
10637 | { | |
10638 | static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar | |
b4c522fa IB |
10639 | GregDay(-735_233, Date(-2012, 1, 1)), |
10640 | GregDay(-735_202, Date(-2012, 2, 1)), | |
10641 | GregDay(-735_175, Date(-2012, 2, 28)), | |
10642 | GregDay(-735_174, Date(-2012, 2, 29)), | |
10643 | GregDay(-735_173, Date(-2012, 3, 1)), | |
10644 | GregDay(-734_502, Date(-2010, 1, 1)), | |
10645 | GregDay(-734_472, Date(-2010, 1, 31)), | |
10646 | GregDay(-734_471, Date(-2010, 2, 1)), | |
10647 | GregDay(-734_444, Date(-2010, 2, 28)), | |
10648 | GregDay(-734_443, Date(-2010, 3, 1)), | |
10649 | GregDay(-734_413, Date(-2010, 3, 31)), | |
10650 | GregDay(-734_412, Date(-2010, 4, 1)), | |
10651 | GregDay(-734_383, Date(-2010, 4, 30)), | |
10652 | GregDay(-734_382, Date(-2010, 5, 1)), | |
10653 | GregDay(-734_352, Date(-2010, 5, 31)), | |
10654 | GregDay(-734_351, Date(-2010, 6, 1)), | |
10655 | GregDay(-734_322, Date(-2010, 6, 30)), | |
10656 | GregDay(-734_321, Date(-2010, 7, 1)), | |
10657 | GregDay(-734_291, Date(-2010, 7, 31)), | |
10658 | GregDay(-734_290, Date(-2010, 8, 1)), | |
10659 | GregDay(-734_260, Date(-2010, 8, 31)), | |
10660 | GregDay(-734_259, Date(-2010, 9, 1)), | |
10661 | GregDay(-734_230, Date(-2010, 9, 30)), | |
10662 | GregDay(-734_229, Date(-2010, 10, 1)), | |
10663 | GregDay(-734_199, Date(-2010, 10, 31)), | |
10664 | GregDay(-734_198, Date(-2010, 11, 1)), | |
10665 | GregDay(-734_169, Date(-2010, 11, 30)), | |
10666 | GregDay(-734_168, Date(-2010, 12, 1)), | |
10667 | GregDay(-734_139, Date(-2010, 12, 30)), | |
10668 | GregDay(-734_138, Date(-2010, 12, 31)), | |
10669 | GregDay(-731_215, Date(-2001, 1, 1)), | |
10670 | GregDay(-730_850, Date(-2000, 1, 1)), | |
10671 | GregDay(-730_849, Date(-2000, 1, 2)), | |
10672 | GregDay(-730_486, Date(-2000, 12, 30)), | |
10673 | GregDay(-730_485, Date(-2000, 12, 31)), | |
10674 | GregDay(-730_484, Date(-1999, 1, 1)), | |
10675 | GregDay(-694_690, Date(-1901, 1, 1)), | |
10676 | GregDay(-694_325, Date(-1900, 1, 1)), | |
10677 | GregDay(-585_118, Date(-1601, 1, 1)), | |
10678 | GregDay(-584_753, Date(-1600, 1, 1)), | |
10679 | GregDay(-584_388, Date(-1600, 12, 31)), | |
10680 | GregDay(-584_387, Date(-1599, 1, 1)), | |
10681 | GregDay(-365_972, Date(-1001, 1, 1)), | |
10682 | GregDay(-365_607, Date(-1000, 1, 1)), | |
10683 | GregDay(-183_351, Date(-501, 1, 1)), | |
10684 | GregDay(-182_986, Date(-500, 1, 1)), | |
10685 | GregDay(-182_621, Date(-499, 1, 1)), | |
10686 | GregDay(-146_827, Date(-401, 1, 1)), | |
10687 | GregDay(-146_462, Date(-400, 1, 1)), | |
10688 | GregDay(-146_097, Date(-400, 12, 31)), | |
10689 | GregDay(-110_302, Date(-301, 1, 1)), | |
10690 | GregDay(-109_937, Date(-300, 1, 1)), | |
10691 | GregDay(-73_778, Date(-201, 1, 1)), | |
10692 | GregDay(-73_413, Date(-200, 1, 1)), | |
10693 | GregDay(-38_715, Date(-105, 1, 1)), | |
10694 | GregDay(-37_254, Date(-101, 1, 1)), | |
10695 | GregDay(-36_889, Date(-100, 1, 1)), | |
10696 | GregDay(-36_524, Date(-99, 1, 1)), | |
10697 | GregDay(-36_160, Date(-99, 12, 31)), | |
10698 | GregDay(-35_794, Date(-97, 1, 1)), | |
10699 | GregDay(-18_627, Date(-50, 1, 1)), | |
10700 | GregDay(-18_262, Date(-49, 1, 1)), | |
10701 | GregDay(-3652, Date(-9, 1, 1)), | |
10702 | GregDay(-2191, Date(-5, 1, 1)), | |
10703 | GregDay(-1827, Date(-5, 12, 31)), | |
10704 | GregDay(-1826, Date(-4, 1, 1)), | |
10705 | GregDay(-1825, Date(-4, 1, 2)), | |
10706 | GregDay(-1462, Date(-4, 12, 30)), | |
10707 | GregDay(-1461, Date(-4, 12, 31)), | |
10708 | GregDay(-1460, Date(-3, 1, 1)), | |
10709 | GregDay(-1096, Date(-3, 12, 31)), | |
10710 | GregDay(-1095, Date(-2, 1, 1)), | |
10711 | GregDay(-731, Date(-2, 12, 31)), | |
10712 | GregDay(-730, Date(-1, 1, 1)), | |
10713 | GregDay(-367, Date(-1, 12, 30)), | |
10714 | GregDay(-366, Date(-1, 12, 31)), | |
10715 | GregDay(-365, Date(0, 1, 1)), | |
10716 | GregDay(-31, Date(0, 11, 30)), | |
10717 | GregDay(-30, Date(0, 12, 1)), | |
10718 | GregDay(-1, Date(0, 12, 30)), | |
10719 | GregDay(0, Date(0, 12, 31))]; | |
5fee5ec3 IB |
10720 | return result; |
10721 | } | |
b4c522fa | 10722 | |
5fee5ec3 IB |
10723 | GregDay[] testGregDaysAD() |
10724 | { | |
10725 | static result = [GregDay(1, Date(1, 1, 1)), | |
b4c522fa IB |
10726 | GregDay(2, Date(1, 1, 2)), |
10727 | GregDay(32, Date(1, 2, 1)), | |
10728 | GregDay(365, Date(1, 12, 31)), | |
10729 | GregDay(366, Date(2, 1, 1)), | |
10730 | GregDay(731, Date(3, 1, 1)), | |
10731 | GregDay(1096, Date(4, 1, 1)), | |
10732 | GregDay(1097, Date(4, 1, 2)), | |
10733 | GregDay(1460, Date(4, 12, 30)), | |
10734 | GregDay(1461, Date(4, 12, 31)), | |
10735 | GregDay(1462, Date(5, 1, 1)), | |
10736 | GregDay(17_898, Date(50, 1, 1)), | |
10737 | GregDay(35_065, Date(97, 1, 1)), | |
10738 | GregDay(36_160, Date(100, 1, 1)), | |
10739 | GregDay(36_525, Date(101, 1, 1)), | |
10740 | GregDay(37_986, Date(105, 1, 1)), | |
10741 | GregDay(72_684, Date(200, 1, 1)), | |
10742 | GregDay(73_049, Date(201, 1, 1)), | |
10743 | GregDay(109_208, Date(300, 1, 1)), | |
10744 | GregDay(109_573, Date(301, 1, 1)), | |
10745 | GregDay(145_732, Date(400, 1, 1)), | |
10746 | GregDay(146_098, Date(401, 1, 1)), | |
10747 | GregDay(182_257, Date(500, 1, 1)), | |
10748 | GregDay(182_622, Date(501, 1, 1)), | |
10749 | GregDay(364_878, Date(1000, 1, 1)), | |
10750 | GregDay(365_243, Date(1001, 1, 1)), | |
10751 | GregDay(584_023, Date(1600, 1, 1)), | |
10752 | GregDay(584_389, Date(1601, 1, 1)), | |
10753 | GregDay(693_596, Date(1900, 1, 1)), | |
10754 | GregDay(693_961, Date(1901, 1, 1)), | |
10755 | GregDay(729_755, Date(1999, 1, 1)), | |
10756 | GregDay(730_120, Date(2000, 1, 1)), | |
10757 | GregDay(730_121, Date(2000, 1, 2)), | |
10758 | GregDay(730_484, Date(2000, 12, 30)), | |
10759 | GregDay(730_485, Date(2000, 12, 31)), | |
10760 | GregDay(730_486, Date(2001, 1, 1)), | |
10761 | GregDay(733_773, Date(2010, 1, 1)), | |
10762 | GregDay(733_774, Date(2010, 1, 2)), | |
10763 | GregDay(733_803, Date(2010, 1, 31)), | |
10764 | GregDay(733_804, Date(2010, 2, 1)), | |
10765 | GregDay(733_831, Date(2010, 2, 28)), | |
10766 | GregDay(733_832, Date(2010, 3, 1)), | |
10767 | GregDay(733_862, Date(2010, 3, 31)), | |
10768 | GregDay(733_863, Date(2010, 4, 1)), | |
10769 | GregDay(733_892, Date(2010, 4, 30)), | |
10770 | GregDay(733_893, Date(2010, 5, 1)), | |
10771 | GregDay(733_923, Date(2010, 5, 31)), | |
10772 | GregDay(733_924, Date(2010, 6, 1)), | |
10773 | GregDay(733_953, Date(2010, 6, 30)), | |
10774 | GregDay(733_954, Date(2010, 7, 1)), | |
10775 | GregDay(733_984, Date(2010, 7, 31)), | |
10776 | GregDay(733_985, Date(2010, 8, 1)), | |
10777 | GregDay(734_015, Date(2010, 8, 31)), | |
10778 | GregDay(734_016, Date(2010, 9, 1)), | |
10779 | GregDay(734_045, Date(2010, 9, 30)), | |
10780 | GregDay(734_046, Date(2010, 10, 1)), | |
10781 | GregDay(734_076, Date(2010, 10, 31)), | |
10782 | GregDay(734_077, Date(2010, 11, 1)), | |
10783 | GregDay(734_106, Date(2010, 11, 30)), | |
10784 | GregDay(734_107, Date(2010, 12, 1)), | |
10785 | GregDay(734_136, Date(2010, 12, 30)), | |
10786 | GregDay(734_137, Date(2010, 12, 31)), | |
10787 | GregDay(734_503, Date(2012, 1, 1)), | |
10788 | GregDay(734_534, Date(2012, 2, 1)), | |
10789 | GregDay(734_561, Date(2012, 2, 28)), | |
10790 | GregDay(734_562, Date(2012, 2, 29)), | |
10791 | GregDay(734_563, Date(2012, 3, 1)), | |
10792 | GregDay(734_858, Date(2012, 12, 21))]; | |
5fee5ec3 IB |
10793 | return result; |
10794 | } | |
b4c522fa IB |
10795 | |
10796 | // I'd use a Tuple, but I get forward reference errors if I try. | |
10797 | struct DayOfYear { int day; MonthDay md; } | |
5fee5ec3 IB |
10798 | DayOfYear[] testDaysOfYear() |
10799 | { | |
10800 | static result = [DayOfYear(1, MonthDay(1, 1)), | |
b4c522fa IB |
10801 | DayOfYear(2, MonthDay(1, 2)), |
10802 | DayOfYear(3, MonthDay(1, 3)), | |
10803 | DayOfYear(31, MonthDay(1, 31)), | |
10804 | DayOfYear(32, MonthDay(2, 1)), | |
10805 | DayOfYear(59, MonthDay(2, 28)), | |
10806 | DayOfYear(60, MonthDay(3, 1)), | |
10807 | DayOfYear(90, MonthDay(3, 31)), | |
10808 | DayOfYear(91, MonthDay(4, 1)), | |
10809 | DayOfYear(120, MonthDay(4, 30)), | |
10810 | DayOfYear(121, MonthDay(5, 1)), | |
10811 | DayOfYear(151, MonthDay(5, 31)), | |
10812 | DayOfYear(152, MonthDay(6, 1)), | |
10813 | DayOfYear(181, MonthDay(6, 30)), | |
10814 | DayOfYear(182, MonthDay(7, 1)), | |
10815 | DayOfYear(212, MonthDay(7, 31)), | |
10816 | DayOfYear(213, MonthDay(8, 1)), | |
10817 | DayOfYear(243, MonthDay(8, 31)), | |
10818 | DayOfYear(244, MonthDay(9, 1)), | |
10819 | DayOfYear(273, MonthDay(9, 30)), | |
10820 | DayOfYear(274, MonthDay(10, 1)), | |
10821 | DayOfYear(304, MonthDay(10, 31)), | |
10822 | DayOfYear(305, MonthDay(11, 1)), | |
10823 | DayOfYear(334, MonthDay(11, 30)), | |
10824 | DayOfYear(335, MonthDay(12, 1)), | |
10825 | DayOfYear(363, MonthDay(12, 29)), | |
10826 | DayOfYear(364, MonthDay(12, 30)), | |
10827 | DayOfYear(365, MonthDay(12, 31))]; | |
5fee5ec3 IB |
10828 | return result; |
10829 | } | |
b4c522fa | 10830 | |
5fee5ec3 IB |
10831 | DayOfYear[] testDaysOfLeapYear() |
10832 | { | |
10833 | static result = [DayOfYear(1, MonthDay(1, 1)), | |
b4c522fa IB |
10834 | DayOfYear(2, MonthDay(1, 2)), |
10835 | DayOfYear(3, MonthDay(1, 3)), | |
10836 | DayOfYear(31, MonthDay(1, 31)), | |
10837 | DayOfYear(32, MonthDay(2, 1)), | |
10838 | DayOfYear(59, MonthDay(2, 28)), | |
10839 | DayOfYear(60, MonthDay(2, 29)), | |
10840 | DayOfYear(61, MonthDay(3, 1)), | |
10841 | DayOfYear(91, MonthDay(3, 31)), | |
10842 | DayOfYear(92, MonthDay(4, 1)), | |
10843 | DayOfYear(121, MonthDay(4, 30)), | |
10844 | DayOfYear(122, MonthDay(5, 1)), | |
10845 | DayOfYear(152, MonthDay(5, 31)), | |
10846 | DayOfYear(153, MonthDay(6, 1)), | |
10847 | DayOfYear(182, MonthDay(6, 30)), | |
10848 | DayOfYear(183, MonthDay(7, 1)), | |
10849 | DayOfYear(213, MonthDay(7, 31)), | |
10850 | DayOfYear(214, MonthDay(8, 1)), | |
10851 | DayOfYear(244, MonthDay(8, 31)), | |
10852 | DayOfYear(245, MonthDay(9, 1)), | |
10853 | DayOfYear(274, MonthDay(9, 30)), | |
10854 | DayOfYear(275, MonthDay(10, 1)), | |
10855 | DayOfYear(305, MonthDay(10, 31)), | |
10856 | DayOfYear(306, MonthDay(11, 1)), | |
10857 | DayOfYear(335, MonthDay(11, 30)), | |
10858 | DayOfYear(336, MonthDay(12, 1)), | |
10859 | DayOfYear(364, MonthDay(12, 29)), | |
10860 | DayOfYear(365, MonthDay(12, 30)), | |
10861 | DayOfYear(366, MonthDay(12, 31))]; | |
5fee5ec3 IB |
10862 | return result; |
10863 | } | |
b4c522fa | 10864 | |
5fee5ec3 | 10865 | void initializeTests() |
b4c522fa IB |
10866 | { |
10867 | foreach (year; testYearsBC) | |
10868 | { | |
10869 | foreach (md; testMonthDays) | |
10870 | testDatesBC ~= Date(year, md.month, md.day); | |
10871 | } | |
10872 | ||
10873 | foreach (year; testYearsAD) | |
10874 | { | |
10875 | foreach (md; testMonthDays) | |
10876 | testDatesAD ~= Date(year, md.month, md.day); | |
10877 | } | |
10878 | ||
10879 | foreach (dt; testDatesBC) | |
10880 | { | |
10881 | foreach (tod; testTODs) | |
10882 | testDateTimesBC ~= DateTime(dt, tod); | |
10883 | } | |
10884 | ||
10885 | foreach (dt; testDatesAD) | |
10886 | { | |
10887 | foreach (tod; testTODs) | |
10888 | testDateTimesAD ~= DateTime(dt, tod); | |
10889 | } | |
10890 | } | |
10891 | } |