1 // Written in the D programming language 2 /++ 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 38 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 39 Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) 40 Source: $(PHOBOSSRC std/datetime/date.d) 41 +/ 42 module std.datetime.date; 43 44 import core.time : TimeException; 45 import std.traits : isSomeString, Unqual; 46 import std.typecons : Flag; 47 import std.range.primitives : isOutputRange; 48 49 version (StdUnittest) import std.exception : assertThrown; 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 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 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 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 } 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 125 If set to `AllowDayOverflow.no`, then day overflow is not allowed. 126 127 Otherwise, if set to `AllowDayOverflow.yes`, then day overflow is 128 allowed. 129 +/ 130 alias AllowDayOverflow = Flag!"allowDayOverflow"; 131 132 133 /++ 134 Array of the strings representing time units, starting with the smallest 135 unit and going to the largest. It does not include `"nsecs"`. 136 137 Includes `"hnsecs"` (hecto-nanoseconds (100 ns)), 138 `"usecs"` (microseconds), `"msecs"` (milliseconds), `"seconds"`, 139 `"minutes"`, `"hours"`, `"days"`, `"weeks"`, `"months"`, and 140 `"years"` 141 +/ 142 immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes", 143 "hours", "days", "weeks", "months", "years"]; 144 145 146 /++ 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. 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 +/ 166 this(Date date, TimeOfDay tod = TimeOfDay.init) @safe pure nothrow @nogc 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 /++ 226 Compares this $(LREF DateTime) with the given `DateTime.`. 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 +/ 235 int opCmp(DateTime rhs) const @safe pure nothrow @nogc 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 +/ 475 @property void date(Date date) @safe pure nothrow @nogc 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 +/ 528 @property void timeOfDay(TimeOfDay tod) @safe pure nothrow @nogc 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 { 595 static void testDT(DateTime dt, int year, DateTime expected, size_t line = __LINE__) 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: 622 $(REF DateTimeException,std,datetime,date) if `isAD` is true. 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 { 639 assertThrown!DateTimeException((DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1)))); 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 { 737 static void testDT(DateTime dt, Month month, DateTime expected = DateTime.init, size_t line = __LINE__) 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 /++ 1055 Adds the given number of years or months to this $(LREF DateTime), 1056 mutating it. A negative number will subtract. 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. 1072 1073 Returns: 1074 A reference to the `DateTime` (`this`). 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 /++ 1120 Adds the given number of years or months to this $(LREF DateTime), 1121 mutating it. A negative number will subtract. 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. 1137 1138 Returns: 1139 A reference to the `DateTime` (`this`). 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 /++ 1193 Adds the given number of units to this $(LREF DateTime), mutating it. A 1194 negative number will subtract. 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 1200 Accepted units are `"days"`, `"minutes"`, `"hours"`, 1201 `"minutes"`, and `"seconds"`. 1202 1203 Params: 1204 units = The units to add. 1205 value = The number of $(D_PARAM units) to add to this 1206 $(LREF DateTime). 1207 1208 Returns: 1209 A reference to the `DateTime` (`this`). 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 1251 /// ditto 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 { 1264 static void testDT(DateTime orig, int hours, DateTime expected, size_t line = __LINE__) 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 { 1567 static void testDT(DateTime orig, int minutes, DateTime expected, size_t line = __LINE__) 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 { 1867 static void testDT(DateTime orig, int seconds, DateTime expected, size_t line = __LINE__) 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 2123 import core.time : Duration; 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 $(TR $(TD Duration) $(TD +) $(TD DateTime) $(TD -->) $(TD DateTime)) 2135 ) 2136 2137 Params: 2138 duration = The $(REF Duration, core,time) to add to or subtract from 2139 this $(LREF DateTime). 2140 +/ 2141 DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 2142 if (op == "+" || op == "-") 2143 { 2144 DateTime retval = this; 2145 immutable seconds = duration.total!"seconds"; 2146 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 2147 } 2148 2149 /// ditto 2150 DateTime opBinaryRight(string op)(Duration duration) const @safe pure nothrow @nogc 2151 if (op == "+") 2152 { 2153 return this + duration; 2154 } 2155 2156 2157 /// 2158 @safe unittest 2159 { 2160 import core.time : hours, seconds; 2161 2162 assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == 2163 DateTime(2016, 1, 1, 0, 0, 0)); 2164 2165 assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == 2166 DateTime(2016, 1, 1, 0, 59, 59)); 2167 2168 assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == 2169 DateTime(2015, 12, 31, 23, 59, 59)); 2170 2171 assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == 2172 DateTime(2015, 12, 31, 23, 59, 59)); 2173 2174 assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == 2175 hours(1) + DateTime(2015, 12, 31, 23, 59, 59)); 2176 } 2177 2178 @safe unittest 2179 { 2180 import core.time : dur; 2181 2182 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2183 2184 assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2185 assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2186 assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2187 assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2188 2189 assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2190 assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2191 assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2192 assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2193 assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2194 assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2195 assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2196 assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2197 assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2198 assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2199 assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2200 assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2201 2202 assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2203 assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2204 assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2205 assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2206 2207 assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2208 assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2209 assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2210 assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2211 assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2212 assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2213 assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2214 assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2215 assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2216 assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2217 assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2218 assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2219 2220 auto duration = dur!"seconds"(12); 2221 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2222 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2223 assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2224 assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2225 assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2226 assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2227 } 2228 2229 2230 /++ 2231 Gives the result of adding or subtracting a duration from this 2232 $(LREF DateTime), as well as assigning the result to this 2233 $(LREF DateTime). 2234 2235 The legal types of arithmetic for $(LREF DateTime) using this operator 2236 are 2237 2238 $(BOOKTABLE, 2239 $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime)) 2240 $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime)) 2241 ) 2242 2243 Params: 2244 duration = The duration to add to or subtract from this 2245 $(LREF DateTime). 2246 +/ 2247 ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 2248 if (op == "+" || op == "-") 2249 { 2250 import core.time : convert; 2251 import std.format : format; 2252 2253 DateTime retval = this; 2254 immutable hnsecs = duration.total!"hnsecs"; 2255 2256 mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op)); 2257 } 2258 2259 @safe unittest 2260 { 2261 import core.time : dur; 2262 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == 2263 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2264 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == 2265 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2266 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == 2267 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2268 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == 2269 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2270 2271 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == 2272 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2273 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == 2274 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2275 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == 2276 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2277 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == 2278 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2279 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == 2280 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2281 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == 2282 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2283 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == 2284 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2285 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == 2286 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2287 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == 2288 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2289 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == 2290 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2291 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == 2292 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == 2294 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2295 2296 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == 2297 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2298 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == 2299 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2300 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == 2301 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2302 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == 2303 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2304 2305 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == 2306 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2307 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == 2308 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2309 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == 2310 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2311 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == 2312 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2313 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == 2314 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2315 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == 2316 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2317 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == 2318 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2319 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == 2320 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2321 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == 2322 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2323 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == 2324 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2325 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == 2326 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2327 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == 2328 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2329 2330 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 2331 (dt += dur!"seconds"(92)) -= dur!"days"(-500); 2332 assert(dt == DateTime(2001, 6, 14, 9, 8, 38)); 2333 2334 auto duration = dur!"seconds"(12); 2335 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2336 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2337 static assert(!__traits(compiles, cdt += duration)); 2338 static assert(!__traits(compiles, idt += duration)); 2339 static assert(!__traits(compiles, cdt -= duration)); 2340 static assert(!__traits(compiles, idt -= duration)); 2341 } 2342 2343 2344 /++ 2345 Gives the difference between two $(LREF DateTime)s. 2346 2347 The legal types of arithmetic for $(LREF DateTime) using this operator are 2348 2349 $(BOOKTABLE, 2350 $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration)) 2351 ) 2352 +/ 2353 Duration opBinary(string op)(DateTime rhs) const @safe pure nothrow @nogc 2354 if (op == "-") 2355 { 2356 immutable dateResult = _date - rhs.date; 2357 immutable todResult = _tod - rhs._tod; 2358 2359 import core.time : dur; 2360 return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs"); 2361 } 2362 2363 @safe unittest 2364 { 2365 auto dt = DateTime(1999, 7, 6, 12, 30, 33); 2366 2367 import core.time : dur; 2368 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) == 2369 dur!"seconds"(31_536_000)); 2370 assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2371 dur!"seconds"(-31_536_000)); 2372 2373 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2374 dur!"seconds"(26_78_400)); 2375 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) == 2376 dur!"seconds"(-26_78_400)); 2377 2378 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) == 2379 dur!"seconds"(86_400)); 2380 assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2381 dur!"seconds"(-86_400)); 2382 2383 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) == 2384 dur!"seconds"(3600)); 2385 assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2386 dur!"seconds"(-3600)); 2387 2388 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2389 dur!"seconds"(60)); 2390 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) == 2391 dur!"seconds"(-60)); 2392 2393 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2394 dur!"seconds"(1)); 2395 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) == 2396 dur!"seconds"(-1)); 2397 2398 assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033)); 2399 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033)); 2400 assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367)); 2401 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367)); 2402 2403 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2404 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2405 assert(dt - dt == Duration.zero); 2406 assert(cdt - dt == Duration.zero); 2407 assert(idt - dt == Duration.zero); 2408 2409 assert(dt - cdt == Duration.zero); 2410 assert(cdt - cdt == Duration.zero); 2411 assert(idt - cdt == Duration.zero); 2412 2413 assert(dt - idt == Duration.zero); 2414 assert(cdt - idt == Duration.zero); 2415 assert(idt - idt == Duration.zero); 2416 } 2417 2418 2419 /++ 2420 Returns the difference between the two $(LREF DateTime)s in months. 2421 2422 To get the difference in years, subtract the year property 2423 of two $(LREF DateTime)s. To get the difference in days or weeks, 2424 subtract the $(LREF DateTime)s themselves and use the 2425 $(REF Duration, core,time) that results. Because converting between 2426 months and smaller units requires a specific date (which 2427 $(REF Duration, core,time)s don't have), getting the difference in 2428 months requires some math using both the year and month properties, so 2429 this is a convenience function for getting the difference in months. 2430 2431 Note that the number of days in the months or how far into the month 2432 either date is is irrelevant. It is the difference in the month property 2433 combined with the difference in years * 12. So, for instance, 2434 December 31st and January 1st are one month apart just as December 1st 2435 and January 31st are one month apart. 2436 2437 Params: 2438 rhs = The $(LREF DateTime) to subtract from this one. 2439 +/ 2440 int diffMonths(DateTime rhs) const @safe pure nothrow @nogc 2441 { 2442 return _date.diffMonths(rhs._date); 2443 } 2444 2445 /// 2446 @safe unittest 2447 { 2448 assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( 2449 DateTime(1999, 1, 31, 23, 59, 59)) == 1); 2450 2451 assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( 2452 DateTime(1999, 2, 1, 12, 3, 42)) == -1); 2453 2454 assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( 2455 DateTime(1999, 1, 1, 2, 4, 7)) == 2); 2456 2457 assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( 2458 DateTime(1999, 3, 31, 0, 30, 58)) == -2); 2459 } 2460 2461 @safe unittest 2462 { 2463 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2464 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2465 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2466 assert(dt.diffMonths(dt) == 0); 2467 assert(cdt.diffMonths(dt) == 0); 2468 assert(idt.diffMonths(dt) == 0); 2469 2470 assert(dt.diffMonths(cdt) == 0); 2471 assert(cdt.diffMonths(cdt) == 0); 2472 assert(idt.diffMonths(cdt) == 0); 2473 2474 assert(dt.diffMonths(idt) == 0); 2475 assert(cdt.diffMonths(idt) == 0); 2476 assert(idt.diffMonths(idt) == 0); 2477 } 2478 2479 2480 /++ 2481 Whether this $(LREF DateTime) is in a leap year. 2482 +/ 2483 @property bool isLeapYear() const @safe pure nothrow @nogc 2484 { 2485 return _date.isLeapYear; 2486 } 2487 2488 @safe unittest 2489 { 2490 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2491 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2492 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2493 assert(!dt.isLeapYear); 2494 assert(!cdt.isLeapYear); 2495 assert(!idt.isLeapYear); 2496 } 2497 2498 2499 /++ 2500 Day of the week this $(LREF DateTime) is on. 2501 +/ 2502 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 2503 { 2504 return _date.dayOfWeek; 2505 } 2506 2507 @safe unittest 2508 { 2509 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2510 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2511 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2512 assert(dt.dayOfWeek == DayOfWeek.tue); 2513 assert(cdt.dayOfWeek == DayOfWeek.tue); 2514 assert(idt.dayOfWeek == DayOfWeek.tue); 2515 } 2516 2517 2518 /++ 2519 Day of the year this $(LREF DateTime) is on. 2520 +/ 2521 @property ushort dayOfYear() const @safe pure nothrow @nogc 2522 { 2523 return _date.dayOfYear; 2524 } 2525 2526 /// 2527 @safe unittest 2528 { 2529 assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); 2530 assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); 2531 assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); 2532 } 2533 2534 @safe unittest 2535 { 2536 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2537 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2538 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2539 assert(dt.dayOfYear == 187); 2540 assert(cdt.dayOfYear == 187); 2541 assert(idt.dayOfYear == 187); 2542 } 2543 2544 2545 /++ 2546 Day of the year. 2547 2548 Params: 2549 day = The day of the year to set which day of the year this 2550 $(LREF DateTime) is on. 2551 +/ 2552 @property void dayOfYear(int day) @safe pure 2553 { 2554 _date.dayOfYear = day; 2555 } 2556 2557 @safe unittest 2558 { 2559 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2560 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2561 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2562 dt.dayOfYear = 12; 2563 assert(dt.dayOfYear == 12); 2564 static assert(!__traits(compiles, cdt.dayOfYear = 12)); 2565 static assert(!__traits(compiles, idt.dayOfYear = 12)); 2566 } 2567 2568 2569 /++ 2570 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2571 +/ 2572 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 2573 { 2574 return _date.dayOfGregorianCal; 2575 } 2576 2577 /// 2578 @safe unittest 2579 { 2580 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); 2581 assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); 2582 assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); 2583 2584 assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); 2585 assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); 2586 assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); 2587 2588 assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); 2589 assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); 2590 } 2591 2592 @safe unittest 2593 { 2594 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2595 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2596 assert(cdt.dayOfGregorianCal == 729_941); 2597 assert(idt.dayOfGregorianCal == 729_941); 2598 } 2599 2600 2601 /++ 2602 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2603 Setting this property does not affect the time portion of 2604 $(LREF DateTime). 2605 2606 Params: 2607 days = The day of the Gregorian Calendar to set this $(LREF DateTime) 2608 to. 2609 +/ 2610 @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc 2611 { 2612 _date.dayOfGregorianCal = days; 2613 } 2614 2615 /// 2616 @safe unittest 2617 { 2618 auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); 2619 dt.dayOfGregorianCal = 1; 2620 assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); 2621 2622 dt.dayOfGregorianCal = 365; 2623 assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); 2624 2625 dt.dayOfGregorianCal = 366; 2626 assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); 2627 2628 dt.dayOfGregorianCal = 0; 2629 assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); 2630 2631 dt.dayOfGregorianCal = -365; 2632 assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); 2633 2634 dt.dayOfGregorianCal = -366; 2635 assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); 2636 2637 dt.dayOfGregorianCal = 730_120; 2638 assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); 2639 2640 dt.dayOfGregorianCal = 734_137; 2641 assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); 2642 } 2643 2644 @safe unittest 2645 { 2646 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2647 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2648 static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7)); 2649 static assert(!__traits(compiles, idt.dayOfGregorianCal = 7)); 2650 } 2651 2652 2653 /++ 2654 The ISO 8601 week of the year that this $(LREF DateTime) is in. 2655 2656 See_Also: 2657 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 2658 +/ 2659 @property ubyte isoWeek() const @safe pure nothrow 2660 { 2661 return _date.isoWeek; 2662 } 2663 2664 @safe unittest 2665 { 2666 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2667 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2668 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2669 assert(dt.isoWeek == 27); 2670 assert(cdt.isoWeek == 27); 2671 assert(idt.isoWeek == 27); 2672 } 2673 2674 2675 /++ 2676 The year of the ISO 8601 week calendar that this $(LREF DateTime) is in. 2677 2678 See_Also: 2679 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 2680 +/ 2681 @property short isoWeekYear() const @safe pure nothrow 2682 { 2683 return _date.isoWeekYear; 2684 } 2685 2686 2687 /++ 2688 $(LREF DateTime) for the last day in the month that this 2689 $(LREF DateTime) is in. The time portion of endOfMonth is always 2690 23:59:59. 2691 +/ 2692 @property DateTime endOfMonth() const @safe pure nothrow 2693 { 2694 try 2695 return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59)); 2696 catch (Exception e) 2697 assert(0, "DateTime constructor threw."); 2698 } 2699 2700 /// 2701 @safe unittest 2702 { 2703 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == 2704 DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); 2705 2706 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == 2707 DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); 2708 2709 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == 2710 DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); 2711 2712 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == 2713 DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); 2714 } 2715 2716 @safe unittest 2717 { 2718 // Test A.D. 2719 assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59)); 2720 assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59)); 2721 assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59)); 2722 assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59)); 2723 assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59)); 2724 assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59)); 2725 assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59)); 2726 assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2727 assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59)); 2728 assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59)); 2729 assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59)); 2730 assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59)); 2731 assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59)); 2732 2733 // Test B.C. 2734 assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59)); 2735 assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59)); 2736 assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59)); 2737 assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59)); 2738 assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59)); 2739 assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59)); 2740 assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59)); 2741 assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59)); 2742 assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59)); 2743 assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59)); 2744 assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59)); 2745 assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59)); 2746 assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59)); 2747 2748 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2749 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2750 assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2751 assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2752 } 2753 2754 2755 /++ 2756 The last day in the month that this $(LREF DateTime) is in. 2757 +/ 2758 @property ubyte daysInMonth() const @safe pure nothrow @nogc 2759 { 2760 return _date.daysInMonth; 2761 } 2762 2763 /// 2764 @safe unittest 2765 { 2766 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); 2767 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); 2768 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); 2769 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); 2770 } 2771 2772 @safe unittest 2773 { 2774 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2775 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2776 assert(cdt.daysInMonth == 31); 2777 assert(idt.daysInMonth == 31); 2778 } 2779 2780 2781 /++ 2782 Whether the current year is a date in A.D. 2783 +/ 2784 @property bool isAD() const @safe pure nothrow @nogc 2785 { 2786 return _date.isAD; 2787 } 2788 2789 /// 2790 @safe unittest 2791 { 2792 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); 2793 assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); 2794 assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); 2795 assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); 2796 } 2797 2798 @safe unittest 2799 { 2800 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2801 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2802 assert(cdt.isAD); 2803 assert(idt.isAD); 2804 } 2805 2806 2807 /++ 2808 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 2809 $(LREF DateTime) at the given time. For example, prior to noon, 2810 1996-03-31 would be the Julian day number 2_450_173, so this function 2811 returns 2_450_173, while from noon onward, the julian day number would 2812 be 2_450_174, so this function returns 2_450_174. 2813 +/ 2814 @property long julianDay() const @safe pure nothrow @nogc 2815 { 2816 if (_tod._hour < 12) 2817 return _date.julianDay - 1; 2818 else 2819 return _date.julianDay; 2820 } 2821 2822 @safe unittest 2823 { 2824 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1); 2825 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0); 2826 2827 assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424); 2828 assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425); 2829 2830 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425); 2831 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426); 2832 2833 assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160); 2834 assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161); 2835 2836 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000); 2837 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001); 2838 2839 assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973); 2840 assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974); 2841 2842 assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173); 2843 assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174); 2844 2845 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432); 2846 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433); 2847 2848 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2849 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2850 assert(cdt.julianDay == 2_451_366); 2851 assert(idt.julianDay == 2_451_366); 2852 } 2853 2854 2855 /++ 2856 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any 2857 time on this date (since, the modified Julian day changes at midnight). 2858 +/ 2859 @property long modJulianDay() const @safe pure nothrow @nogc 2860 { 2861 return _date.modJulianDay; 2862 } 2863 2864 @safe unittest 2865 { 2866 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0); 2867 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0); 2868 2869 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432); 2870 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432); 2871 2872 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2873 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2874 assert(cdt.modJulianDay == 51_365); 2875 assert(idt.modJulianDay == 51_365); 2876 } 2877 2878 2879 /++ 2880 Converts this $(LREF DateTime) to a string with the format `YYYYMMDDTHHMMSS`. 2881 If `writer` is set, the resulting string will be written directly to it. 2882 2883 Params: 2884 writer = A `char` accepting 2885 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 2886 Returns: 2887 A `string` when not using an output range; `void` otherwise. 2888 +/ 2889 string toISOString() const @safe pure nothrow 2890 { 2891 import std.array : appender; 2892 auto w = appender!string(); 2893 w.reserve(18); 2894 try 2895 toISOString(w); 2896 catch (Exception e) 2897 assert(0, "toISOString() threw."); 2898 return w.data; 2899 } 2900 2901 /// ditto 2902 void toISOString(W)(ref W writer) const 2903 if (isOutputRange!(W, char)) 2904 { 2905 import std.format.write : formattedWrite; 2906 _date.toISOString(writer); 2907 formattedWrite!("T%02d%02d%02d")( 2908 writer, 2909 _tod._hour, 2910 _tod._minute, 2911 _tod._second 2912 ); 2913 } 2914 2915 /// 2916 @safe unittest 2917 { 2918 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == 2919 "20100704T070612"); 2920 2921 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == 2922 "19981225T021500"); 2923 2924 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == 2925 "00000105T230959"); 2926 2927 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == 2928 "-00040105T000002"); 2929 } 2930 2931 @safe unittest 2932 { 2933 // Test A.D. 2934 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000"); 2935 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612"); 2936 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459"); 2937 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959"); 2938 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101"); 2939 2940 // Test B.C. 2941 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204"); 2942 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000"); 2943 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612"); 2944 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459"); 2945 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959"); 2946 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101"); 2947 2948 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2949 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2950 assert(cdt.toISOString() == "19990706T123033"); 2951 assert(idt.toISOString() == "19990706T123033"); 2952 } 2953 2954 2955 /++ 2956 Converts this $(LREF DateTime) to a string with the format 2957 `YYYY-MM-DDTHH:MM:SS`. If `writer` is set, the resulting 2958 string will be written directly to it. 2959 2960 Params: 2961 writer = A `char` accepting 2962 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 2963 Returns: 2964 A `string` when not using an output range; `void` otherwise. 2965 +/ 2966 string toISOExtString() const @safe pure nothrow 2967 { 2968 import std.array : appender; 2969 auto w = appender!string(); 2970 w.reserve(20); 2971 try 2972 toISOExtString(w); 2973 catch (Exception e) 2974 assert(0, "toISOExtString() threw."); 2975 return w.data; 2976 } 2977 2978 /// ditto 2979 void toISOExtString(W)(ref W writer) const 2980 if (isOutputRange!(W, char)) 2981 { 2982 import std.format.write : formattedWrite; 2983 _date.toISOExtString(writer); 2984 formattedWrite!("T%02d:%02d:%02d")( 2985 writer, 2986 _tod._hour, 2987 _tod._minute, 2988 _tod._second 2989 ); 2990 } 2991 2992 /// 2993 @safe unittest 2994 { 2995 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == 2996 "2010-07-04T07:06:12"); 2997 2998 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == 2999 "1998-12-25T02:15:00"); 3000 3001 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == 3002 "0000-01-05T23:09:59"); 3003 3004 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == 3005 "-0004-01-05T00:00:02"); 3006 } 3007 3008 @safe unittest 3009 { 3010 // Test A.D. 3011 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); 3012 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); 3013 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); 3014 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); 3015 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); 3016 3017 // Test B.C. 3018 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); 3019 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); 3020 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); 3021 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); 3022 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); 3023 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); 3024 3025 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3026 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3027 assert(cdt.toISOExtString() == "1999-07-06T12:30:33"); 3028 assert(idt.toISOExtString() == "1999-07-06T12:30:33"); 3029 } 3030 3031 /++ 3032 Converts this $(LREF DateTime) to a string with the format 3033 `YYYY-Mon-DD HH:MM:SS`. If `writer` is set, the resulting 3034 string will be written directly to it. 3035 3036 Params: 3037 writer = A `char` accepting 3038 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 3039 Returns: 3040 A `string` when not using an output range; `void` otherwise. 3041 +/ 3042 string toSimpleString() const @safe pure nothrow 3043 { 3044 import std.array : appender; 3045 auto w = appender!string(); 3046 w.reserve(22); 3047 try 3048 toSimpleString(w); 3049 catch (Exception e) 3050 assert(0, "toSimpleString() threw."); 3051 return w.data; 3052 } 3053 3054 /// ditto 3055 void toSimpleString(W)(ref W writer) const 3056 if (isOutputRange!(W, char)) 3057 { 3058 import std.format.write : formattedWrite; 3059 _date.toSimpleString(writer); 3060 formattedWrite!(" %02d:%02d:%02d")( 3061 writer, 3062 _tod._hour, 3063 _tod._minute, 3064 _tod._second 3065 ); 3066 } 3067 3068 /// 3069 @safe unittest 3070 { 3071 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == 3072 "2010-Jul-04 07:06:12"); 3073 3074 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == 3075 "1998-Dec-25 02:15:00"); 3076 3077 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == 3078 "0000-Jan-05 23:09:59"); 3079 3080 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == 3081 "-0004-Jan-05 00:00:02"); 3082 } 3083 3084 @safe unittest 3085 { 3086 // Test A.D. 3087 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); 3088 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); 3089 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); 3090 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); 3091 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); 3092 3093 // Test B.C. 3094 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); 3095 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); 3096 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); 3097 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); 3098 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); 3099 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); 3100 3101 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3102 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3103 assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33"); 3104 assert(idt.toSimpleString() == "1999-Jul-06 12:30:33"); 3105 } 3106 3107 3108 /++ 3109 Converts this $(LREF DateTime) to a string. 3110 3111 This function exists to make it easy to convert a $(LREF DateTime) to a 3112 string for code that does not care what the exact format is - just that 3113 it presents the information in a clear manner. It also makes it easy to 3114 simply convert a $(LREF DateTime) to a string when using functions such 3115 as `to!string`, `format`, or `writeln` which use toString to convert 3116 user-defined types. So, it is unlikely that much code will call 3117 toString directly. 3118 3119 The format of the string is purposefully unspecified, and code that 3120 cares about the format of the string should use `toISOString`, 3121 `toISOExtString`, `toSimpleString`, or some other custom formatting 3122 function that explicitly generates the format that the code needs. The 3123 reason is that the code is then clear about what format it's using, 3124 making it less error-prone to maintain the code and interact with other 3125 software that consumes the generated strings. It's for this same reason 3126 that $(LREF DateTime) has no `fromString` function, whereas it does have 3127 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 3128 3129 The format returned by toString may or may not change in the future. 3130 +/ 3131 string toString() const @safe pure nothrow 3132 { 3133 return toSimpleString(); 3134 } 3135 3136 @safe unittest 3137 { 3138 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3139 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3140 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3141 assert(dt.toString()); 3142 assert(cdt.toString()); 3143 assert(idt.toString()); 3144 } 3145 3146 /// ditto 3147 void toString(W)(ref W writer) const 3148 if (isOutputRange!(W, char)) 3149 { 3150 toSimpleString(writer); 3151 } 3152 3153 /++ 3154 Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS. 3155 Whitespace is stripped from the given string. 3156 3157 Params: 3158 isoString = A string formatted in the ISO format for dates and times. 3159 3160 Throws: 3161 $(REF DateTimeException,std,datetime,date) if the given string is 3162 not in the ISO format or if the resulting $(LREF DateTime) would not 3163 be valid. 3164 +/ 3165 static DateTime fromISOString(S)(scope const S isoString) @safe pure 3166 if (isSomeString!S) 3167 { 3168 import std.algorithm.searching : countUntil; 3169 import std.exception : enforce; 3170 import std.format : format; 3171 import std.string : strip; 3172 import std.utf : byCodeUnit; 3173 3174 auto str = strip(isoString); 3175 3176 enforce!DateTimeException(str.length >= 15, format("Invalid format for DateTime.fromISOString %s", isoString)); 3177 auto t = str.byCodeUnit.countUntil('T'); 3178 3179 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOString: %s", isoString)); 3180 3181 immutable date = Date.fromISOString(str[0 .. t]); 3182 immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]); 3183 3184 return DateTime(date, tod); 3185 } 3186 3187 /// 3188 @safe unittest 3189 { 3190 assert(DateTime.fromISOString("20100704T070612") == 3191 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3192 3193 assert(DateTime.fromISOString("19981225T021500") == 3194 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3195 3196 assert(DateTime.fromISOString("00000105T230959") == 3197 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3198 3199 assert(DateTime.fromISOString("-00040105T000002") == 3200 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3201 3202 assert(DateTime.fromISOString(" 20100704T070612 ") == 3203 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3204 } 3205 3206 @safe unittest 3207 { 3208 assertThrown!DateTimeException(DateTime.fromISOString("")); 3209 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3210 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3211 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3212 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3213 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3214 3215 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3216 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3217 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3218 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3219 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3220 3221 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3222 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3223 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3224 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3225 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3226 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3227 3228 assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201")); 3229 assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01")); 3230 3231 assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3232 assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3233 assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3234 assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3235 assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3236 assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3237 assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3238 } 3239 3240 // https://issues.dlang.org/show_bug.cgi?id=17801 3241 @safe unittest 3242 { 3243 import std.conv : to; 3244 import std.meta : AliasSeq; 3245 static foreach (C; AliasSeq!(char, wchar, dchar)) 3246 { 3247 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3248 assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16)); 3249 } 3250 } 3251 3252 3253 /++ 3254 Creates a $(LREF DateTime) from a string with the format 3255 YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string. 3256 3257 Params: 3258 isoExtString = A string formatted in the ISO Extended format for dates 3259 and times. 3260 3261 Throws: 3262 $(REF DateTimeException,std,datetime,date) if the given string is 3263 not in the ISO Extended format or if the resulting $(LREF DateTime) 3264 would not be valid. 3265 +/ 3266 static DateTime fromISOExtString(S)(scope const S isoExtString) @safe pure 3267 if (isSomeString!(S)) 3268 { 3269 import std.algorithm.searching : countUntil; 3270 import std.exception : enforce; 3271 import std.format : format; 3272 import std.string : strip; 3273 import std.utf : byCodeUnit; 3274 3275 auto str = strip(isoExtString); 3276 3277 enforce!DateTimeException(str.length >= 15, 3278 format("Invalid format for DateTime.fromISOExtString: %s", isoExtString)); 3279 auto t = str.byCodeUnit.countUntil('T'); 3280 3281 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOExtString: %s", isoExtString)); 3282 3283 immutable date = Date.fromISOExtString(str[0 .. t]); 3284 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3285 3286 return DateTime(date, tod); 3287 } 3288 3289 /// 3290 @safe unittest 3291 { 3292 assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == 3293 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3294 3295 assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == 3296 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3297 3298 assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == 3299 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3300 3301 assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == 3302 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3303 3304 assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == 3305 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3306 } 3307 3308 @safe unittest 3309 { 3310 assertThrown!DateTimeException(DateTime.fromISOExtString("")); 3311 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000")); 3312 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000")); 3313 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000")); 3314 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.")); 3315 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0")); 3316 3317 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00")); 3318 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3319 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3320 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00")); 3321 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.")); 3322 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0")); 3323 3324 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00")); 3325 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00")); 3326 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.")); 3327 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0")); 3328 3329 assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201")); 3330 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01")); 3331 3332 assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3333 assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3334 assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3335 assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3336 assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3337 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3338 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3339 } 3340 3341 // https://issues.dlang.org/show_bug.cgi?id=17801 3342 @safe unittest 3343 { 3344 import std.conv : to; 3345 import std.meta : AliasSeq; 3346 static foreach (C; AliasSeq!(char, wchar, dchar)) 3347 { 3348 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3349 assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3350 } 3351 } 3352 3353 3354 /++ 3355 Creates a $(LREF DateTime) from a string with the format 3356 YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string. 3357 3358 Params: 3359 simpleString = A string formatted in the way that toSimpleString 3360 formats dates and times. 3361 3362 Throws: 3363 $(REF DateTimeException,std,datetime,date) if the given string is 3364 not in the correct format or if the resulting $(LREF DateTime) 3365 would not be valid. 3366 +/ 3367 static DateTime fromSimpleString(S)(scope const S simpleString) @safe pure 3368 if (isSomeString!(S)) 3369 { 3370 import std.algorithm.searching : countUntil; 3371 import std.exception : enforce; 3372 import std.format : format; 3373 import std.string : strip; 3374 import std.utf : byCodeUnit; 3375 3376 auto str = strip(simpleString); 3377 3378 enforce!DateTimeException(str.length >= 15, 3379 format("Invalid format for DateTime.fromSimpleString: %s", simpleString)); 3380 auto t = str.byCodeUnit.countUntil(' '); 3381 3382 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromSimpleString: %s", simpleString)); 3383 3384 immutable date = Date.fromSimpleString(str[0 .. t]); 3385 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3386 3387 return DateTime(date, tod); 3388 } 3389 3390 /// 3391 @safe unittest 3392 { 3393 assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == 3394 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3395 assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == 3396 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3397 assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == 3398 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3399 assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == 3400 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3401 assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == 3402 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3403 } 3404 3405 @safe unittest 3406 { 3407 assertThrown!DateTimeException(DateTime.fromISOString("")); 3408 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3409 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3410 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3411 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3412 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3413 3414 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3415 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3416 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3417 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3418 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3419 3420 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3421 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3422 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3423 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3424 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3425 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3426 3427 assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201")); 3428 assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201")); 3429 3430 assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == 3431 DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3432 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == 3433 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3434 assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == 3435 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3436 assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == 3437 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3438 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == 3439 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3440 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == 3441 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3442 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == 3443 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3444 } 3445 3446 // https://issues.dlang.org/show_bug.cgi?id=17801 3447 @safe unittest 3448 { 3449 import std.conv : to; 3450 import std.meta : AliasSeq; 3451 static foreach (C; AliasSeq!(char, wchar, dchar)) 3452 { 3453 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3454 assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3455 } 3456 } 3457 3458 3459 /++ 3460 Returns the $(LREF DateTime) farthest in the past which is representable 3461 by $(LREF DateTime). 3462 +/ 3463 @property static DateTime min() @safe pure nothrow @nogc 3464 out(result) 3465 { 3466 assert(result._date == Date.min); 3467 assert(result._tod == TimeOfDay.min); 3468 } 3469 do 3470 { 3471 auto dt = DateTime.init; 3472 dt._date._year = short.min; 3473 dt._date._month = Month.jan; 3474 dt._date._day = 1; 3475 3476 return dt; 3477 } 3478 3479 @safe unittest 3480 { 3481 assert(DateTime.min.year < 0); 3482 assert(DateTime.min < DateTime.max); 3483 } 3484 3485 3486 /++ 3487 Returns the $(LREF DateTime) farthest in the future which is 3488 representable by $(LREF DateTime). 3489 +/ 3490 @property static DateTime max() @safe pure nothrow @nogc 3491 out(result) 3492 { 3493 assert(result._date == Date.max); 3494 assert(result._tod == TimeOfDay.max); 3495 } 3496 do 3497 { 3498 auto dt = DateTime.init; 3499 dt._date._year = short.max; 3500 dt._date._month = Month.dec; 3501 dt._date._day = 31; 3502 dt._tod._hour = TimeOfDay.maxHour; 3503 dt._tod._minute = TimeOfDay.maxMinute; 3504 dt._tod._second = TimeOfDay.maxSecond; 3505 3506 return dt; 3507 } 3508 3509 @safe unittest 3510 { 3511 assert(DateTime.max.year > 0); 3512 assert(DateTime.max > DateTime.min); 3513 } 3514 3515 3516 private: 3517 3518 /+ 3519 Add seconds to the time of day. Negative values will subtract. If the 3520 number of seconds overflows (or underflows), then the seconds will wrap, 3521 increasing (or decreasing) the number of minutes accordingly. The 3522 same goes for any larger units. 3523 3524 Params: 3525 seconds = The number of seconds to add to this $(LREF DateTime). 3526 +/ 3527 ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc 3528 { 3529 import core.time : convert; 3530 long hnsecs = convert!("seconds", "hnsecs")(seconds); 3531 hnsecs += convert!("hours", "hnsecs")(_tod._hour); 3532 hnsecs += convert!("minutes", "hnsecs")(_tod._minute); 3533 hnsecs += convert!("seconds", "hnsecs")(_tod._second); 3534 3535 auto days = splitUnitsFromHNSecs!"days"(hnsecs); 3536 3537 if (hnsecs < 0) 3538 { 3539 hnsecs += convert!("days", "hnsecs")(1); 3540 --days; 3541 } 3542 3543 _date._addDays(days); 3544 3545 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 3546 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 3547 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 3548 3549 _tod._hour = cast(ubyte) newHours; 3550 _tod._minute = cast(ubyte) newMinutes; 3551 _tod._second = cast(ubyte) newSeconds; 3552 3553 return this; 3554 } 3555 3556 @safe unittest 3557 { 3558 static void testDT(DateTime orig, int seconds, DateTime expected, size_t line = __LINE__) 3559 { 3560 orig._addSeconds(seconds); 3561 assert(orig == expected); 3562 } 3563 3564 // Test A.D. 3565 testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33)); 3566 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34)); 3567 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35)); 3568 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36)); 3569 testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37)); 3570 testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38)); 3571 testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43)); 3572 testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48)); 3573 testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59)); 3574 testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0)); 3575 testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3)); 3576 testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32)); 3577 testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33)); 3578 testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34)); 3579 3580 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59)); 3581 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0)); 3582 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1)); 3583 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0)); 3584 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32)); 3585 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33)); 3586 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34)); 3587 testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33)); 3588 testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3)); 3589 3590 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32)); 3591 testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31)); 3592 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30)); 3593 testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29)); 3594 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28)); 3595 testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23)); 3596 testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18)); 3597 testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0)); 3598 testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59)); 3599 testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58)); 3600 testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34)); 3601 testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33)); 3602 testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32)); 3603 3604 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0)); 3605 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59)); 3606 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33)); 3607 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32)); 3608 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59)); 3609 testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57)); 3610 3611 testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1)); 3612 testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0)); 3613 testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59)); 3614 3615 testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1)); 3616 testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0)); 3617 testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59)); 3618 3619 testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1)); 3620 testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0)); 3621 testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59)); 3622 3623 testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0)); 3624 testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59)); 3625 testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58)); 3626 3627 testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0)); 3628 testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59)); 3629 testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58)); 3630 3631 testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1)); 3632 testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0)); 3633 testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59)); 3634 3635 // Test B.C. 3636 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33)); 3637 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34)); 3638 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35)); 3639 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36)); 3640 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37)); 3641 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38)); 3642 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43)); 3643 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48)); 3644 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59)); 3645 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0)); 3646 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3)); 3647 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32)); 3648 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33)); 3649 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34)); 3650 3651 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59)); 3652 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0)); 3653 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1)); 3654 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0)); 3655 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32)); 3656 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33)); 3657 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34)); 3658 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33)); 3659 testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3)); 3660 3661 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32)); 3662 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31)); 3663 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30)); 3664 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29)); 3665 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28)); 3666 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23)); 3667 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18)); 3668 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0)); 3669 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59)); 3670 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58)); 3671 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34)); 3672 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33)); 3673 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32)); 3674 3675 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0)); 3676 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59)); 3677 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33)); 3678 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32)); 3679 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59)); 3680 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33)); 3681 testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57)); 3682 3683 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1)); 3684 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0)); 3685 testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59)); 3686 3687 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1)); 3688 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0)); 3689 testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59)); 3690 3691 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1)); 3692 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0)); 3693 testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59)); 3694 3695 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0)); 3696 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59)); 3697 testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58)); 3698 3699 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0)); 3700 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59)); 3701 testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58)); 3702 3703 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1)); 3704 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0)); 3705 testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59)); 3706 3707 // Test Both 3708 testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59)); 3709 testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0)); 3710 3711 testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59)); 3712 testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0)); 3713 3714 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33)); 3715 testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33)); 3716 3717 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50)); 3718 testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33)); 3719 3720 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3721 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3722 static assert(!__traits(compiles, cdt._addSeconds(4))); 3723 static assert(!__traits(compiles, idt._addSeconds(4))); 3724 } 3725 3726 3727 Date _date; 3728 TimeOfDay _tod; 3729 } 3730 3731 /// 3732 @safe pure unittest 3733 { 3734 import core.time : days, seconds; 3735 3736 auto dt = DateTime(2000, 6, 1, 10, 30, 0); 3737 3738 assert(dt.date == Date(2000, 6, 1)); 3739 assert(dt.timeOfDay == TimeOfDay(10, 30, 0)); 3740 assert(dt.dayOfYear == 153); 3741 assert(dt.dayOfWeek == DayOfWeek.thu); 3742 3743 dt += 10.days + 100.seconds; 3744 assert(dt == DateTime(2000, 6, 11, 10, 31, 40)); 3745 3746 assert(dt.toISOExtString() == "2000-06-11T10:31:40"); 3747 assert(dt.toISOString() == "20000611T103140"); 3748 assert(dt.toSimpleString() == "2000-Jun-11 10:31:40"); 3749 3750 assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); 3751 assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0)); 3752 assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); 3753 } 3754 3755 /++ 3756 Represents a date in the 3757 $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic 3758 Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years 3759 are A.D. Non-positive years are B.C. 3760 3761 Year, month, and day are kept separately internally so that `Date` is 3762 optimized for calendar-based operations. 3763 3764 `Date` uses the Proleptic Gregorian Calendar, so it assumes the Gregorian 3765 leap year calculations for its entire length. As per 3766 $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as 3767 year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C. 3768 as a positive integer with 1 B.C. being the year prior to 1 A.D. 3769 3770 Year 0 is a leap year. 3771 +/ 3772 struct Date 3773 { 3774 public: 3775 3776 /++ 3777 Throws: 3778 $(REF DateTimeException,std,datetime,date) if the resulting 3779 $(LREF Date) would not be valid. 3780 3781 Params: 3782 year = Year of the Gregorian Calendar. Positive values are A.D. 3783 Non-positive values are B.C. with year 0 being the year 3784 prior to 1 A.D. 3785 month = Month of the year (January is 1). 3786 day = Day of the month. 3787 +/ 3788 this(int year, int month, int day) @safe pure 3789 { 3790 enforceValid!"months"(cast(Month) month); 3791 enforceValid!"days"(year, cast(Month) month, day); 3792 3793 _year = year.castToYear; 3794 _month = cast(Month) month; 3795 _day = cast(ubyte) day; 3796 } 3797 3798 @safe unittest 3799 { 3800 import std.exception : assertNotThrown; 3801 assert(Date(1, 1, 1) == Date.init); 3802 3803 static void testDate(Date date, int year, int month, int day) 3804 { 3805 assert(date._year == year); 3806 assert(date._month == month); 3807 assert(date._day == day); 3808 } 3809 3810 testDate(Date(1999, 1 , 1), 1999, Month.jan, 1); 3811 testDate(Date(1999, 7 , 1), 1999, Month.jul, 1); 3812 testDate(Date(1999, 7 , 6), 1999, Month.jul, 6); 3813 3814 // Test A.D. 3815 assertThrown!DateTimeException(Date(1, 0, 1)); 3816 assertThrown!DateTimeException(Date(1, 1, 0)); 3817 assertThrown!DateTimeException(Date(1999, 13, 1)); 3818 assertThrown!DateTimeException(Date(1999, 1, 32)); 3819 assertThrown!DateTimeException(Date(1999, 2, 29)); 3820 assertThrown!DateTimeException(Date(2000, 2, 30)); 3821 assertThrown!DateTimeException(Date(1999, 3, 32)); 3822 assertThrown!DateTimeException(Date(1999, 4, 31)); 3823 assertThrown!DateTimeException(Date(1999, 5, 32)); 3824 assertThrown!DateTimeException(Date(1999, 6, 31)); 3825 assertThrown!DateTimeException(Date(1999, 7, 32)); 3826 assertThrown!DateTimeException(Date(1999, 8, 32)); 3827 assertThrown!DateTimeException(Date(1999, 9, 31)); 3828 assertThrown!DateTimeException(Date(1999, 10, 32)); 3829 assertThrown!DateTimeException(Date(1999, 11, 31)); 3830 assertThrown!DateTimeException(Date(1999, 12, 32)); 3831 assertThrown!DateTimeException(Date(short.max+1, 1, 1)); 3832 3833 assertNotThrown!DateTimeException(Date(1999, 1, 31)); 3834 assertNotThrown!DateTimeException(Date(1999, 2, 28)); 3835 assertNotThrown!DateTimeException(Date(2000, 2, 29)); 3836 assertNotThrown!DateTimeException(Date(1999, 3, 31)); 3837 assertNotThrown!DateTimeException(Date(1999, 4, 30)); 3838 assertNotThrown!DateTimeException(Date(1999, 5, 31)); 3839 assertNotThrown!DateTimeException(Date(1999, 6, 30)); 3840 assertNotThrown!DateTimeException(Date(1999, 7, 31)); 3841 assertNotThrown!DateTimeException(Date(1999, 8, 31)); 3842 assertNotThrown!DateTimeException(Date(1999, 9, 30)); 3843 assertNotThrown!DateTimeException(Date(1999, 10, 31)); 3844 assertNotThrown!DateTimeException(Date(1999, 11, 30)); 3845 assertNotThrown!DateTimeException(Date(1999, 12, 31)); 3846 3847 // Test B.C. 3848 assertNotThrown!DateTimeException(Date(0, 1, 1)); 3849 assertNotThrown!DateTimeException(Date(-1, 1, 1)); 3850 assertNotThrown!DateTimeException(Date(-1, 12, 31)); 3851 assertNotThrown!DateTimeException(Date(-1, 2, 28)); 3852 assertNotThrown!DateTimeException(Date(-4, 2, 29)); 3853 3854 assertThrown!DateTimeException(Date(-1, 2, 29)); 3855 assertThrown!DateTimeException(Date(-2, 2, 29)); 3856 assertThrown!DateTimeException(Date(-3, 2, 29)); 3857 assertThrown!DateTimeException(Date(short.min-1, 1, 1)); 3858 } 3859 3860 3861 /++ 3862 Params: 3863 day = The Xth day of the Gregorian Calendar that the constructed 3864 $(LREF Date) will be for. 3865 +/ 3866 this(int day) @safe pure nothrow @nogc 3867 { 3868 if (day > 0) 3869 { 3870 int years = (day / daysIn400Years) * 400 + 1; 3871 day %= daysIn400Years; 3872 3873 { 3874 immutable tempYears = day / daysIn100Years; 3875 3876 if (tempYears == 4) 3877 { 3878 years += 300; 3879 day -= daysIn100Years * 3; 3880 } 3881 else 3882 { 3883 years += tempYears * 100; 3884 day %= daysIn100Years; 3885 } 3886 } 3887 3888 years += (day / daysIn4Years) * 4; 3889 day %= daysIn4Years; 3890 3891 { 3892 immutable tempYears = day / daysInYear; 3893 3894 if (tempYears == 4) 3895 { 3896 years += 3; 3897 day -= daysInYear * 3; 3898 } 3899 else 3900 { 3901 years += tempYears; 3902 day %= daysInYear; 3903 } 3904 } 3905 3906 if (day == 0) 3907 { 3908 _year = cast(short)(years - 1); 3909 _month = Month.dec; 3910 _day = 31; 3911 } 3912 else 3913 { 3914 _year = cast(short) years; 3915 3916 setDayOfYear(day); 3917 } 3918 } 3919 else if (day <= 0 && -day < daysInLeapYear) 3920 { 3921 _year = 0; 3922 3923 setDayOfYear(daysInLeapYear + day); 3924 } 3925 else 3926 { 3927 day += daysInLeapYear - 1; 3928 int years = (day / daysIn400Years) * 400 - 1; 3929 day %= daysIn400Years; 3930 3931 { 3932 immutable tempYears = day / daysIn100Years; 3933 3934 if (tempYears == -4) 3935 { 3936 years -= 300; 3937 day += daysIn100Years * 3; 3938 } 3939 else 3940 { 3941 years += tempYears * 100; 3942 day %= daysIn100Years; 3943 } 3944 } 3945 3946 years += (day / daysIn4Years) * 4; 3947 day %= daysIn4Years; 3948 3949 { 3950 immutable tempYears = day / daysInYear; 3951 3952 if (tempYears == -4) 3953 { 3954 years -= 3; 3955 day += daysInYear * 3; 3956 } 3957 else 3958 { 3959 years += tempYears; 3960 day %= daysInYear; 3961 } 3962 } 3963 3964 if (day == 0) 3965 { 3966 _year = cast(short)(years + 1); 3967 _month = Month.jan; 3968 _day = 1; 3969 } 3970 else 3971 { 3972 _year = cast(short) years; 3973 immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1; 3974 3975 setDayOfYear(newDoY); 3976 } 3977 } 3978 } 3979 3980 @safe unittest 3981 { 3982 import std.range : chain; 3983 3984 // Test A.D. 3985 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 3986 assert(Date(gd.day) == gd.date); 3987 } 3988 3989 3990 /++ 3991 Compares this $(LREF Date) with the given $(LREF Date). 3992 3993 Returns: 3994 $(BOOKTABLE, 3995 $(TR $(TD this < rhs) $(TD < 0)) 3996 $(TR $(TD this == rhs) $(TD 0)) 3997 $(TR $(TD this > rhs) $(TD > 0)) 3998 ) 3999 +/ 4000 int opCmp(Date rhs) const @safe pure nothrow @nogc 4001 { 4002 if (_year < rhs._year) 4003 return -1; 4004 if (_year > rhs._year) 4005 return 1; 4006 4007 if (_month < rhs._month) 4008 return -1; 4009 if (_month > rhs._month) 4010 return 1; 4011 4012 if (_day < rhs._day) 4013 return -1; 4014 if (_day > rhs._day) 4015 return 1; 4016 4017 return 0; 4018 } 4019 4020 @safe unittest 4021 { 4022 // Test A.D. 4023 assert(Date(1, 1, 1).opCmp(Date.init) == 0); 4024 4025 assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0); 4026 assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0); 4027 assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0); 4028 4029 assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0); 4030 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0); 4031 4032 assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0); 4033 4034 assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0); 4035 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0); 4036 assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0); 4037 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0); 4038 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0); 4039 assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0); 4040 4041 assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0); 4042 assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 4043 assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0); 4044 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0); 4045 assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0); 4046 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 4047 4048 // Test B.C. 4049 assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0); 4050 assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0); 4051 assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0); 4052 assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0); 4053 4054 assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0); 4055 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0); 4056 4057 assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0); 4058 4059 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0); 4060 assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0); 4061 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0); 4062 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0); 4063 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 4064 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0); 4065 4066 assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0); 4067 assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0); 4068 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 4069 assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0); 4070 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0); 4071 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0); 4072 4073 // Test Both 4074 assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0); 4075 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0); 4076 4077 assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0); 4078 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0); 4079 4080 assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0); 4081 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0); 4082 4083 assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0); 4084 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0); 4085 4086 assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0); 4087 assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0); 4088 4089 auto date = Date(1999, 7, 6); 4090 const cdate = Date(1999, 7, 6); 4091 immutable idate = Date(1999, 7, 6); 4092 assert(date.opCmp(date) == 0); 4093 assert(date.opCmp(cdate) == 0); 4094 assert(date.opCmp(idate) == 0); 4095 assert(cdate.opCmp(date) == 0); 4096 assert(cdate.opCmp(cdate) == 0); 4097 assert(cdate.opCmp(idate) == 0); 4098 assert(idate.opCmp(date) == 0); 4099 assert(idate.opCmp(cdate) == 0); 4100 assert(idate.opCmp(idate) == 0); 4101 } 4102 4103 4104 /++ 4105 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 4106 are B.C. 4107 +/ 4108 @property short year() const @safe pure nothrow @nogc 4109 { 4110 return _year; 4111 } 4112 4113 /// 4114 @safe unittest 4115 { 4116 assert(Date(1999, 7, 6).year == 1999); 4117 assert(Date(2010, 10, 4).year == 2010); 4118 assert(Date(-7, 4, 5).year == -7); 4119 } 4120 4121 @safe unittest 4122 { 4123 assert(Date.init.year == 1); 4124 assert(Date(1999, 7, 6).year == 1999); 4125 assert(Date(-1999, 7, 6).year == -1999); 4126 4127 const cdate = Date(1999, 7, 6); 4128 immutable idate = Date(1999, 7, 6); 4129 assert(cdate.year == 1999); 4130 assert(idate.year == 1999); 4131 } 4132 4133 /++ 4134 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 4135 are B.C. 4136 4137 Params: 4138 year = The year to set this Date's year to. 4139 4140 Throws: 4141 $(REF DateTimeException,std,datetime,date) if the new year is not 4142 a leap year and the resulting date would be on February 29th. 4143 +/ 4144 @property void year(int year) @safe pure 4145 { 4146 enforceValid!"days"(year, _month, _day); 4147 _year = year.castToYear; 4148 } 4149 4150 /// 4151 @safe unittest 4152 { 4153 assert(Date(1999, 7, 6).year == 1999); 4154 assert(Date(2010, 10, 4).year == 2010); 4155 assert(Date(-7, 4, 5).year == -7); 4156 } 4157 4158 @safe unittest 4159 { 4160 static void testDateInvalid(Date date, int year) 4161 { 4162 date.year = year; 4163 } 4164 4165 static void testDate(Date date, int year, Date expected) 4166 { 4167 date.year = year; 4168 assert(date == expected); 4169 } 4170 4171 assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1)); 4172 4173 testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1)); 4174 testDate(Date(1, 1, 1), 0, Date(0, 1, 1)); 4175 testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1)); 4176 4177 const cdate = Date(1999, 7, 6); 4178 immutable idate = Date(1999, 7, 6); 4179 static assert(!__traits(compiles, cdate.year = 1999)); 4180 static assert(!__traits(compiles, idate.year = 1999)); 4181 } 4182 4183 4184 /++ 4185 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4186 4187 Throws: 4188 $(REF DateTimeException,std,datetime,date) if `isAD` is true. 4189 +/ 4190 @property ushort yearBC() const @safe pure 4191 { 4192 import std.format : format; 4193 4194 if (isAD) 4195 throw new DateTimeException(format("Year %s is A.D.", _year)); 4196 return cast(ushort)((_year * -1) + 1); 4197 } 4198 4199 /// 4200 @safe unittest 4201 { 4202 assert(Date(0, 1, 1).yearBC == 1); 4203 assert(Date(-1, 1, 1).yearBC == 2); 4204 assert(Date(-100, 1, 1).yearBC == 101); 4205 } 4206 4207 @safe unittest 4208 { 4209 assertThrown!DateTimeException((Date date){date.yearBC;}(Date(1, 1, 1))); 4210 4211 auto date = Date(0, 7, 6); 4212 const cdate = Date(0, 7, 6); 4213 immutable idate = Date(0, 7, 6); 4214 assert(date.yearBC == 1); 4215 assert(cdate.yearBC == 1); 4216 assert(idate.yearBC == 1); 4217 } 4218 4219 4220 /++ 4221 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4222 4223 Params: 4224 year = The year B.C. to set this $(LREF Date)'s year to. 4225 4226 Throws: 4227 $(REF DateTimeException,std,datetime,date) if a non-positive value 4228 is given. 4229 +/ 4230 @property void yearBC(int year) @safe pure 4231 { 4232 if (year <= 0) 4233 throw new DateTimeException("The given year is not a year B.C."); 4234 _year = castToYear((year - 1) * -1); 4235 } 4236 4237 /// 4238 @safe unittest 4239 { 4240 auto date = Date(2010, 1, 1); 4241 date.yearBC = 1; 4242 assert(date == Date(0, 1, 1)); 4243 4244 date.yearBC = 10; 4245 assert(date == Date(-9, 1, 1)); 4246 } 4247 4248 @safe unittest 4249 { 4250 assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1))); 4251 4252 auto date = Date(0, 7, 6); 4253 const cdate = Date(0, 7, 6); 4254 immutable idate = Date(0, 7, 6); 4255 date.yearBC = 7; 4256 assert(date.yearBC == 7); 4257 static assert(!__traits(compiles, cdate.yearBC = 7)); 4258 static assert(!__traits(compiles, idate.yearBC = 7)); 4259 } 4260 4261 4262 /++ 4263 Month of a Gregorian Year. 4264 +/ 4265 @property Month month() const @safe pure nothrow @nogc 4266 { 4267 return _month; 4268 } 4269 4270 /// 4271 @safe unittest 4272 { 4273 assert(Date(1999, 7, 6).month == 7); 4274 assert(Date(2010, 10, 4).month == 10); 4275 assert(Date(-7, 4, 5).month == 4); 4276 } 4277 4278 @safe unittest 4279 { 4280 assert(Date.init.month == 1); 4281 assert(Date(1999, 7, 6).month == 7); 4282 assert(Date(-1999, 7, 6).month == 7); 4283 4284 const cdate = Date(1999, 7, 6); 4285 immutable idate = Date(1999, 7, 6); 4286 assert(cdate.month == 7); 4287 assert(idate.month == 7); 4288 } 4289 4290 /++ 4291 Month of a Gregorian Year. 4292 4293 Params: 4294 month = The month to set this $(LREF Date)'s month to. 4295 4296 Throws: 4297 $(REF DateTimeException,std,datetime,date) if the given month is 4298 not a valid month or if the current day would not be valid in the 4299 given month. 4300 +/ 4301 @property void month(Month month) @safe pure 4302 { 4303 enforceValid!"months"(month); 4304 enforceValid!"days"(_year, month, _day); 4305 _month = cast(Month) month; 4306 } 4307 4308 @safe unittest 4309 { 4310 static void testDate(Date date, Month month, Date expected = Date.init) 4311 { 4312 date.month = month; 4313 assert(expected != Date.init); 4314 assert(date == expected); 4315 } 4316 4317 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0)); 4318 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13)); 4319 assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2)); 4320 assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2)); 4321 4322 testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1)); 4323 testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1)); 4324 4325 const cdate = Date(1999, 7, 6); 4326 immutable idate = Date(1999, 7, 6); 4327 static assert(!__traits(compiles, cdate.month = 7)); 4328 static assert(!__traits(compiles, idate.month = 7)); 4329 } 4330 4331 4332 /++ 4333 Day of a Gregorian Month. 4334 +/ 4335 @property ubyte day() const @safe pure nothrow @nogc 4336 { 4337 return _day; 4338 } 4339 4340 /// 4341 @safe unittest 4342 { 4343 assert(Date(1999, 7, 6).day == 6); 4344 assert(Date(2010, 10, 4).day == 4); 4345 assert(Date(-7, 4, 5).day == 5); 4346 } 4347 4348 @safe unittest 4349 { 4350 import std.format : format; 4351 import std.range : chain; 4352 4353 static void test(Date date, int expected) 4354 { 4355 assert(date.day == expected, format("Value given: %s", date)); 4356 } 4357 4358 foreach (year; chain(testYearsBC, testYearsAD)) 4359 { 4360 foreach (md; testMonthDays) 4361 test(Date(year, md.month, md.day), md.day); 4362 } 4363 4364 const cdate = Date(1999, 7, 6); 4365 immutable idate = Date(1999, 7, 6); 4366 assert(cdate.day == 6); 4367 assert(idate.day == 6); 4368 } 4369 4370 /++ 4371 Day of a Gregorian Month. 4372 4373 Params: 4374 day = The day of the month to set this $(LREF Date)'s day to. 4375 4376 Throws: 4377 $(REF DateTimeException,std,datetime,date) if the given day is not 4378 a valid day of the current month. 4379 +/ 4380 @property void day(int day) @safe pure 4381 { 4382 enforceValid!"days"(_year, _month, day); 4383 _day = cast(ubyte) day; 4384 } 4385 4386 @safe unittest 4387 { 4388 import std.exception : assertNotThrown; 4389 4390 static void testDate(Date date, int day) 4391 { 4392 date.day = day; 4393 } 4394 4395 // Test A.D. 4396 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0)); 4397 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32)); 4398 assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29)); 4399 assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30)); 4400 assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32)); 4401 assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31)); 4402 assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32)); 4403 assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31)); 4404 assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32)); 4405 assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32)); 4406 assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31)); 4407 assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32)); 4408 assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31)); 4409 assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32)); 4410 4411 assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31)); 4412 assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28)); 4413 assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29)); 4414 assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31)); 4415 assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30)); 4416 assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31)); 4417 assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30)); 4418 assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31)); 4419 assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31)); 4420 assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30)); 4421 assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31)); 4422 assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30)); 4423 assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31)); 4424 4425 { 4426 auto date = Date(1, 1, 1); 4427 date.day = 6; 4428 assert(date == Date(1, 1, 6)); 4429 } 4430 4431 // Test B.C. 4432 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0)); 4433 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32)); 4434 assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29)); 4435 assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30)); 4436 assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32)); 4437 assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31)); 4438 assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32)); 4439 assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31)); 4440 assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32)); 4441 assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32)); 4442 assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31)); 4443 assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32)); 4444 assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31)); 4445 assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32)); 4446 4447 assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31)); 4448 assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28)); 4449 assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29)); 4450 assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31)); 4451 assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30)); 4452 assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31)); 4453 assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30)); 4454 assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31)); 4455 assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31)); 4456 assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30)); 4457 assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31)); 4458 assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30)); 4459 assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31)); 4460 4461 { 4462 auto date = Date(-1, 1, 1); 4463 date.day = 6; 4464 assert(date == Date(-1, 1, 6)); 4465 } 4466 4467 const cdate = Date(1999, 7, 6); 4468 immutable idate = Date(1999, 7, 6); 4469 static assert(!__traits(compiles, cdate.day = 6)); 4470 static assert(!__traits(compiles, idate.day = 6)); 4471 } 4472 4473 4474 /++ 4475 Adds the given number of years or months to this $(LREF Date), mutating 4476 it. A negative number will subtract. 4477 4478 Note that if day overflow is allowed, and the date with the adjusted 4479 year/month overflows the number of days in the new month, then the month 4480 will be incremented by one, and the day set to the number of days 4481 overflowed. (e.g. if the day were 31 and the new month were June, then 4482 the month would be incremented to July, and the new day would be 1). If 4483 day overflow is not allowed, then the day will be set to the last valid 4484 day in the month (e.g. June 31st would become June 30th). 4485 4486 Params: 4487 units = The type of units to add ("years" or "months"). 4488 value = The number of months or years to add to this 4489 $(LREF Date). 4490 allowOverflow = Whether the day should be allowed to overflow, 4491 causing the month to increment. 4492 4493 Returns: 4494 A reference to the `Date` (`this`). 4495 +/ 4496 @safe pure nothrow @nogc 4497 ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4498 if (units == "years") 4499 { 4500 _year += value; 4501 4502 if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year)) 4503 { 4504 if (allowOverflow == AllowDayOverflow.yes) 4505 { 4506 _month = Month.mar; 4507 _day = 1; 4508 } 4509 else 4510 _day = 28; 4511 } 4512 4513 return this; 4514 } 4515 4516 /// 4517 @safe unittest 4518 { 4519 auto d1 = Date(2010, 1, 1); 4520 d1.add!"months"(11); 4521 assert(d1 == Date(2010, 12, 1)); 4522 4523 auto d2 = Date(2010, 1, 1); 4524 d2.add!"months"(-11); 4525 assert(d2 == Date(2009, 2, 1)); 4526 4527 auto d3 = Date(2000, 2, 29); 4528 d3.add!"years"(1); 4529 assert(d3 == Date(2001, 3, 1)); 4530 4531 auto d4 = Date(2000, 2, 29); 4532 d4.add!"years"(1, AllowDayOverflow.no); 4533 assert(d4 == Date(2001, 2, 28)); 4534 } 4535 4536 // Test add!"years"() with AllowDayOverflow.yes 4537 @safe unittest 4538 { 4539 // Test A.D. 4540 { 4541 auto date = Date(1999, 7, 6); 4542 date.add!"years"(7); 4543 assert(date == Date(2006, 7, 6)); 4544 date.add!"years"(-9); 4545 assert(date == Date(1997, 7, 6)); 4546 } 4547 4548 { 4549 auto date = Date(1999, 2, 28); 4550 date.add!"years"(1); 4551 assert(date == Date(2000, 2, 28)); 4552 } 4553 4554 { 4555 auto date = Date(2000, 2, 29); 4556 date.add!"years"(-1); 4557 assert(date == Date(1999, 3, 1)); 4558 } 4559 4560 // Test B.C. 4561 { 4562 auto date = Date(-1999, 7, 6); 4563 date.add!"years"(-7); 4564 assert(date == Date(-2006, 7, 6)); 4565 date.add!"years"(9); 4566 assert(date == Date(-1997, 7, 6)); 4567 } 4568 4569 { 4570 auto date = Date(-1999, 2, 28); 4571 date.add!"years"(-1); 4572 assert(date == Date(-2000, 2, 28)); 4573 } 4574 4575 { 4576 auto date = Date(-2000, 2, 29); 4577 date.add!"years"(1); 4578 assert(date == Date(-1999, 3, 1)); 4579 } 4580 4581 // Test Both 4582 { 4583 auto date = Date(4, 7, 6); 4584 date.add!"years"(-5); 4585 assert(date == Date(-1, 7, 6)); 4586 date.add!"years"(5); 4587 assert(date == Date(4, 7, 6)); 4588 } 4589 4590 { 4591 auto date = Date(-4, 7, 6); 4592 date.add!"years"(5); 4593 assert(date == Date(1, 7, 6)); 4594 date.add!"years"(-5); 4595 assert(date == Date(-4, 7, 6)); 4596 } 4597 4598 { 4599 auto date = Date(4, 7, 6); 4600 date.add!"years"(-8); 4601 assert(date == Date(-4, 7, 6)); 4602 date.add!"years"(8); 4603 assert(date == Date(4, 7, 6)); 4604 } 4605 4606 { 4607 auto date = Date(-4, 7, 6); 4608 date.add!"years"(8); 4609 assert(date == Date(4, 7, 6)); 4610 date.add!"years"(-8); 4611 assert(date == Date(-4, 7, 6)); 4612 } 4613 4614 { 4615 auto date = Date(-4, 2, 29); 4616 date.add!"years"(5); 4617 assert(date == Date(1, 3, 1)); 4618 } 4619 4620 { 4621 auto date = Date(4, 2, 29); 4622 date.add!"years"(-5); 4623 assert(date == Date(-1, 3, 1)); 4624 } 4625 4626 { 4627 auto date = Date(4, 2, 29); 4628 date.add!"years"(-5).add!"years"(7); 4629 assert(date == Date(6, 3, 1)); 4630 } 4631 4632 const cdate = Date(1999, 7, 6); 4633 immutable idate = Date(1999, 7, 6); 4634 static assert(!__traits(compiles, cdate.add!"years"(7))); 4635 static assert(!__traits(compiles, idate.add!"years"(7))); 4636 } 4637 4638 // Test add!"years"() with AllowDayOverflow.no 4639 @safe unittest 4640 { 4641 // Test A.D. 4642 { 4643 auto date = Date(1999, 7, 6); 4644 date.add!"years"(7, AllowDayOverflow.no); 4645 assert(date == Date(2006, 7, 6)); 4646 date.add!"years"(-9, AllowDayOverflow.no); 4647 assert(date == Date(1997, 7, 6)); 4648 } 4649 4650 { 4651 auto date = Date(1999, 2, 28); 4652 date.add!"years"(1, AllowDayOverflow.no); 4653 assert(date == Date(2000, 2, 28)); 4654 } 4655 4656 { 4657 auto date = Date(2000, 2, 29); 4658 date.add!"years"(-1, AllowDayOverflow.no); 4659 assert(date == Date(1999, 2, 28)); 4660 } 4661 4662 // Test B.C. 4663 { 4664 auto date = Date(-1999, 7, 6); 4665 date.add!"years"(-7, AllowDayOverflow.no); 4666 assert(date == Date(-2006, 7, 6)); 4667 date.add!"years"(9, AllowDayOverflow.no); 4668 assert(date == Date(-1997, 7, 6)); 4669 } 4670 4671 { 4672 auto date = Date(-1999, 2, 28); 4673 date.add!"years"(-1, AllowDayOverflow.no); 4674 assert(date == Date(-2000, 2, 28)); 4675 } 4676 4677 { 4678 auto date = Date(-2000, 2, 29); 4679 date.add!"years"(1, AllowDayOverflow.no); 4680 assert(date == Date(-1999, 2, 28)); 4681 } 4682 4683 // Test Both 4684 { 4685 auto date = Date(4, 7, 6); 4686 date.add!"years"(-5, AllowDayOverflow.no); 4687 assert(date == Date(-1, 7, 6)); 4688 date.add!"years"(5, AllowDayOverflow.no); 4689 assert(date == Date(4, 7, 6)); 4690 } 4691 4692 { 4693 auto date = Date(-4, 7, 6); 4694 date.add!"years"(5, AllowDayOverflow.no); 4695 assert(date == Date(1, 7, 6)); 4696 date.add!"years"(-5, AllowDayOverflow.no); 4697 assert(date == Date(-4, 7, 6)); 4698 } 4699 4700 { 4701 auto date = Date(4, 7, 6); 4702 date.add!"years"(-8, AllowDayOverflow.no); 4703 assert(date == Date(-4, 7, 6)); 4704 date.add!"years"(8, AllowDayOverflow.no); 4705 assert(date == Date(4, 7, 6)); 4706 } 4707 4708 { 4709 auto date = Date(-4, 7, 6); 4710 date.add!"years"(8, AllowDayOverflow.no); 4711 assert(date == Date(4, 7, 6)); 4712 date.add!"years"(-8, AllowDayOverflow.no); 4713 assert(date == Date(-4, 7, 6)); 4714 } 4715 4716 { 4717 auto date = Date(-4, 2, 29); 4718 date.add!"years"(5, AllowDayOverflow.no); 4719 assert(date == Date(1, 2, 28)); 4720 } 4721 4722 { 4723 auto date = Date(4, 2, 29); 4724 date.add!"years"(-5, AllowDayOverflow.no); 4725 assert(date == Date(-1, 2, 28)); 4726 } 4727 4728 { 4729 auto date = Date(4, 2, 29); 4730 date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); 4731 assert(date == Date(6, 2, 28)); 4732 } 4733 } 4734 4735 4736 // Shares documentation with "years" version. 4737 @safe pure nothrow @nogc 4738 ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4739 if (units == "months") 4740 { 4741 auto years = months / 12; 4742 months %= 12; 4743 auto newMonth = _month + months; 4744 4745 if (months < 0) 4746 { 4747 if (newMonth < 1) 4748 { 4749 newMonth += 12; 4750 --years; 4751 } 4752 } 4753 else if (newMonth > 12) 4754 { 4755 newMonth -= 12; 4756 ++years; 4757 } 4758 4759 _year += years; 4760 _month = cast(Month) newMonth; 4761 4762 immutable currMaxDay = maxDay(_year, _month); 4763 immutable overflow = _day - currMaxDay; 4764 4765 if (overflow > 0) 4766 { 4767 if (allowOverflow == AllowDayOverflow.yes) 4768 { 4769 ++_month; 4770 _day = cast(ubyte) overflow; 4771 } 4772 else 4773 _day = cast(ubyte) currMaxDay; 4774 } 4775 4776 return this; 4777 } 4778 4779 // Test add!"months"() with AllowDayOverflow.yes 4780 @safe unittest 4781 { 4782 // Test A.D. 4783 { 4784 auto date = Date(1999, 7, 6); 4785 date.add!"months"(3); 4786 assert(date == Date(1999, 10, 6)); 4787 date.add!"months"(-4); 4788 assert(date == Date(1999, 6, 6)); 4789 } 4790 4791 { 4792 auto date = Date(1999, 7, 6); 4793 date.add!"months"(6); 4794 assert(date == Date(2000, 1, 6)); 4795 date.add!"months"(-6); 4796 assert(date == Date(1999, 7, 6)); 4797 } 4798 4799 { 4800 auto date = Date(1999, 7, 6); 4801 date.add!"months"(27); 4802 assert(date == Date(2001, 10, 6)); 4803 date.add!"months"(-28); 4804 assert(date == Date(1999, 6, 6)); 4805 } 4806 4807 { 4808 auto date = Date(1999, 5, 31); 4809 date.add!"months"(1); 4810 assert(date == Date(1999, 7, 1)); 4811 } 4812 4813 { 4814 auto date = Date(1999, 5, 31); 4815 date.add!"months"(-1); 4816 assert(date == Date(1999, 5, 1)); 4817 } 4818 4819 { 4820 auto date = Date(1999, 2, 28); 4821 date.add!"months"(12); 4822 assert(date == Date(2000, 2, 28)); 4823 } 4824 4825 { 4826 auto date = Date(2000, 2, 29); 4827 date.add!"months"(12); 4828 assert(date == Date(2001, 3, 1)); 4829 } 4830 4831 { 4832 auto date = Date(1999, 7, 31); 4833 date.add!"months"(1); 4834 assert(date == Date(1999, 8, 31)); 4835 date.add!"months"(1); 4836 assert(date == Date(1999, 10, 1)); 4837 } 4838 4839 { 4840 auto date = Date(1998, 8, 31); 4841 date.add!"months"(13); 4842 assert(date == Date(1999, 10, 1)); 4843 date.add!"months"(-13); 4844 assert(date == Date(1998, 9, 1)); 4845 } 4846 4847 { 4848 auto date = Date(1997, 12, 31); 4849 date.add!"months"(13); 4850 assert(date == Date(1999, 1, 31)); 4851 date.add!"months"(-13); 4852 assert(date == Date(1997, 12, 31)); 4853 } 4854 4855 { 4856 auto date = Date(1997, 12, 31); 4857 date.add!"months"(14); 4858 assert(date == Date(1999, 3, 3)); 4859 date.add!"months"(-14); 4860 assert(date == Date(1998, 1, 3)); 4861 } 4862 4863 { 4864 auto date = Date(1998, 12, 31); 4865 date.add!"months"(14); 4866 assert(date == Date(2000, 3, 2)); 4867 date.add!"months"(-14); 4868 assert(date == Date(1999, 1, 2)); 4869 } 4870 4871 { 4872 auto date = Date(1999, 12, 31); 4873 date.add!"months"(14); 4874 assert(date == Date(2001, 3, 3)); 4875 date.add!"months"(-14); 4876 assert(date == Date(2000, 1, 3)); 4877 } 4878 4879 // Test B.C. 4880 { 4881 auto date = Date(-1999, 7, 6); 4882 date.add!"months"(3); 4883 assert(date == Date(-1999, 10, 6)); 4884 date.add!"months"(-4); 4885 assert(date == Date(-1999, 6, 6)); 4886 } 4887 4888 { 4889 auto date = Date(-1999, 7, 6); 4890 date.add!"months"(6); 4891 assert(date == Date(-1998, 1, 6)); 4892 date.add!"months"(-6); 4893 assert(date == Date(-1999, 7, 6)); 4894 } 4895 4896 { 4897 auto date = Date(-1999, 7, 6); 4898 date.add!"months"(-27); 4899 assert(date == Date(-2001, 4, 6)); 4900 date.add!"months"(28); 4901 assert(date == Date(-1999, 8, 6)); 4902 } 4903 4904 { 4905 auto date = Date(-1999, 5, 31); 4906 date.add!"months"(1); 4907 assert(date == Date(-1999, 7, 1)); 4908 } 4909 4910 { 4911 auto date = Date(-1999, 5, 31); 4912 date.add!"months"(-1); 4913 assert(date == Date(-1999, 5, 1)); 4914 } 4915 4916 { 4917 auto date = Date(-1999, 2, 28); 4918 date.add!"months"(-12); 4919 assert(date == Date(-2000, 2, 28)); 4920 } 4921 4922 { 4923 auto date = Date(-2000, 2, 29); 4924 date.add!"months"(-12); 4925 assert(date == Date(-2001, 3, 1)); 4926 } 4927 4928 { 4929 auto date = Date(-1999, 7, 31); 4930 date.add!"months"(1); 4931 assert(date == Date(-1999, 8, 31)); 4932 date.add!"months"(1); 4933 assert(date == Date(-1999, 10, 1)); 4934 } 4935 4936 { 4937 auto date = Date(-1998, 8, 31); 4938 date.add!"months"(13); 4939 assert(date == Date(-1997, 10, 1)); 4940 date.add!"months"(-13); 4941 assert(date == Date(-1998, 9, 1)); 4942 } 4943 4944 { 4945 auto date = Date(-1997, 12, 31); 4946 date.add!"months"(13); 4947 assert(date == Date(-1995, 1, 31)); 4948 date.add!"months"(-13); 4949 assert(date == Date(-1997, 12, 31)); 4950 } 4951 4952 { 4953 auto date = Date(-1997, 12, 31); 4954 date.add!"months"(14); 4955 assert(date == Date(-1995, 3, 3)); 4956 date.add!"months"(-14); 4957 assert(date == Date(-1996, 1, 3)); 4958 } 4959 4960 { 4961 auto date = Date(-2002, 12, 31); 4962 date.add!"months"(14); 4963 assert(date == Date(-2000, 3, 2)); 4964 date.add!"months"(-14); 4965 assert(date == Date(-2001, 1, 2)); 4966 } 4967 4968 { 4969 auto date = Date(-2001, 12, 31); 4970 date.add!"months"(14); 4971 assert(date == Date(-1999, 3, 3)); 4972 date.add!"months"(-14); 4973 assert(date == Date(-2000, 1, 3)); 4974 } 4975 4976 // Test Both 4977 { 4978 auto date = Date(1, 1, 1); 4979 date.add!"months"(-1); 4980 assert(date == Date(0, 12, 1)); 4981 date.add!"months"(1); 4982 assert(date == Date(1, 1, 1)); 4983 } 4984 4985 { 4986 auto date = Date(4, 1, 1); 4987 date.add!"months"(-48); 4988 assert(date == Date(0, 1, 1)); 4989 date.add!"months"(48); 4990 assert(date == Date(4, 1, 1)); 4991 } 4992 4993 { 4994 auto date = Date(4, 3, 31); 4995 date.add!"months"(-49); 4996 assert(date == Date(0, 3, 2)); 4997 date.add!"months"(49); 4998 assert(date == Date(4, 4, 2)); 4999 } 5000 5001 { 5002 auto date = Date(4, 3, 31); 5003 date.add!"months"(-85); 5004 assert(date == Date(-3, 3, 3)); 5005 date.add!"months"(85); 5006 assert(date == Date(4, 4, 3)); 5007 } 5008 5009 { 5010 auto date = Date(-3, 3, 31); 5011 date.add!"months"(85).add!"months"(-83); 5012 assert(date == Date(-3, 6, 1)); 5013 } 5014 5015 const cdate = Date(1999, 7, 6); 5016 immutable idate = Date(1999, 7, 6); 5017 static assert(!__traits(compiles, cdate.add!"months"(3))); 5018 static assert(!__traits(compiles, idate.add!"months"(3))); 5019 } 5020 5021 // Test add!"months"() with AllowDayOverflow.no 5022 @safe unittest 5023 { 5024 // Test A.D. 5025 { 5026 auto date = Date(1999, 7, 6); 5027 date.add!"months"(3, AllowDayOverflow.no); 5028 assert(date == Date(1999, 10, 6)); 5029 date.add!"months"(-4, AllowDayOverflow.no); 5030 assert(date == Date(1999, 6, 6)); 5031 } 5032 5033 { 5034 auto date = Date(1999, 7, 6); 5035 date.add!"months"(6, AllowDayOverflow.no); 5036 assert(date == Date(2000, 1, 6)); 5037 date.add!"months"(-6, AllowDayOverflow.no); 5038 assert(date == Date(1999, 7, 6)); 5039 } 5040 5041 { 5042 auto date = Date(1999, 7, 6); 5043 date.add!"months"(27, AllowDayOverflow.no); 5044 assert(date == Date(2001, 10, 6)); 5045 date.add!"months"(-28, AllowDayOverflow.no); 5046 assert(date == Date(1999, 6, 6)); 5047 } 5048 5049 { 5050 auto date = Date(1999, 5, 31); 5051 date.add!"months"(1, AllowDayOverflow.no); 5052 assert(date == Date(1999, 6, 30)); 5053 } 5054 5055 { 5056 auto date = Date(1999, 5, 31); 5057 date.add!"months"(-1, AllowDayOverflow.no); 5058 assert(date == Date(1999, 4, 30)); 5059 } 5060 5061 { 5062 auto date = Date(1999, 2, 28); 5063 date.add!"months"(12, AllowDayOverflow.no); 5064 assert(date == Date(2000, 2, 28)); 5065 } 5066 5067 { 5068 auto date = Date(2000, 2, 29); 5069 date.add!"months"(12, AllowDayOverflow.no); 5070 assert(date == Date(2001, 2, 28)); 5071 } 5072 5073 { 5074 auto date = Date(1999, 7, 31); 5075 date.add!"months"(1, AllowDayOverflow.no); 5076 assert(date == Date(1999, 8, 31)); 5077 date.add!"months"(1, AllowDayOverflow.no); 5078 assert(date == Date(1999, 9, 30)); 5079 } 5080 5081 { 5082 auto date = Date(1998, 8, 31); 5083 date.add!"months"(13, AllowDayOverflow.no); 5084 assert(date == Date(1999, 9, 30)); 5085 date.add!"months"(-13, AllowDayOverflow.no); 5086 assert(date == Date(1998, 8, 30)); 5087 } 5088 5089 { 5090 auto date = Date(1997, 12, 31); 5091 date.add!"months"(13, AllowDayOverflow.no); 5092 assert(date == Date(1999, 1, 31)); 5093 date.add!"months"(-13, AllowDayOverflow.no); 5094 assert(date == Date(1997, 12, 31)); 5095 } 5096 5097 { 5098 auto date = Date(1997, 12, 31); 5099 date.add!"months"(14, AllowDayOverflow.no); 5100 assert(date == Date(1999, 2, 28)); 5101 date.add!"months"(-14, AllowDayOverflow.no); 5102 assert(date == Date(1997, 12, 28)); 5103 } 5104 5105 { 5106 auto date = Date(1998, 12, 31); 5107 date.add!"months"(14, AllowDayOverflow.no); 5108 assert(date == Date(2000, 2, 29)); 5109 date.add!"months"(-14, AllowDayOverflow.no); 5110 assert(date == Date(1998, 12, 29)); 5111 } 5112 5113 { 5114 auto date = Date(1999, 12, 31); 5115 date.add!"months"(14, AllowDayOverflow.no); 5116 assert(date == Date(2001, 2, 28)); 5117 date.add!"months"(-14, AllowDayOverflow.no); 5118 assert(date == Date(1999, 12, 28)); 5119 } 5120 5121 // Test B.C. 5122 { 5123 auto date = Date(-1999, 7, 6); 5124 date.add!"months"(3, AllowDayOverflow.no); 5125 assert(date == Date(-1999, 10, 6)); 5126 date.add!"months"(-4, AllowDayOverflow.no); 5127 assert(date == Date(-1999, 6, 6)); 5128 } 5129 5130 { 5131 auto date = Date(-1999, 7, 6); 5132 date.add!"months"(6, AllowDayOverflow.no); 5133 assert(date == Date(-1998, 1, 6)); 5134 date.add!"months"(-6, AllowDayOverflow.no); 5135 assert(date == Date(-1999, 7, 6)); 5136 } 5137 5138 { 5139 auto date = Date(-1999, 7, 6); 5140 date.add!"months"(-27, AllowDayOverflow.no); 5141 assert(date == Date(-2001, 4, 6)); 5142 date.add!"months"(28, AllowDayOverflow.no); 5143 assert(date == Date(-1999, 8, 6)); 5144 } 5145 5146 { 5147 auto date = Date(-1999, 5, 31); 5148 date.add!"months"(1, AllowDayOverflow.no); 5149 assert(date == Date(-1999, 6, 30)); 5150 } 5151 5152 { 5153 auto date = Date(-1999, 5, 31); 5154 date.add!"months"(-1, AllowDayOverflow.no); 5155 assert(date == Date(-1999, 4, 30)); 5156 } 5157 5158 { 5159 auto date = Date(-1999, 2, 28); 5160 date.add!"months"(-12, AllowDayOverflow.no); 5161 assert(date == Date(-2000, 2, 28)); 5162 } 5163 5164 { 5165 auto date = Date(-2000, 2, 29); 5166 date.add!"months"(-12, AllowDayOverflow.no); 5167 assert(date == Date(-2001, 2, 28)); 5168 } 5169 5170 { 5171 auto date = Date(-1999, 7, 31); 5172 date.add!"months"(1, AllowDayOverflow.no); 5173 assert(date == Date(-1999, 8, 31)); 5174 date.add!"months"(1, AllowDayOverflow.no); 5175 assert(date == Date(-1999, 9, 30)); 5176 } 5177 5178 { 5179 auto date = Date(-1998, 8, 31); 5180 date.add!"months"(13, AllowDayOverflow.no); 5181 assert(date == Date(-1997, 9, 30)); 5182 date.add!"months"(-13, AllowDayOverflow.no); 5183 assert(date == Date(-1998, 8, 30)); 5184 } 5185 5186 { 5187 auto date = Date(-1997, 12, 31); 5188 date.add!"months"(13, AllowDayOverflow.no); 5189 assert(date == Date(-1995, 1, 31)); 5190 date.add!"months"(-13, AllowDayOverflow.no); 5191 assert(date == Date(-1997, 12, 31)); 5192 } 5193 5194 { 5195 auto date = Date(-1997, 12, 31); 5196 date.add!"months"(14, AllowDayOverflow.no); 5197 assert(date == Date(-1995, 2, 28)); 5198 date.add!"months"(-14, AllowDayOverflow.no); 5199 assert(date == Date(-1997, 12, 28)); 5200 } 5201 5202 { 5203 auto date = Date(-2002, 12, 31); 5204 date.add!"months"(14, AllowDayOverflow.no); 5205 assert(date == Date(-2000, 2, 29)); 5206 date.add!"months"(-14, AllowDayOverflow.no); 5207 assert(date == Date(-2002, 12, 29)); 5208 } 5209 5210 { 5211 auto date = Date(-2001, 12, 31); 5212 date.add!"months"(14, AllowDayOverflow.no); 5213 assert(date == Date(-1999, 2, 28)); 5214 date.add!"months"(-14, AllowDayOverflow.no); 5215 assert(date == Date(-2001, 12, 28)); 5216 } 5217 5218 // Test Both 5219 { 5220 auto date = Date(1, 1, 1); 5221 date.add!"months"(-1, AllowDayOverflow.no); 5222 assert(date == Date(0, 12, 1)); 5223 date.add!"months"(1, AllowDayOverflow.no); 5224 assert(date == Date(1, 1, 1)); 5225 } 5226 5227 { 5228 auto date = Date(4, 1, 1); 5229 date.add!"months"(-48, AllowDayOverflow.no); 5230 assert(date == Date(0, 1, 1)); 5231 date.add!"months"(48, AllowDayOverflow.no); 5232 assert(date == Date(4, 1, 1)); 5233 } 5234 5235 { 5236 auto date = Date(4, 3, 31); 5237 date.add!"months"(-49, AllowDayOverflow.no); 5238 assert(date == Date(0, 2, 29)); 5239 date.add!"months"(49, AllowDayOverflow.no); 5240 assert(date == Date(4, 3, 29)); 5241 } 5242 5243 { 5244 auto date = Date(4, 3, 31); 5245 date.add!"months"(-85, AllowDayOverflow.no); 5246 assert(date == Date(-3, 2, 28)); 5247 date.add!"months"(85, AllowDayOverflow.no); 5248 assert(date == Date(4, 3, 28)); 5249 } 5250 5251 { 5252 auto date = Date(-3, 3, 31); 5253 date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); 5254 assert(date == Date(-3, 5, 30)); 5255 } 5256 } 5257 5258 5259 /++ 5260 Adds the given number of years or months to this $(LREF Date), mutating 5261 it. A negative number will subtract. 5262 5263 The difference between rolling and adding is that rolling does not 5264 affect larger units. Rolling a $(LREF Date) 12 months gets 5265 the exact same $(LREF Date). However, the days can still be affected due 5266 to the differing number of days in each month. 5267 5268 Because there are no units larger than years, there is no difference 5269 between adding and rolling years. 5270 5271 Params: 5272 units = The type of units to add ("years" or "months"). 5273 value = The number of months or years to add to this 5274 $(LREF Date). 5275 allowOverflow = Whether the day should be allowed to overflow, 5276 causing the month to increment. 5277 5278 Returns: 5279 A reference to the `Date` (`this`). 5280 +/ 5281 @safe pure nothrow @nogc 5282 ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5283 if (units == "years") 5284 { 5285 return add!"years"(value, allowOverflow); 5286 } 5287 5288 /// 5289 @safe unittest 5290 { 5291 auto d1 = Date(2010, 1, 1); 5292 d1.roll!"months"(1); 5293 assert(d1 == Date(2010, 2, 1)); 5294 5295 auto d2 = Date(2010, 1, 1); 5296 d2.roll!"months"(-1); 5297 assert(d2 == Date(2010, 12, 1)); 5298 5299 auto d3 = Date(1999, 1, 29); 5300 d3.roll!"months"(1); 5301 assert(d3 == Date(1999, 3, 1)); 5302 5303 auto d4 = Date(1999, 1, 29); 5304 d4.roll!"months"(1, AllowDayOverflow.no); 5305 assert(d4 == Date(1999, 2, 28)); 5306 5307 auto d5 = Date(2000, 2, 29); 5308 d5.roll!"years"(1); 5309 assert(d5 == Date(2001, 3, 1)); 5310 5311 auto d6 = Date(2000, 2, 29); 5312 d6.roll!"years"(1, AllowDayOverflow.no); 5313 assert(d6 == Date(2001, 2, 28)); 5314 } 5315 5316 @safe unittest 5317 { 5318 const cdate = Date(1999, 7, 6); 5319 immutable idate = Date(1999, 7, 6); 5320 static assert(!__traits(compiles, cdate.roll!"years"(3))); 5321 static assert(!__traits(compiles, idate.rolYears(3))); 5322 } 5323 5324 5325 // Shares documentation with "years" version. 5326 @safe pure nothrow @nogc 5327 ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5328 if (units == "months") 5329 { 5330 months %= 12; 5331 auto newMonth = _month + months; 5332 5333 if (months < 0) 5334 { 5335 if (newMonth < 1) 5336 newMonth += 12; 5337 } 5338 else 5339 { 5340 if (newMonth > 12) 5341 newMonth -= 12; 5342 } 5343 5344 _month = cast(Month) newMonth; 5345 5346 immutable currMaxDay = maxDay(_year, _month); 5347 immutable overflow = _day - currMaxDay; 5348 5349 if (overflow > 0) 5350 { 5351 if (allowOverflow == AllowDayOverflow.yes) 5352 { 5353 ++_month; 5354 _day = cast(ubyte) overflow; 5355 } 5356 else 5357 _day = cast(ubyte) currMaxDay; 5358 } 5359 5360 return this; 5361 } 5362 5363 // Test roll!"months"() with AllowDayOverflow.yes 5364 @safe unittest 5365 { 5366 // Test A.D. 5367 { 5368 auto date = Date(1999, 7, 6); 5369 date.roll!"months"(3); 5370 assert(date == Date(1999, 10, 6)); 5371 date.roll!"months"(-4); 5372 assert(date == Date(1999, 6, 6)); 5373 } 5374 5375 { 5376 auto date = Date(1999, 7, 6); 5377 date.roll!"months"(6); 5378 assert(date == Date(1999, 1, 6)); 5379 date.roll!"months"(-6); 5380 assert(date == Date(1999, 7, 6)); 5381 } 5382 5383 { 5384 auto date = Date(1999, 7, 6); 5385 date.roll!"months"(27); 5386 assert(date == Date(1999, 10, 6)); 5387 date.roll!"months"(-28); 5388 assert(date == Date(1999, 6, 6)); 5389 } 5390 5391 { 5392 auto date = Date(1999, 5, 31); 5393 date.roll!"months"(1); 5394 assert(date == Date(1999, 7, 1)); 5395 } 5396 5397 { 5398 auto date = Date(1999, 5, 31); 5399 date.roll!"months"(-1); 5400 assert(date == Date(1999, 5, 1)); 5401 } 5402 5403 { 5404 auto date = Date(1999, 2, 28); 5405 date.roll!"months"(12); 5406 assert(date == Date(1999, 2, 28)); 5407 } 5408 5409 { 5410 auto date = Date(2000, 2, 29); 5411 date.roll!"months"(12); 5412 assert(date == Date(2000, 2, 29)); 5413 } 5414 5415 { 5416 auto date = Date(1999, 7, 31); 5417 date.roll!"months"(1); 5418 assert(date == Date(1999, 8, 31)); 5419 date.roll!"months"(1); 5420 assert(date == Date(1999, 10, 1)); 5421 } 5422 5423 { 5424 auto date = Date(1998, 8, 31); 5425 date.roll!"months"(13); 5426 assert(date == Date(1998, 10, 1)); 5427 date.roll!"months"(-13); 5428 assert(date == Date(1998, 9, 1)); 5429 } 5430 5431 { 5432 auto date = Date(1997, 12, 31); 5433 date.roll!"months"(13); 5434 assert(date == Date(1997, 1, 31)); 5435 date.roll!"months"(-13); 5436 assert(date == Date(1997, 12, 31)); 5437 } 5438 5439 { 5440 auto date = Date(1997, 12, 31); 5441 date.roll!"months"(14); 5442 assert(date == Date(1997, 3, 3)); 5443 date.roll!"months"(-14); 5444 assert(date == Date(1997, 1, 3)); 5445 } 5446 5447 { 5448 auto date = Date(1998, 12, 31); 5449 date.roll!"months"(14); 5450 assert(date == Date(1998, 3, 3)); 5451 date.roll!"months"(-14); 5452 assert(date == Date(1998, 1, 3)); 5453 } 5454 5455 { 5456 auto date = Date(1999, 12, 31); 5457 date.roll!"months"(14); 5458 assert(date == Date(1999, 3, 3)); 5459 date.roll!"months"(-14); 5460 assert(date == Date(1999, 1, 3)); 5461 } 5462 5463 // Test B.C. 5464 { 5465 auto date = Date(-1999, 7, 6); 5466 date.roll!"months"(3); 5467 assert(date == Date(-1999, 10, 6)); 5468 date.roll!"months"(-4); 5469 assert(date == Date(-1999, 6, 6)); 5470 } 5471 5472 { 5473 auto date = Date(-1999, 7, 6); 5474 date.roll!"months"(6); 5475 assert(date == Date(-1999, 1, 6)); 5476 date.roll!"months"(-6); 5477 assert(date == Date(-1999, 7, 6)); 5478 } 5479 5480 { 5481 auto date = Date(-1999, 7, 6); 5482 date.roll!"months"(-27); 5483 assert(date == Date(-1999, 4, 6)); 5484 date.roll!"months"(28); 5485 assert(date == Date(-1999, 8, 6)); 5486 } 5487 5488 { 5489 auto date = Date(-1999, 5, 31); 5490 date.roll!"months"(1); 5491 assert(date == Date(-1999, 7, 1)); 5492 } 5493 5494 { 5495 auto date = Date(-1999, 5, 31); 5496 date.roll!"months"(-1); 5497 assert(date == Date(-1999, 5, 1)); 5498 } 5499 5500 { 5501 auto date = Date(-1999, 2, 28); 5502 date.roll!"months"(-12); 5503 assert(date == Date(-1999, 2, 28)); 5504 } 5505 5506 { 5507 auto date = Date(-2000, 2, 29); 5508 date.roll!"months"(-12); 5509 assert(date == Date(-2000, 2, 29)); 5510 } 5511 5512 { 5513 auto date = Date(-1999, 7, 31); 5514 date.roll!"months"(1); 5515 assert(date == Date(-1999, 8, 31)); 5516 date.roll!"months"(1); 5517 assert(date == Date(-1999, 10, 1)); 5518 } 5519 5520 { 5521 auto date = Date(-1998, 8, 31); 5522 date.roll!"months"(13); 5523 assert(date == Date(-1998, 10, 1)); 5524 date.roll!"months"(-13); 5525 assert(date == Date(-1998, 9, 1)); 5526 } 5527 5528 { 5529 auto date = Date(-1997, 12, 31); 5530 date.roll!"months"(13); 5531 assert(date == Date(-1997, 1, 31)); 5532 date.roll!"months"(-13); 5533 assert(date == Date(-1997, 12, 31)); 5534 } 5535 5536 { 5537 auto date = Date(-1997, 12, 31); 5538 date.roll!"months"(14); 5539 assert(date == Date(-1997, 3, 3)); 5540 date.roll!"months"(-14); 5541 assert(date == Date(-1997, 1, 3)); 5542 } 5543 5544 { 5545 auto date = Date(-2002, 12, 31); 5546 date.roll!"months"(14); 5547 assert(date == Date(-2002, 3, 3)); 5548 date.roll!"months"(-14); 5549 assert(date == Date(-2002, 1, 3)); 5550 } 5551 5552 { 5553 auto date = Date(-2001, 12, 31); 5554 date.roll!"months"(14); 5555 assert(date == Date(-2001, 3, 3)); 5556 date.roll!"months"(-14); 5557 assert(date == Date(-2001, 1, 3)); 5558 } 5559 5560 // Test Both 5561 { 5562 auto date = Date(1, 1, 1); 5563 date.roll!"months"(-1); 5564 assert(date == Date(1, 12, 1)); 5565 date.roll!"months"(1); 5566 assert(date == Date(1, 1, 1)); 5567 } 5568 5569 { 5570 auto date = Date(4, 1, 1); 5571 date.roll!"months"(-48); 5572 assert(date == Date(4, 1, 1)); 5573 date.roll!"months"(48); 5574 assert(date == Date(4, 1, 1)); 5575 } 5576 5577 { 5578 auto date = Date(4, 3, 31); 5579 date.roll!"months"(-49); 5580 assert(date == Date(4, 3, 2)); 5581 date.roll!"months"(49); 5582 assert(date == Date(4, 4, 2)); 5583 } 5584 5585 { 5586 auto date = Date(4, 3, 31); 5587 date.roll!"months"(-85); 5588 assert(date == Date(4, 3, 2)); 5589 date.roll!"months"(85); 5590 assert(date == Date(4, 4, 2)); 5591 } 5592 5593 { 5594 auto date = Date(-1, 1, 1); 5595 date.roll!"months"(-1); 5596 assert(date == Date(-1, 12, 1)); 5597 date.roll!"months"(1); 5598 assert(date == Date(-1, 1, 1)); 5599 } 5600 5601 { 5602 auto date = Date(-4, 1, 1); 5603 date.roll!"months"(-48); 5604 assert(date == Date(-4, 1, 1)); 5605 date.roll!"months"(48); 5606 assert(date == Date(-4, 1, 1)); 5607 } 5608 5609 { 5610 auto date = Date(-4, 3, 31); 5611 date.roll!"months"(-49); 5612 assert(date == Date(-4, 3, 2)); 5613 date.roll!"months"(49); 5614 assert(date == Date(-4, 4, 2)); 5615 } 5616 5617 { 5618 auto date = Date(-4, 3, 31); 5619 date.roll!"months"(-85); 5620 assert(date == Date(-4, 3, 2)); 5621 date.roll!"months"(85); 5622 assert(date == Date(-4, 4, 2)); 5623 } 5624 5625 { 5626 auto date = Date(-3, 3, 31); 5627 date.roll!"months"(85).roll!"months"(-83); 5628 assert(date == Date(-3, 6, 1)); 5629 } 5630 5631 const cdate = Date(1999, 7, 6); 5632 immutable idate = Date(1999, 7, 6); 5633 static assert(!__traits(compiles, cdate.roll!"months"(3))); 5634 static assert(!__traits(compiles, idate.roll!"months"(3))); 5635 } 5636 5637 // Test roll!"months"() with AllowDayOverflow.no 5638 @safe unittest 5639 { 5640 // Test A.D. 5641 { 5642 auto date = Date(1999, 7, 6); 5643 date.roll!"months"(3, AllowDayOverflow.no); 5644 assert(date == Date(1999, 10, 6)); 5645 date.roll!"months"(-4, AllowDayOverflow.no); 5646 assert(date == Date(1999, 6, 6)); 5647 } 5648 5649 { 5650 auto date = Date(1999, 7, 6); 5651 date.roll!"months"(6, AllowDayOverflow.no); 5652 assert(date == Date(1999, 1, 6)); 5653 date.roll!"months"(-6, AllowDayOverflow.no); 5654 assert(date == Date(1999, 7, 6)); 5655 } 5656 5657 { 5658 auto date = Date(1999, 7, 6); 5659 date.roll!"months"(27, AllowDayOverflow.no); 5660 assert(date == Date(1999, 10, 6)); 5661 date.roll!"months"(-28, AllowDayOverflow.no); 5662 assert(date == Date(1999, 6, 6)); 5663 } 5664 5665 { 5666 auto date = Date(1999, 5, 31); 5667 date.roll!"months"(1, AllowDayOverflow.no); 5668 assert(date == Date(1999, 6, 30)); 5669 } 5670 5671 { 5672 auto date = Date(1999, 5, 31); 5673 date.roll!"months"(-1, AllowDayOverflow.no); 5674 assert(date == Date(1999, 4, 30)); 5675 } 5676 5677 { 5678 auto date = Date(1999, 2, 28); 5679 date.roll!"months"(12, AllowDayOverflow.no); 5680 assert(date == Date(1999, 2, 28)); 5681 } 5682 5683 { 5684 auto date = Date(2000, 2, 29); 5685 date.roll!"months"(12, AllowDayOverflow.no); 5686 assert(date == Date(2000, 2, 29)); 5687 } 5688 5689 { 5690 auto date = Date(1999, 7, 31); 5691 date.roll!"months"(1, AllowDayOverflow.no); 5692 assert(date == Date(1999, 8, 31)); 5693 date.roll!"months"(1, AllowDayOverflow.no); 5694 assert(date == Date(1999, 9, 30)); 5695 } 5696 5697 { 5698 auto date = Date(1998, 8, 31); 5699 date.roll!"months"(13, AllowDayOverflow.no); 5700 assert(date == Date(1998, 9, 30)); 5701 date.roll!"months"(-13, AllowDayOverflow.no); 5702 assert(date == Date(1998, 8, 30)); 5703 } 5704 5705 { 5706 auto date = Date(1997, 12, 31); 5707 date.roll!"months"(13, AllowDayOverflow.no); 5708 assert(date == Date(1997, 1, 31)); 5709 date.roll!"months"(-13, AllowDayOverflow.no); 5710 assert(date == Date(1997, 12, 31)); 5711 } 5712 5713 { 5714 auto date = Date(1997, 12, 31); 5715 date.roll!"months"(14, AllowDayOverflow.no); 5716 assert(date == Date(1997, 2, 28)); 5717 date.roll!"months"(-14, AllowDayOverflow.no); 5718 assert(date == Date(1997, 12, 28)); 5719 } 5720 5721 { 5722 auto date = Date(1998, 12, 31); 5723 date.roll!"months"(14, AllowDayOverflow.no); 5724 assert(date == Date(1998, 2, 28)); 5725 date.roll!"months"(-14, AllowDayOverflow.no); 5726 assert(date == Date(1998, 12, 28)); 5727 } 5728 5729 { 5730 auto date = Date(1999, 12, 31); 5731 date.roll!"months"(14, AllowDayOverflow.no); 5732 assert(date == Date(1999, 2, 28)); 5733 date.roll!"months"(-14, AllowDayOverflow.no); 5734 assert(date == Date(1999, 12, 28)); 5735 } 5736 5737 // Test B.C. 5738 { 5739 auto date = Date(-1999, 7, 6); 5740 date.roll!"months"(3, AllowDayOverflow.no); 5741 assert(date == Date(-1999, 10, 6)); 5742 date.roll!"months"(-4, AllowDayOverflow.no); 5743 assert(date == Date(-1999, 6, 6)); 5744 } 5745 5746 { 5747 auto date = Date(-1999, 7, 6); 5748 date.roll!"months"(6, AllowDayOverflow.no); 5749 assert(date == Date(-1999, 1, 6)); 5750 date.roll!"months"(-6, AllowDayOverflow.no); 5751 assert(date == Date(-1999, 7, 6)); 5752 } 5753 5754 { 5755 auto date = Date(-1999, 7, 6); 5756 date.roll!"months"(-27, AllowDayOverflow.no); 5757 assert(date == Date(-1999, 4, 6)); 5758 date.roll!"months"(28, AllowDayOverflow.no); 5759 assert(date == Date(-1999, 8, 6)); 5760 } 5761 5762 { 5763 auto date = Date(-1999, 5, 31); 5764 date.roll!"months"(1, AllowDayOverflow.no); 5765 assert(date == Date(-1999, 6, 30)); 5766 } 5767 5768 { 5769 auto date = Date(-1999, 5, 31); 5770 date.roll!"months"(-1, AllowDayOverflow.no); 5771 assert(date == Date(-1999, 4, 30)); 5772 } 5773 5774 { 5775 auto date = Date(-1999, 2, 28); 5776 date.roll!"months"(-12, AllowDayOverflow.no); 5777 assert(date == Date(-1999, 2, 28)); 5778 } 5779 5780 { 5781 auto date = Date(-2000, 2, 29); 5782 date.roll!"months"(-12, AllowDayOverflow.no); 5783 assert(date == Date(-2000, 2, 29)); 5784 } 5785 5786 { 5787 auto date = Date(-1999, 7, 31); 5788 date.roll!"months"(1, AllowDayOverflow.no); 5789 assert(date == Date(-1999, 8, 31)); 5790 date.roll!"months"(1, AllowDayOverflow.no); 5791 assert(date == Date(-1999, 9, 30)); 5792 } 5793 5794 { 5795 auto date = Date(-1998, 8, 31); 5796 date.roll!"months"(13, AllowDayOverflow.no); 5797 assert(date == Date(-1998, 9, 30)); 5798 date.roll!"months"(-13, AllowDayOverflow.no); 5799 assert(date == Date(-1998, 8, 30)); 5800 } 5801 5802 { 5803 auto date = Date(-1997, 12, 31); 5804 date.roll!"months"(13, AllowDayOverflow.no); 5805 assert(date == Date(-1997, 1, 31)); 5806 date.roll!"months"(-13, AllowDayOverflow.no); 5807 assert(date == Date(-1997, 12, 31)); 5808 } 5809 5810 { 5811 auto date = Date(-1997, 12, 31); 5812 date.roll!"months"(14, AllowDayOverflow.no); 5813 assert(date == Date(-1997, 2, 28)); 5814 date.roll!"months"(-14, AllowDayOverflow.no); 5815 assert(date == Date(-1997, 12, 28)); 5816 } 5817 5818 { 5819 auto date = Date(-2002, 12, 31); 5820 date.roll!"months"(14, AllowDayOverflow.no); 5821 assert(date == Date(-2002, 2, 28)); 5822 date.roll!"months"(-14, AllowDayOverflow.no); 5823 assert(date == Date(-2002, 12, 28)); 5824 } 5825 5826 { 5827 auto date = Date(-2001, 12, 31); 5828 date.roll!"months"(14, AllowDayOverflow.no); 5829 assert(date == Date(-2001, 2, 28)); 5830 date.roll!"months"(-14, AllowDayOverflow.no); 5831 assert(date == Date(-2001, 12, 28)); 5832 } 5833 5834 // Test Both 5835 { 5836 auto date = Date(1, 1, 1); 5837 date.roll!"months"(-1, AllowDayOverflow.no); 5838 assert(date == Date(1, 12, 1)); 5839 date.roll!"months"(1, AllowDayOverflow.no); 5840 assert(date == Date(1, 1, 1)); 5841 } 5842 5843 { 5844 auto date = Date(4, 1, 1); 5845 date.roll!"months"(-48, AllowDayOverflow.no); 5846 assert(date == Date(4, 1, 1)); 5847 date.roll!"months"(48, AllowDayOverflow.no); 5848 assert(date == Date(4, 1, 1)); 5849 } 5850 5851 { 5852 auto date = Date(4, 3, 31); 5853 date.roll!"months"(-49, AllowDayOverflow.no); 5854 assert(date == Date(4, 2, 29)); 5855 date.roll!"months"(49, AllowDayOverflow.no); 5856 assert(date == Date(4, 3, 29)); 5857 } 5858 5859 { 5860 auto date = Date(4, 3, 31); 5861 date.roll!"months"(-85, AllowDayOverflow.no); 5862 assert(date == Date(4, 2, 29)); 5863 date.roll!"months"(85, AllowDayOverflow.no); 5864 assert(date == Date(4, 3, 29)); 5865 } 5866 5867 { 5868 auto date = Date(-1, 1, 1); 5869 date.roll!"months"(-1, AllowDayOverflow.no); 5870 assert(date == Date(-1, 12, 1)); 5871 date.roll!"months"(1, AllowDayOverflow.no); 5872 assert(date == Date(-1, 1, 1)); 5873 } 5874 5875 { 5876 auto date = Date(-4, 1, 1); 5877 date.roll!"months"(-48, AllowDayOverflow.no); 5878 assert(date == Date(-4, 1, 1)); 5879 date.roll!"months"(48, AllowDayOverflow.no); 5880 assert(date == Date(-4, 1, 1)); 5881 } 5882 5883 { 5884 auto date = Date(-4, 3, 31); 5885 date.roll!"months"(-49, AllowDayOverflow.no); 5886 assert(date == Date(-4, 2, 29)); 5887 date.roll!"months"(49, AllowDayOverflow.no); 5888 assert(date == Date(-4, 3, 29)); 5889 } 5890 5891 { 5892 auto date = Date(-4, 3, 31); 5893 date.roll!"months"(-85, AllowDayOverflow.no); 5894 assert(date == Date(-4, 2, 29)); 5895 date.roll!"months"(85, AllowDayOverflow.no); 5896 assert(date == Date(-4, 3, 29)); 5897 } 5898 5899 { 5900 auto date = Date(-3, 3, 31); 5901 date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); 5902 assert(date == Date(-3, 5, 30)); 5903 } 5904 } 5905 5906 5907 /++ 5908 Adds the given number of units to this $(LREF Date), mutating it. A 5909 negative number will subtract. 5910 5911 The difference between rolling and adding is that rolling does not 5912 affect larger units. For instance, rolling a $(LREF Date) one 5913 year's worth of days gets the exact same $(LREF Date). 5914 5915 The only accepted units are `"days"`. 5916 5917 Params: 5918 units = The units to add. Must be `"days"`. 5919 days = The number of days to add to this $(LREF Date). 5920 5921 Returns: 5922 A reference to the `Date` (`this`). 5923 +/ 5924 ref Date roll(string units)(long days) @safe pure nothrow @nogc 5925 if (units == "days") 5926 { 5927 immutable limit = maxDay(_year, _month); 5928 days %= limit; 5929 auto newDay = _day + days; 5930 5931 if (days < 0) 5932 { 5933 if (newDay < 1) 5934 newDay += limit; 5935 } 5936 else if (newDay > limit) 5937 newDay -= limit; 5938 5939 _day = cast(ubyte) newDay; 5940 return this; 5941 } 5942 5943 /// 5944 @safe unittest 5945 { 5946 auto d = Date(2010, 1, 1); 5947 d.roll!"days"(1); 5948 assert(d == Date(2010, 1, 2)); 5949 d.roll!"days"(365); 5950 assert(d == Date(2010, 1, 26)); 5951 d.roll!"days"(-32); 5952 assert(d == Date(2010, 1, 25)); 5953 } 5954 5955 @safe unittest 5956 { 5957 // Test A.D. 5958 { 5959 auto date = Date(1999, 2, 28); 5960 date.roll!"days"(1); 5961 assert(date == Date(1999, 2, 1)); 5962 date.roll!"days"(-1); 5963 assert(date == Date(1999, 2, 28)); 5964 } 5965 5966 { 5967 auto date = Date(2000, 2, 28); 5968 date.roll!"days"(1); 5969 assert(date == Date(2000, 2, 29)); 5970 date.roll!"days"(1); 5971 assert(date == Date(2000, 2, 1)); 5972 date.roll!"days"(-1); 5973 assert(date == Date(2000, 2, 29)); 5974 } 5975 5976 { 5977 auto date = Date(1999, 6, 30); 5978 date.roll!"days"(1); 5979 assert(date == Date(1999, 6, 1)); 5980 date.roll!"days"(-1); 5981 assert(date == Date(1999, 6, 30)); 5982 } 5983 5984 { 5985 auto date = Date(1999, 7, 31); 5986 date.roll!"days"(1); 5987 assert(date == Date(1999, 7, 1)); 5988 date.roll!"days"(-1); 5989 assert(date == Date(1999, 7, 31)); 5990 } 5991 5992 { 5993 auto date = Date(1999, 1, 1); 5994 date.roll!"days"(-1); 5995 assert(date == Date(1999, 1, 31)); 5996 date.roll!"days"(1); 5997 assert(date == Date(1999, 1, 1)); 5998 } 5999 6000 { 6001 auto date = Date(1999, 7, 6); 6002 date.roll!"days"(9); 6003 assert(date == Date(1999, 7, 15)); 6004 date.roll!"days"(-11); 6005 assert(date == Date(1999, 7, 4)); 6006 date.roll!"days"(30); 6007 assert(date == Date(1999, 7, 3)); 6008 date.roll!"days"(-3); 6009 assert(date == Date(1999, 7, 31)); 6010 } 6011 6012 { 6013 auto date = Date(1999, 7, 6); 6014 date.roll!"days"(365); 6015 assert(date == Date(1999, 7, 30)); 6016 date.roll!"days"(-365); 6017 assert(date == Date(1999, 7, 6)); 6018 date.roll!"days"(366); 6019 assert(date == Date(1999, 7, 31)); 6020 date.roll!"days"(730); 6021 assert(date == Date(1999, 7, 17)); 6022 date.roll!"days"(-1096); 6023 assert(date == Date(1999, 7, 6)); 6024 } 6025 6026 { 6027 auto date = Date(1999, 2, 6); 6028 date.roll!"days"(365); 6029 assert(date == Date(1999, 2, 7)); 6030 date.roll!"days"(-365); 6031 assert(date == Date(1999, 2, 6)); 6032 date.roll!"days"(366); 6033 assert(date == Date(1999, 2, 8)); 6034 date.roll!"days"(730); 6035 assert(date == Date(1999, 2, 10)); 6036 date.roll!"days"(-1096); 6037 assert(date == Date(1999, 2, 6)); 6038 } 6039 6040 // Test B.C. 6041 { 6042 auto date = Date(-1999, 2, 28); 6043 date.roll!"days"(1); 6044 assert(date == Date(-1999, 2, 1)); 6045 date.roll!"days"(-1); 6046 assert(date == Date(-1999, 2, 28)); 6047 } 6048 6049 { 6050 auto date = Date(-2000, 2, 28); 6051 date.roll!"days"(1); 6052 assert(date == Date(-2000, 2, 29)); 6053 date.roll!"days"(1); 6054 assert(date == Date(-2000, 2, 1)); 6055 date.roll!"days"(-1); 6056 assert(date == Date(-2000, 2, 29)); 6057 } 6058 6059 { 6060 auto date = Date(-1999, 6, 30); 6061 date.roll!"days"(1); 6062 assert(date == Date(-1999, 6, 1)); 6063 date.roll!"days"(-1); 6064 assert(date == Date(-1999, 6, 30)); 6065 } 6066 6067 { 6068 auto date = Date(-1999, 7, 31); 6069 date.roll!"days"(1); 6070 assert(date == Date(-1999, 7, 1)); 6071 date.roll!"days"(-1); 6072 assert(date == Date(-1999, 7, 31)); 6073 } 6074 6075 { 6076 auto date = Date(-1999, 1, 1); 6077 date.roll!"days"(-1); 6078 assert(date == Date(-1999, 1, 31)); 6079 date.roll!"days"(1); 6080 assert(date == Date(-1999, 1, 1)); 6081 } 6082 6083 { 6084 auto date = Date(-1999, 7, 6); 6085 date.roll!"days"(9); 6086 assert(date == Date(-1999, 7, 15)); 6087 date.roll!"days"(-11); 6088 assert(date == Date(-1999, 7, 4)); 6089 date.roll!"days"(30); 6090 assert(date == Date(-1999, 7, 3)); 6091 date.roll!"days"(-3); 6092 assert(date == Date(-1999, 7, 31)); 6093 } 6094 6095 { 6096 auto date = Date(-1999, 7, 6); 6097 date.roll!"days"(365); 6098 assert(date == Date(-1999, 7, 30)); 6099 date.roll!"days"(-365); 6100 assert(date == Date(-1999, 7, 6)); 6101 date.roll!"days"(366); 6102 assert(date == Date(-1999, 7, 31)); 6103 date.roll!"days"(730); 6104 assert(date == Date(-1999, 7, 17)); 6105 date.roll!"days"(-1096); 6106 assert(date == Date(-1999, 7, 6)); 6107 } 6108 6109 // Test Both 6110 { 6111 auto date = Date(1, 7, 6); 6112 date.roll!"days"(-365); 6113 assert(date == Date(1, 7, 13)); 6114 date.roll!"days"(365); 6115 assert(date == Date(1, 7, 6)); 6116 date.roll!"days"(-731); 6117 assert(date == Date(1, 7, 19)); 6118 date.roll!"days"(730); 6119 assert(date == Date(1, 7, 5)); 6120 } 6121 6122 { 6123 auto date = Date(0, 7, 6); 6124 date.roll!"days"(-365); 6125 assert(date == Date(0, 7, 13)); 6126 date.roll!"days"(365); 6127 assert(date == Date(0, 7, 6)); 6128 date.roll!"days"(-731); 6129 assert(date == Date(0, 7, 19)); 6130 date.roll!"days"(730); 6131 assert(date == Date(0, 7, 5)); 6132 } 6133 6134 { 6135 auto date = Date(0, 7, 6); 6136 date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); 6137 assert(date == Date(0, 7, 8)); 6138 } 6139 6140 const cdate = Date(1999, 7, 6); 6141 immutable idate = Date(1999, 7, 6); 6142 static assert(!__traits(compiles, cdate.roll!"days"(12))); 6143 static assert(!__traits(compiles, idate.roll!"days"(12))); 6144 } 6145 6146 import core.time : Duration; 6147 /++ 6148 Gives the result of adding or subtracting a $(REF Duration, core,time) 6149 from this $(LREF Date). 6150 6151 The legal types of arithmetic for $(LREF Date) using this operator are 6152 6153 $(BOOKTABLE, 6154 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 6155 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 6156 $(TR $(TD Duration) $(TD +) $(TD Date) $(TD -->) $(TD Date)) 6157 ) 6158 6159 Params: 6160 duration = The $(REF Duration, core,time) to add to or subtract from 6161 this $(LREF Date). 6162 +/ 6163 Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 6164 if (op == "+" || op == "-") 6165 { 6166 Date retval = this; 6167 immutable days = duration.total!"days"; 6168 mixin("return retval._addDays(" ~ op ~ "days);"); 6169 } 6170 6171 6172 /// ditto 6173 Date opBinaryRight(string op)(Duration duration) const @safe pure nothrow @nogc 6174 if (op == "+") 6175 { 6176 return this + duration; 6177 } 6178 6179 /// 6180 @safe unittest 6181 { 6182 import core.time : days; 6183 6184 assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); 6185 assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); 6186 6187 assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); 6188 assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); 6189 6190 assert(Date(2004, 2, 26) + days(4) == days(4) + Date(2004, 2, 26)); 6191 } 6192 6193 @safe unittest 6194 { 6195 auto date = Date(1999, 7, 6); 6196 6197 import core.time : dur; 6198 assert(date + dur!"weeks"(7) == Date(1999, 8, 24)); 6199 assert(date + dur!"weeks"(-7) == Date(1999, 5, 18)); 6200 assert(date + dur!"days"(7) == Date(1999, 7, 13)); 6201 assert(date + dur!"days"(-7) == Date(1999, 6, 29)); 6202 6203 assert(date + dur!"hours"(24) == Date(1999, 7, 7)); 6204 assert(date + dur!"hours"(-24) == Date(1999, 7, 5)); 6205 assert(date + dur!"minutes"(1440) == Date(1999, 7, 7)); 6206 assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6207 assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6208 assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6209 assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6210 assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6211 assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6212 assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6213 assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6214 assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6215 6216 assert(date - dur!"weeks"(-7) == Date(1999, 8, 24)); 6217 assert(date - dur!"weeks"(7) == Date(1999, 5, 18)); 6218 assert(date - dur!"days"(-7) == Date(1999, 7, 13)); 6219 assert(date - dur!"days"(7) == Date(1999, 6, 29)); 6220 6221 assert(date - dur!"hours"(-24) == Date(1999, 7, 7)); 6222 assert(date - dur!"hours"(24) == Date(1999, 7, 5)); 6223 assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6224 assert(date - dur!"minutes"(1440) == Date(1999, 7, 5)); 6225 assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6226 assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6227 assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6228 assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6229 assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6230 assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6231 assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6232 assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6233 6234 auto duration = dur!"days"(12); 6235 const cdate = Date(1999, 7, 6); 6236 immutable idate = Date(1999, 7, 6); 6237 assert(date + duration == Date(1999, 7, 18)); 6238 assert(cdate + duration == Date(1999, 7, 18)); 6239 assert(idate + duration == Date(1999, 7, 18)); 6240 6241 assert(date - duration == Date(1999, 6, 24)); 6242 assert(cdate - duration == Date(1999, 6, 24)); 6243 assert(idate - duration == Date(1999, 6, 24)); 6244 } 6245 6246 6247 /++ 6248 Gives the result of adding or subtracting a $(REF Duration, core,time) 6249 from this $(LREF Date), as well as assigning the result to this 6250 $(LREF Date). 6251 6252 The legal types of arithmetic for $(LREF Date) using this operator are 6253 6254 $(BOOKTABLE, 6255 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 6256 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 6257 ) 6258 6259 Params: 6260 duration = The $(REF Duration, core,time) to add to or subtract from 6261 this $(LREF Date). 6262 +/ 6263 ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 6264 if (op == "+" || op == "-") 6265 { 6266 immutable days = duration.total!"days"; 6267 mixin("return _addDays(" ~ op ~ "days);"); 6268 } 6269 6270 @safe unittest 6271 { 6272 import core.time : dur; 6273 assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24)); 6274 assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18)); 6275 assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13)); 6276 assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29)); 6277 6278 assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7)); 6279 assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5)); 6280 assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7)); 6281 assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6282 assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6283 assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6284 assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6285 assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6286 assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6287 assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6288 assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6289 assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6290 6291 assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24)); 6292 assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18)); 6293 assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13)); 6294 assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29)); 6295 6296 assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7)); 6297 assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5)); 6298 assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6299 assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5)); 6300 assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6301 assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6302 assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6303 assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6304 assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6305 assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6306 assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6307 assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6308 6309 { 6310 auto date = Date(0, 1, 31); 6311 (date += dur!"days"(507)) += dur!"days"(-2); 6312 assert(date == Date(1, 6, 19)); 6313 } 6314 6315 auto duration = dur!"days"(12); 6316 auto date = Date(1999, 7, 6); 6317 const cdate = Date(1999, 7, 6); 6318 immutable idate = Date(1999, 7, 6); 6319 date += duration; 6320 static assert(!__traits(compiles, cdate += duration)); 6321 static assert(!__traits(compiles, idate += duration)); 6322 6323 date -= duration; 6324 static assert(!__traits(compiles, cdate -= duration)); 6325 static assert(!__traits(compiles, idate -= duration)); 6326 } 6327 6328 6329 /++ 6330 Gives the difference between two $(LREF Date)s. 6331 6332 The legal types of arithmetic for $(LREF Date) using this operator are 6333 6334 $(BOOKTABLE, 6335 $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration)) 6336 ) 6337 +/ 6338 Duration opBinary(string op)(Date rhs) const @safe pure nothrow @nogc 6339 if (op == "-") 6340 { 6341 import core.time : dur; 6342 return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal); 6343 } 6344 6345 @safe unittest 6346 { 6347 auto date = Date(1999, 7, 6); 6348 6349 import core.time : dur; 6350 assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365)); 6351 assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365)); 6352 assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31)); 6353 assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31)); 6354 assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1)); 6355 assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1)); 6356 6357 const cdate = Date(1999, 7, 6); 6358 immutable idate = Date(1999, 7, 6); 6359 assert(date - date == Duration.zero); 6360 assert(cdate - date == Duration.zero); 6361 assert(idate - date == Duration.zero); 6362 6363 assert(date - cdate == Duration.zero); 6364 assert(cdate - cdate == Duration.zero); 6365 assert(idate - cdate == Duration.zero); 6366 6367 assert(date - idate == Duration.zero); 6368 assert(cdate - idate == Duration.zero); 6369 assert(idate - idate == Duration.zero); 6370 } 6371 6372 6373 /++ 6374 Returns the difference between the two $(LREF Date)s in months. 6375 6376 To get the difference in years, subtract the year property 6377 of two $(LREF Date)s. To get the difference in days or weeks, 6378 subtract the $(LREF Date)s themselves and use the 6379 $(REF Duration, core,time) that results. Because converting between 6380 months and smaller units requires a specific date (which 6381 $(REF Duration, core,time)s don't have), getting the difference in 6382 months requires some math using both the year and month properties, so 6383 this is a convenience function for getting the difference in months. 6384 6385 Note that the number of days in the months or how far into the month 6386 either $(LREF Date) is is irrelevant. It is the difference in the month 6387 property combined with the difference in years * 12. So, for instance, 6388 December 31st and January 1st are one month apart just as December 1st 6389 and January 31st are one month apart. 6390 6391 Params: 6392 rhs = The $(LREF Date) to subtract from this one. 6393 +/ 6394 int diffMonths(Date rhs) const @safe pure nothrow @nogc 6395 { 6396 immutable yearDiff = _year - rhs._year; 6397 immutable monthDiff = _month - rhs._month; 6398 6399 return yearDiff * 12 + monthDiff; 6400 } 6401 6402 /// 6403 @safe unittest 6404 { 6405 assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); 6406 assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); 6407 assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); 6408 assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); 6409 } 6410 6411 @safe unittest 6412 { 6413 auto date = Date(1999, 7, 6); 6414 6415 // Test A.D. 6416 assert(date.diffMonths(Date(1998, 6, 5)) == 13); 6417 assert(date.diffMonths(Date(1998, 7, 5)) == 12); 6418 assert(date.diffMonths(Date(1998, 8, 5)) == 11); 6419 assert(date.diffMonths(Date(1998, 9, 5)) == 10); 6420 assert(date.diffMonths(Date(1998, 10, 5)) == 9); 6421 assert(date.diffMonths(Date(1998, 11, 5)) == 8); 6422 assert(date.diffMonths(Date(1998, 12, 5)) == 7); 6423 assert(date.diffMonths(Date(1999, 1, 5)) == 6); 6424 assert(date.diffMonths(Date(1999, 2, 6)) == 5); 6425 assert(date.diffMonths(Date(1999, 3, 6)) == 4); 6426 assert(date.diffMonths(Date(1999, 4, 6)) == 3); 6427 assert(date.diffMonths(Date(1999, 5, 6)) == 2); 6428 assert(date.diffMonths(Date(1999, 6, 6)) == 1); 6429 assert(date.diffMonths(date) == 0); 6430 assert(date.diffMonths(Date(1999, 8, 6)) == -1); 6431 assert(date.diffMonths(Date(1999, 9, 6)) == -2); 6432 assert(date.diffMonths(Date(1999, 10, 6)) == -3); 6433 assert(date.diffMonths(Date(1999, 11, 6)) == -4); 6434 assert(date.diffMonths(Date(1999, 12, 6)) == -5); 6435 assert(date.diffMonths(Date(2000, 1, 6)) == -6); 6436 assert(date.diffMonths(Date(2000, 2, 6)) == -7); 6437 assert(date.diffMonths(Date(2000, 3, 6)) == -8); 6438 assert(date.diffMonths(Date(2000, 4, 6)) == -9); 6439 assert(date.diffMonths(Date(2000, 5, 6)) == -10); 6440 assert(date.diffMonths(Date(2000, 6, 6)) == -11); 6441 assert(date.diffMonths(Date(2000, 7, 6)) == -12); 6442 assert(date.diffMonths(Date(2000, 8, 6)) == -13); 6443 6444 assert(Date(1998, 6, 5).diffMonths(date) == -13); 6445 assert(Date(1998, 7, 5).diffMonths(date) == -12); 6446 assert(Date(1998, 8, 5).diffMonths(date) == -11); 6447 assert(Date(1998, 9, 5).diffMonths(date) == -10); 6448 assert(Date(1998, 10, 5).diffMonths(date) == -9); 6449 assert(Date(1998, 11, 5).diffMonths(date) == -8); 6450 assert(Date(1998, 12, 5).diffMonths(date) == -7); 6451 assert(Date(1999, 1, 5).diffMonths(date) == -6); 6452 assert(Date(1999, 2, 6).diffMonths(date) == -5); 6453 assert(Date(1999, 3, 6).diffMonths(date) == -4); 6454 assert(Date(1999, 4, 6).diffMonths(date) == -3); 6455 assert(Date(1999, 5, 6).diffMonths(date) == -2); 6456 assert(Date(1999, 6, 6).diffMonths(date) == -1); 6457 assert(Date(1999, 8, 6).diffMonths(date) == 1); 6458 assert(Date(1999, 9, 6).diffMonths(date) == 2); 6459 assert(Date(1999, 10, 6).diffMonths(date) == 3); 6460 assert(Date(1999, 11, 6).diffMonths(date) == 4); 6461 assert(Date(1999, 12, 6).diffMonths(date) == 5); 6462 assert(Date(2000, 1, 6).diffMonths(date) == 6); 6463 assert(Date(2000, 2, 6).diffMonths(date) == 7); 6464 assert(Date(2000, 3, 6).diffMonths(date) == 8); 6465 assert(Date(2000, 4, 6).diffMonths(date) == 9); 6466 assert(Date(2000, 5, 6).diffMonths(date) == 10); 6467 assert(Date(2000, 6, 6).diffMonths(date) == 11); 6468 assert(Date(2000, 7, 6).diffMonths(date) == 12); 6469 assert(Date(2000, 8, 6).diffMonths(date) == 13); 6470 6471 assert(date.diffMonths(Date(1999, 6, 30)) == 1); 6472 assert(date.diffMonths(Date(1999, 7, 1)) == 0); 6473 assert(date.diffMonths(Date(1999, 7, 6)) == 0); 6474 assert(date.diffMonths(Date(1999, 7, 11)) == 0); 6475 assert(date.diffMonths(Date(1999, 7, 16)) == 0); 6476 assert(date.diffMonths(Date(1999, 7, 21)) == 0); 6477 assert(date.diffMonths(Date(1999, 7, 26)) == 0); 6478 assert(date.diffMonths(Date(1999, 7, 31)) == 0); 6479 assert(date.diffMonths(Date(1999, 8, 1)) == -1); 6480 6481 assert(date.diffMonths(Date(1990, 6, 30)) == 109); 6482 assert(date.diffMonths(Date(1990, 7, 1)) == 108); 6483 assert(date.diffMonths(Date(1990, 7, 6)) == 108); 6484 assert(date.diffMonths(Date(1990, 7, 11)) == 108); 6485 assert(date.diffMonths(Date(1990, 7, 16)) == 108); 6486 assert(date.diffMonths(Date(1990, 7, 21)) == 108); 6487 assert(date.diffMonths(Date(1990, 7, 26)) == 108); 6488 assert(date.diffMonths(Date(1990, 7, 31)) == 108); 6489 assert(date.diffMonths(Date(1990, 8, 1)) == 107); 6490 6491 assert(Date(1999, 6, 30).diffMonths(date) == -1); 6492 assert(Date(1999, 7, 1).diffMonths(date) == 0); 6493 assert(Date(1999, 7, 6).diffMonths(date) == 0); 6494 assert(Date(1999, 7, 11).diffMonths(date) == 0); 6495 assert(Date(1999, 7, 16).diffMonths(date) == 0); 6496 assert(Date(1999, 7, 21).diffMonths(date) == 0); 6497 assert(Date(1999, 7, 26).diffMonths(date) == 0); 6498 assert(Date(1999, 7, 31).diffMonths(date) == 0); 6499 assert(Date(1999, 8, 1).diffMonths(date) == 1); 6500 6501 assert(Date(1990, 6, 30).diffMonths(date) == -109); 6502 assert(Date(1990, 7, 1).diffMonths(date) == -108); 6503 assert(Date(1990, 7, 6).diffMonths(date) == -108); 6504 assert(Date(1990, 7, 11).diffMonths(date) == -108); 6505 assert(Date(1990, 7, 16).diffMonths(date) == -108); 6506 assert(Date(1990, 7, 21).diffMonths(date) == -108); 6507 assert(Date(1990, 7, 26).diffMonths(date) == -108); 6508 assert(Date(1990, 7, 31).diffMonths(date) == -108); 6509 assert(Date(1990, 8, 1).diffMonths(date) == -107); 6510 6511 // Test B.C. 6512 auto dateBC = Date(-1999, 7, 6); 6513 6514 assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13); 6515 assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12); 6516 assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11); 6517 assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10); 6518 assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9); 6519 assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8); 6520 assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7); 6521 assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6); 6522 assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5); 6523 assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4); 6524 assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3); 6525 assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2); 6526 assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1); 6527 assert(dateBC.diffMonths(dateBC) == 0); 6528 assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1); 6529 assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2); 6530 assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3); 6531 assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4); 6532 assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5); 6533 assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6); 6534 assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7); 6535 assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8); 6536 assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9); 6537 assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10); 6538 assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11); 6539 assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12); 6540 assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13); 6541 6542 assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13); 6543 assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12); 6544 assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11); 6545 assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10); 6546 assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9); 6547 assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8); 6548 assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7); 6549 assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6); 6550 assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5); 6551 assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4); 6552 assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3); 6553 assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2); 6554 assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1); 6555 assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1); 6556 assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2); 6557 assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3); 6558 assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4); 6559 assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5); 6560 assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6); 6561 assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7); 6562 assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8); 6563 assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9); 6564 assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10); 6565 assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11); 6566 assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12); 6567 assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13); 6568 6569 assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1); 6570 assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0); 6571 assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0); 6572 assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0); 6573 assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0); 6574 assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0); 6575 assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0); 6576 assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0); 6577 assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1); 6578 6579 assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109); 6580 assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108); 6581 assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108); 6582 assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108); 6583 assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108); 6584 assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108); 6585 assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108); 6586 assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108); 6587 assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107); 6588 6589 assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1); 6590 assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0); 6591 assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0); 6592 assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0); 6593 assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0); 6594 assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0); 6595 assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0); 6596 assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0); 6597 assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1); 6598 6599 assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109); 6600 assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108); 6601 assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108); 6602 assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108); 6603 assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108); 6604 assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108); 6605 assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108); 6606 assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108); 6607 assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107); 6608 6609 // Test Both 6610 assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94); 6611 assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94); 6612 6613 const cdate = Date(1999, 7, 6); 6614 immutable idate = Date(1999, 7, 6); 6615 assert(date.diffMonths(date) == 0); 6616 assert(cdate.diffMonths(date) == 0); 6617 assert(idate.diffMonths(date) == 0); 6618 6619 assert(date.diffMonths(cdate) == 0); 6620 assert(cdate.diffMonths(cdate) == 0); 6621 assert(idate.diffMonths(cdate) == 0); 6622 6623 assert(date.diffMonths(idate) == 0); 6624 assert(cdate.diffMonths(idate) == 0); 6625 assert(idate.diffMonths(idate) == 0); 6626 } 6627 6628 6629 /++ 6630 Whether this $(LREF Date) is in a leap year. 6631 +/ 6632 @property bool isLeapYear() const @safe pure nothrow @nogc 6633 { 6634 return yearIsLeapYear(_year); 6635 } 6636 6637 @safe unittest 6638 { 6639 auto date = Date(1999, 7, 6); 6640 const cdate = Date(1999, 7, 6); 6641 immutable idate = Date(1999, 7, 6); 6642 static assert(!__traits(compiles, date.isLeapYear = true)); 6643 static assert(!__traits(compiles, cdate.isLeapYear = true)); 6644 static assert(!__traits(compiles, idate.isLeapYear = true)); 6645 } 6646 6647 6648 /++ 6649 Day of the week this $(LREF Date) is on. 6650 +/ 6651 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 6652 { 6653 return getDayOfWeek(dayOfGregorianCal); 6654 } 6655 6656 @safe unittest 6657 { 6658 const cdate = Date(1999, 7, 6); 6659 immutable idate = Date(1999, 7, 6); 6660 assert(cdate.dayOfWeek == DayOfWeek.tue); 6661 static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun)); 6662 assert(idate.dayOfWeek == DayOfWeek.tue); 6663 static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun)); 6664 } 6665 6666 6667 /++ 6668 Day of the year this $(LREF Date) is on. 6669 +/ 6670 @property ushort dayOfYear() const @safe pure nothrow @nogc 6671 { 6672 if (_month >= Month.jan && _month <= Month.dec) 6673 { 6674 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6675 auto monthIndex = _month - Month.jan; 6676 6677 return cast(ushort)(lastDay[monthIndex] + _day); 6678 } 6679 assert(0, "Invalid month."); 6680 } 6681 6682 /// 6683 @safe unittest 6684 { 6685 assert(Date(1999, 1, 1).dayOfYear == 1); 6686 assert(Date(1999, 12, 31).dayOfYear == 365); 6687 assert(Date(2000, 12, 31).dayOfYear == 366); 6688 } 6689 6690 @safe unittest 6691 { 6692 import std.algorithm.iteration : filter; 6693 import std.range : chain; 6694 6695 foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6696 { 6697 foreach (doy; testDaysOfYear) 6698 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6699 } 6700 6701 foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6702 { 6703 foreach (doy; testDaysOfLeapYear) 6704 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6705 } 6706 6707 const cdate = Date(1999, 7, 6); 6708 immutable idate = Date(1999, 7, 6); 6709 assert(cdate.dayOfYear == 187); 6710 assert(idate.dayOfYear == 187); 6711 } 6712 6713 /++ 6714 Day of the year. 6715 6716 Params: 6717 day = The day of the year to set which day of the year this 6718 $(LREF Date) is on. 6719 6720 Throws: 6721 $(REF DateTimeException,std,datetime,date) if the given day is an 6722 invalid day of the year. 6723 +/ 6724 @property void dayOfYear(int day) @safe pure 6725 { 6726 setDayOfYear!true(day); 6727 } 6728 6729 private void setDayOfYear(bool useExceptions = false)(int day) 6730 { 6731 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6732 6733 bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear); 6734 enum errorMsg = "Invalid day of the year."; 6735 6736 static if (useExceptions) 6737 { 6738 if (dayOutOfRange) throw new DateTimeException(errorMsg); 6739 } 6740 else 6741 { 6742 assert(!dayOutOfRange, errorMsg); 6743 } 6744 6745 foreach (i; 1 .. lastDay.length) 6746 { 6747 if (day <= lastDay[i]) 6748 { 6749 _month = cast(Month)(cast(int) Month.jan + i - 1); 6750 _day = cast(ubyte)(day - lastDay[i - 1]); 6751 return; 6752 } 6753 } 6754 assert(0, "Invalid day of the year."); 6755 } 6756 6757 @safe unittest 6758 { 6759 static void test(Date date, int day, MonthDay expected, size_t line = __LINE__) 6760 { 6761 date.dayOfYear = day; 6762 assert(date.month == expected.month); 6763 assert(date.day == expected.day); 6764 } 6765 6766 foreach (doy; testDaysOfYear) 6767 { 6768 test(Date(1999, 1, 1), doy.day, doy.md); 6769 test(Date(-1, 1, 1), doy.day, doy.md); 6770 } 6771 6772 foreach (doy; testDaysOfLeapYear) 6773 { 6774 test(Date(2000, 1, 1), doy.day, doy.md); 6775 test(Date(-4, 1, 1), doy.day, doy.md); 6776 } 6777 6778 const cdate = Date(1999, 7, 6); 6779 immutable idate = Date(1999, 7, 6); 6780 static assert(!__traits(compiles, cdate.dayOfYear = 187)); 6781 static assert(!__traits(compiles, idate.dayOfYear = 187)); 6782 } 6783 6784 6785 /++ 6786 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6787 +/ 6788 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 6789 { 6790 if (isAD) 6791 { 6792 if (_year == 1) 6793 return dayOfYear; 6794 6795 int years = _year - 1; 6796 auto days = (years / 400) * daysIn400Years; 6797 years %= 400; 6798 6799 days += (years / 100) * daysIn100Years; 6800 years %= 100; 6801 6802 days += (years / 4) * daysIn4Years; 6803 years %= 4; 6804 6805 days += years * daysInYear; 6806 6807 days += dayOfYear; 6808 6809 return days; 6810 } 6811 else if (_year == 0) 6812 return dayOfYear - daysInLeapYear; 6813 else 6814 { 6815 int years = _year; 6816 auto days = (years / 400) * daysIn400Years; 6817 years %= 400; 6818 6819 days += (years / 100) * daysIn100Years; 6820 years %= 100; 6821 6822 days += (years / 4) * daysIn4Years; 6823 years %= 4; 6824 6825 if (years < 0) 6826 { 6827 days -= daysInLeapYear; 6828 ++years; 6829 6830 days += years * daysInYear; 6831 6832 days -= daysInYear - dayOfYear; 6833 } 6834 else 6835 days -= daysInLeapYear - dayOfYear; 6836 6837 return days; 6838 } 6839 } 6840 6841 /// 6842 @safe unittest 6843 { 6844 assert(Date(1, 1, 1).dayOfGregorianCal == 1); 6845 assert(Date(1, 12, 31).dayOfGregorianCal == 365); 6846 assert(Date(2, 1, 1).dayOfGregorianCal == 366); 6847 6848 assert(Date(0, 12, 31).dayOfGregorianCal == 0); 6849 assert(Date(0, 1, 1).dayOfGregorianCal == -365); 6850 assert(Date(-1, 12, 31).dayOfGregorianCal == -366); 6851 6852 assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); 6853 assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); 6854 } 6855 6856 @safe unittest 6857 { 6858 import std.range : chain; 6859 6860 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 6861 assert(gd.date.dayOfGregorianCal == gd.day); 6862 6863 auto date = Date(1999, 7, 6); 6864 const cdate = Date(1999, 7, 6); 6865 immutable idate = Date(1999, 7, 6); 6866 assert(date.dayOfGregorianCal == 729_941); 6867 assert(cdate.dayOfGregorianCal == 729_941); 6868 assert(idate.dayOfGregorianCal == 729_941); 6869 } 6870 6871 /++ 6872 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6873 6874 Params: 6875 day = The day of the Gregorian Calendar to set this $(LREF Date) to. 6876 +/ 6877 @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc 6878 { 6879 this = Date(day); 6880 } 6881 6882 /// 6883 @safe unittest 6884 { 6885 auto date = Date.init; 6886 date.dayOfGregorianCal = 1; 6887 assert(date == Date(1, 1, 1)); 6888 6889 date.dayOfGregorianCal = 365; 6890 assert(date == Date(1, 12, 31)); 6891 6892 date.dayOfGregorianCal = 366; 6893 assert(date == Date(2, 1, 1)); 6894 6895 date.dayOfGregorianCal = 0; 6896 assert(date == Date(0, 12, 31)); 6897 6898 date.dayOfGregorianCal = -365; 6899 assert(date == Date(-0, 1, 1)); 6900 6901 date.dayOfGregorianCal = -366; 6902 assert(date == Date(-1, 12, 31)); 6903 6904 date.dayOfGregorianCal = 730_120; 6905 assert(date == Date(2000, 1, 1)); 6906 6907 date.dayOfGregorianCal = 734_137; 6908 assert(date == Date(2010, 12, 31)); 6909 } 6910 6911 @safe unittest 6912 { 6913 auto date = Date(1999, 7, 6); 6914 const cdate = Date(1999, 7, 6); 6915 immutable idate = Date(1999, 7, 6); 6916 date.dayOfGregorianCal = 187; 6917 assert(date.dayOfGregorianCal == 187); 6918 static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187)); 6919 static assert(!__traits(compiles, idate.dayOfGregorianCal = 187)); 6920 } 6921 6922 6923 /++ 6924 The ISO 8601 week and year of the year that this $(LREF Date) is in. 6925 6926 Returns: 6927 An anonymous struct with the members $(D isoWeekYear) for the 6928 resulting year and $(D isoWeek) for the resulting ISO week. 6929 6930 See_Also: 6931 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 6932 +/ 6933 @property auto isoWeekAndYear() const @safe pure nothrow 6934 { 6935 struct ISOWeekAndYear { short isoWeekYear; ubyte isoWeek; } 6936 6937 immutable weekday = dayOfWeek; 6938 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; 6939 immutable week = (dayOfYear - adjustedWeekday + 10) / 7; 6940 6941 try 6942 { 6943 if (week == 53) 6944 { 6945 switch (Date(_year + 1, 1, 1).dayOfWeek) 6946 { 6947 case DayOfWeek.mon: 6948 case DayOfWeek.tue: 6949 case DayOfWeek.wed: 6950 case DayOfWeek.thu: 6951 return ISOWeekAndYear(cast(short) (_year + 1), 1); 6952 case DayOfWeek.fri: 6953 case DayOfWeek.sat: 6954 case DayOfWeek.sun: 6955 return ISOWeekAndYear(_year, 53); 6956 default: 6957 assert(0, "Invalid ISO Week"); 6958 } 6959 } 6960 else if (week > 0) 6961 return ISOWeekAndYear(_year, cast(ubyte) week); 6962 else 6963 return Date(_year - 1, 12, 31).isoWeekAndYear; 6964 } 6965 catch (Exception e) 6966 assert(0, "Date's constructor threw."); 6967 } 6968 6969 /++ 6970 The ISO 8601 week of the year that this $(LREF Date) is in. 6971 6972 See_Also: 6973 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 6974 +/ 6975 @property ubyte isoWeek() const @safe pure nothrow 6976 { 6977 return isoWeekAndYear().isoWeek; 6978 } 6979 6980 @safe unittest 6981 { 6982 // Test A.D. 6983 assert(Date(2009, 12, 28).isoWeek == 53); 6984 assert(Date(2009, 12, 29).isoWeek == 53); 6985 assert(Date(2009, 12, 30).isoWeek == 53); 6986 assert(Date(2009, 12, 31).isoWeek == 53); 6987 assert(Date(2010, 1, 1).isoWeek == 53); 6988 assert(Date(2010, 1, 2).isoWeek == 53); 6989 assert(Date(2010, 1, 3).isoWeek == 53); 6990 assert(Date(2010, 1, 4).isoWeek == 1); 6991 assert(Date(2010, 1, 5).isoWeek == 1); 6992 assert(Date(2010, 1, 6).isoWeek == 1); 6993 assert(Date(2010, 1, 7).isoWeek == 1); 6994 assert(Date(2010, 1, 8).isoWeek == 1); 6995 assert(Date(2010, 1, 9).isoWeek == 1); 6996 assert(Date(2010, 1, 10).isoWeek == 1); 6997 assert(Date(2010, 1, 11).isoWeek == 2); 6998 assert(Date(2010, 12, 31).isoWeek == 52); 6999 7000 assert(Date(2004, 12, 26).isoWeek == 52); 7001 assert(Date(2004, 12, 27).isoWeek == 53); 7002 assert(Date(2004, 12, 28).isoWeek == 53); 7003 assert(Date(2004, 12, 29).isoWeek == 53); 7004 assert(Date(2004, 12, 30).isoWeek == 53); 7005 assert(Date(2004, 12, 31).isoWeek == 53); 7006 assert(Date(2005, 1, 1).isoWeek == 53); 7007 assert(Date(2005, 1, 2).isoWeek == 53); 7008 7009 assert(Date(2005, 12, 31).isoWeek == 52); 7010 assert(Date(2007, 1, 1).isoWeek == 1); 7011 7012 assert(Date(2007, 12, 30).isoWeek == 52); 7013 assert(Date(2007, 12, 31).isoWeek == 1); 7014 assert(Date(2008, 1, 1).isoWeek == 1); 7015 7016 assert(Date(2008, 12, 28).isoWeek == 52); 7017 assert(Date(2008, 12, 29).isoWeek == 1); 7018 assert(Date(2008, 12, 30).isoWeek == 1); 7019 assert(Date(2008, 12, 31).isoWeek == 1); 7020 assert(Date(2009, 1, 1).isoWeek == 1); 7021 assert(Date(2009, 1, 2).isoWeek == 1); 7022 assert(Date(2009, 1, 3).isoWeek == 1); 7023 assert(Date(2009, 1, 4).isoWeek == 1); 7024 7025 // Test B.C. 7026 // The algorithm should work identically for both A.D. and B.C. since 7027 // it doesn't really take the year into account, so B.C. testing 7028 // probably isn't really needed. 7029 assert(Date(0, 12, 31).isoWeek == 52); 7030 assert(Date(0, 1, 4).isoWeek == 1); 7031 assert(Date(0, 1, 1).isoWeek == 52); 7032 7033 const cdate = Date(1999, 7, 6); 7034 immutable idate = Date(1999, 7, 6); 7035 assert(cdate.isoWeek == 27); 7036 static assert(!__traits(compiles, cdate.isoWeek = 3)); 7037 assert(idate.isoWeek == 27); 7038 static assert(!__traits(compiles, idate.isoWeek = 3)); 7039 } 7040 7041 /++ 7042 The year inside the ISO 8601 week calendar that this $(LREF Date) is in. 7043 7044 May differ from $(LREF year) between 28 December and 4 January. 7045 7046 See_Also: 7047 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 7048 +/ 7049 @property short isoWeekYear() const @safe pure nothrow 7050 { 7051 return isoWeekAndYear().isoWeekYear; 7052 } 7053 7054 @safe unittest 7055 { 7056 // Test A.D. 7057 assert(Date(2009, 12, 28).isoWeekYear == 2009); 7058 assert(Date(2009, 12, 29).isoWeekYear == 2009); 7059 assert(Date(2009, 12, 30).isoWeekYear == 2009); 7060 assert(Date(2009, 12, 31).isoWeekYear == 2009); 7061 assert(Date(2010, 1, 1).isoWeekYear == 2009); 7062 assert(Date(2010, 1, 2).isoWeekYear == 2009); 7063 assert(Date(2010, 1, 3).isoWeekYear == 2009); 7064 assert(Date(2010, 1, 4).isoWeekYear == 2010); 7065 assert(Date(2010, 1, 5).isoWeekYear == 2010); 7066 assert(Date(2010, 1, 6).isoWeekYear == 2010); 7067 assert(Date(2010, 1, 7).isoWeekYear == 2010); 7068 assert(Date(2010, 1, 8).isoWeekYear == 2010); 7069 assert(Date(2010, 1, 9).isoWeekYear == 2010); 7070 assert(Date(2010, 1, 10).isoWeekYear == 2010); 7071 assert(Date(2010, 1, 11).isoWeekYear == 2010); 7072 assert(Date(2010, 12, 31).isoWeekYear == 2010); 7073 7074 assert(Date(2004, 12, 26).isoWeekYear == 2004); 7075 assert(Date(2004, 12, 27).isoWeekYear == 2004); 7076 assert(Date(2004, 12, 28).isoWeekYear == 2004); 7077 assert(Date(2004, 12, 29).isoWeekYear == 2004); 7078 assert(Date(2004, 12, 30).isoWeekYear == 2004); 7079 assert(Date(2004, 12, 31).isoWeekYear == 2004); 7080 assert(Date(2005, 1, 1).isoWeekYear == 2004); 7081 assert(Date(2005, 1, 2).isoWeekYear == 2004); 7082 assert(Date(2005, 1, 3).isoWeekYear == 2005); 7083 7084 assert(Date(2005, 12, 31).isoWeekYear == 2005); 7085 assert(Date(2007, 1, 1).isoWeekYear == 2007); 7086 7087 assert(Date(2007, 12, 30).isoWeekYear == 2007); 7088 assert(Date(2007, 12, 31).isoWeekYear == 2008); 7089 assert(Date(2008, 1, 1).isoWeekYear == 2008); 7090 7091 assert(Date(2008, 12, 28).isoWeekYear == 2008); 7092 assert(Date(2008, 12, 29).isoWeekYear == 2009); 7093 assert(Date(2008, 12, 30).isoWeekYear == 2009); 7094 assert(Date(2008, 12, 31).isoWeekYear == 2009); 7095 assert(Date(2009, 1, 1).isoWeekYear == 2009); 7096 assert(Date(2009, 1, 2).isoWeekYear == 2009); 7097 assert(Date(2009, 1, 3).isoWeekYear == 2009); 7098 assert(Date(2009, 1, 4).isoWeekYear == 2009); 7099 7100 // Test B.C. 7101 assert(Date(0, 12, 31).isoWeekYear == 0); 7102 assert(Date(0, 1, 4).isoWeekYear == 0); 7103 assert(Date(0, 1, 1).isoWeekYear == -1); 7104 7105 const cdate = Date(1999, 7, 6); 7106 immutable idate = Date(1999, 7, 6); 7107 assert(cdate.isoWeekYear == 1999); 7108 assert(idate.isoWeekYear == 1999); 7109 } 7110 7111 static Date fromISOWeek(short isoWeekYear, ubyte isoWeek, DayOfWeek weekday) @safe pure nothrow @nogc 7112 { 7113 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; 7114 immutable dayOffset = (isoWeek - 1) * 7 + adjustedWeekday; 7115 7116 Date date; 7117 date._year = isoWeekYear; 7118 date._month = Month.jan; 7119 date._day = 3; 7120 immutable startOfYear = date.dayOfWeek; 7121 return date._addDays(dayOffset - startOfYear); 7122 } 7123 7124 @safe unittest 7125 { 7126 // Test -30000 days to 30000 days for matching construction <-> deconstruction 7127 Date date = Date(1, 1, 1); 7128 date._addDays(-30_000); 7129 foreach (day; 0 .. 60_000) 7130 { 7131 const year = date.isoWeekYear; 7132 const dow = date.dayOfWeek; 7133 const isoWeek = date.isoWeek; 7134 const reversed = Date.fromISOWeek(year, isoWeek, dow); 7135 assert(reversed == date, date.toISOExtString ~ " != " ~ reversed.toISOExtString); 7136 date = date._addDays(1); 7137 } 7138 } 7139 7140 7141 /++ 7142 $(LREF Date) for the last day in the month that this $(LREF Date) is in. 7143 +/ 7144 @property Date endOfMonth() const @safe pure nothrow 7145 { 7146 try 7147 return Date(_year, _month, maxDay(_year, _month)); 7148 catch (Exception e) 7149 assert(0, "Date's constructor threw."); 7150 } 7151 7152 /// 7153 @safe unittest 7154 { 7155 assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); 7156 assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); 7157 assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); 7158 assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); 7159 } 7160 7161 @safe unittest 7162 { 7163 // Test A.D. 7164 assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31)); 7165 assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28)); 7166 assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29)); 7167 assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31)); 7168 assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30)); 7169 assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31)); 7170 assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30)); 7171 assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31)); 7172 assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31)); 7173 assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30)); 7174 assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31)); 7175 assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30)); 7176 assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31)); 7177 7178 // Test B.C. 7179 assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31)); 7180 assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28)); 7181 assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29)); 7182 assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31)); 7183 assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30)); 7184 assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31)); 7185 assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30)); 7186 assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31)); 7187 assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31)); 7188 assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30)); 7189 assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31)); 7190 assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30)); 7191 assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31)); 7192 7193 const cdate = Date(1999, 7, 6); 7194 immutable idate = Date(1999, 7, 6); 7195 static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30))); 7196 static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30))); 7197 } 7198 7199 7200 /++ 7201 The last day in the month that this $(LREF Date) is in. 7202 +/ 7203 @property ubyte daysInMonth() const @safe pure nothrow @nogc 7204 { 7205 return maxDay(_year, _month); 7206 } 7207 7208 /// 7209 @safe unittest 7210 { 7211 assert(Date(1999, 1, 6).daysInMonth == 31); 7212 assert(Date(1999, 2, 7).daysInMonth == 28); 7213 assert(Date(2000, 2, 7).daysInMonth == 29); 7214 assert(Date(2000, 6, 4).daysInMonth == 30); 7215 } 7216 7217 @safe unittest 7218 { 7219 // Test A.D. 7220 assert(Date(1999, 1, 1).daysInMonth == 31); 7221 assert(Date(1999, 2, 1).daysInMonth == 28); 7222 assert(Date(2000, 2, 1).daysInMonth == 29); 7223 assert(Date(1999, 3, 1).daysInMonth == 31); 7224 assert(Date(1999, 4, 1).daysInMonth == 30); 7225 assert(Date(1999, 5, 1).daysInMonth == 31); 7226 assert(Date(1999, 6, 1).daysInMonth == 30); 7227 assert(Date(1999, 7, 1).daysInMonth == 31); 7228 assert(Date(1999, 8, 1).daysInMonth == 31); 7229 assert(Date(1999, 9, 1).daysInMonth == 30); 7230 assert(Date(1999, 10, 1).daysInMonth == 31); 7231 assert(Date(1999, 11, 1).daysInMonth == 30); 7232 assert(Date(1999, 12, 1).daysInMonth == 31); 7233 7234 // Test B.C. 7235 assert(Date(-1999, 1, 1).daysInMonth == 31); 7236 assert(Date(-1999, 2, 1).daysInMonth == 28); 7237 assert(Date(-2000, 2, 1).daysInMonth == 29); 7238 assert(Date(-1999, 3, 1).daysInMonth == 31); 7239 assert(Date(-1999, 4, 1).daysInMonth == 30); 7240 assert(Date(-1999, 5, 1).daysInMonth == 31); 7241 assert(Date(-1999, 6, 1).daysInMonth == 30); 7242 assert(Date(-1999, 7, 1).daysInMonth == 31); 7243 assert(Date(-1999, 8, 1).daysInMonth == 31); 7244 assert(Date(-1999, 9, 1).daysInMonth == 30); 7245 assert(Date(-1999, 10, 1).daysInMonth == 31); 7246 assert(Date(-1999, 11, 1).daysInMonth == 30); 7247 assert(Date(-1999, 12, 1).daysInMonth == 31); 7248 7249 const cdate = Date(1999, 7, 6); 7250 immutable idate = Date(1999, 7, 6); 7251 static assert(!__traits(compiles, cdate.daysInMonth = 30)); 7252 static assert(!__traits(compiles, idate.daysInMonth = 30)); 7253 } 7254 7255 7256 /++ 7257 Whether the current year is a date in A.D. 7258 +/ 7259 @property bool isAD() const @safe pure nothrow @nogc 7260 { 7261 return _year > 0; 7262 } 7263 7264 /// 7265 @safe unittest 7266 { 7267 assert(Date(1, 1, 1).isAD); 7268 assert(Date(2010, 12, 31).isAD); 7269 assert(!Date(0, 12, 31).isAD); 7270 assert(!Date(-2010, 1, 1).isAD); 7271 } 7272 7273 @safe unittest 7274 { 7275 assert(Date(2010, 7, 4).isAD); 7276 assert(Date(1, 1, 1).isAD); 7277 assert(!Date(0, 1, 1).isAD); 7278 assert(!Date(-1, 1, 1).isAD); 7279 assert(!Date(-2010, 7, 4).isAD); 7280 7281 const cdate = Date(1999, 7, 6); 7282 immutable idate = Date(1999, 7, 6); 7283 assert(cdate.isAD); 7284 assert(idate.isAD); 7285 } 7286 7287 7288 /++ 7289 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 7290 $(LREF Date) at noon (since the Julian day changes at noon). 7291 +/ 7292 @property long julianDay() const @safe pure nothrow @nogc 7293 { 7294 return dayOfGregorianCal + 1_721_425; 7295 } 7296 7297 @safe unittest 7298 { 7299 assert(Date(-4713, 11, 24).julianDay == 0); 7300 assert(Date(0, 12, 31).julianDay == 1_721_425); 7301 assert(Date(1, 1, 1).julianDay == 1_721_426); 7302 assert(Date(1582, 10, 15).julianDay == 2_299_161); 7303 assert(Date(1858, 11, 17).julianDay == 2_400_001); 7304 assert(Date(1982, 1, 4).julianDay == 2_444_974); 7305 assert(Date(1996, 3, 31).julianDay == 2_450_174); 7306 assert(Date(2010, 8, 24).julianDay == 2_455_433); 7307 7308 const cdate = Date(1999, 7, 6); 7309 immutable idate = Date(1999, 7, 6); 7310 assert(cdate.julianDay == 2_451_366); 7311 assert(idate.julianDay == 2_451_366); 7312 } 7313 7314 7315 /++ 7316 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for 7317 any time on this date (since, the modified Julian day changes at 7318 midnight). 7319 +/ 7320 @property long modJulianDay() const @safe pure nothrow @nogc 7321 { 7322 return julianDay - 2_400_001; 7323 } 7324 7325 @safe unittest 7326 { 7327 assert(Date(1858, 11, 17).modJulianDay == 0); 7328 assert(Date(2010, 8, 24).modJulianDay == 55_432); 7329 7330 const cdate = Date(1999, 7, 6); 7331 immutable idate = Date(1999, 7, 6); 7332 assert(cdate.modJulianDay == 51_365); 7333 assert(idate.modJulianDay == 51_365); 7334 } 7335 7336 7337 /++ 7338 Converts this $(LREF Date) to a string with the format `YYYYMMDD`. 7339 If `writer` is set, the resulting string will be written directly 7340 to it. 7341 7342 Params: 7343 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7344 Returns: 7345 A `string` when not using an output range; `void` otherwise. 7346 +/ 7347 string toISOString() const @safe pure nothrow 7348 { 7349 import std.array : appender; 7350 auto w = appender!string(); 7351 w.reserve(8); 7352 try 7353 toISOString(w); 7354 catch (Exception e) 7355 assert(0, "toISOString() threw."); 7356 return w.data; 7357 } 7358 7359 /// 7360 @safe unittest 7361 { 7362 assert(Date(2010, 7, 4).toISOString() == "20100704"); 7363 assert(Date(1998, 12, 25).toISOString() == "19981225"); 7364 assert(Date(0, 1, 5).toISOString() == "00000105"); 7365 assert(Date(-4, 1, 5).toISOString() == "-00040105"); 7366 } 7367 7368 @safe unittest 7369 { 7370 // Test A.D. 7371 assert(Date(9, 12, 4).toISOString() == "00091204"); 7372 assert(Date(99, 12, 4).toISOString() == "00991204"); 7373 assert(Date(999, 12, 4).toISOString() == "09991204"); 7374 assert(Date(9999, 7, 4).toISOString() == "99990704"); 7375 assert(Date(10000, 10, 20).toISOString() == "+100001020"); 7376 7377 // Test B.C. 7378 assert(Date(0, 12, 4).toISOString() == "00001204"); 7379 assert(Date(-9, 12, 4).toISOString() == "-00091204"); 7380 assert(Date(-99, 12, 4).toISOString() == "-00991204"); 7381 assert(Date(-999, 12, 4).toISOString() == "-09991204"); 7382 assert(Date(-9999, 7, 4).toISOString() == "-99990704"); 7383 assert(Date(-10000, 10, 20).toISOString() == "-100001020"); 7384 7385 const cdate = Date(1999, 7, 6); 7386 immutable idate = Date(1999, 7, 6); 7387 assert(cdate.toISOString() == "19990706"); 7388 assert(idate.toISOString() == "19990706"); 7389 } 7390 7391 /// ditto 7392 void toISOString(W)(ref W writer) const 7393 if (isOutputRange!(W, char)) 7394 { 7395 import std.format.write : formattedWrite; 7396 if (_year >= 0) 7397 { 7398 if (_year < 10_000) 7399 formattedWrite(writer, "%04d%02d%02d", _year, _month, _day); 7400 else 7401 formattedWrite(writer, "+%05d%02d%02d", _year, _month, _day); 7402 } 7403 else if (_year > -10_000) 7404 formattedWrite(writer, "%05d%02d%02d", _year, _month, _day); 7405 else 7406 formattedWrite(writer, "%06d%02d%02d", _year, _month, _day); 7407 } 7408 7409 @safe pure unittest 7410 { 7411 import std.array : appender; 7412 7413 auto w = appender!(char[])(); 7414 Date(2010, 7, 4).toISOString(w); 7415 assert(w.data == "20100704"); 7416 w.clear(); 7417 Date(1998, 12, 25).toISOString(w); 7418 assert(w.data == "19981225"); 7419 } 7420 7421 /++ 7422 Converts this $(LREF Date) to a string with the format `YYYY-MM-DD`. 7423 If `writer` is set, the resulting string will be written directly 7424 to it. 7425 7426 Params: 7427 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7428 Returns: 7429 A `string` when not using an output range; `void` otherwise. 7430 +/ 7431 string toISOExtString() const @safe pure nothrow 7432 { 7433 import std.array : appender; 7434 auto w = appender!string(); 7435 w.reserve(10); 7436 try 7437 toISOExtString(w); 7438 catch (Exception e) 7439 assert(0, "toISOExtString() threw."); 7440 return w.data; 7441 } 7442 7443 /// 7444 @safe unittest 7445 { 7446 assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); 7447 assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); 7448 assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); 7449 assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); 7450 } 7451 7452 @safe unittest 7453 { 7454 // Test A.D. 7455 assert(Date(9, 12, 4).toISOExtString() == "0009-12-04"); 7456 assert(Date(99, 12, 4).toISOExtString() == "0099-12-04"); 7457 assert(Date(999, 12, 4).toISOExtString() == "0999-12-04"); 7458 assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04"); 7459 assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20"); 7460 7461 // Test B.C. 7462 assert(Date(0, 12, 4).toISOExtString() == "0000-12-04"); 7463 assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04"); 7464 assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04"); 7465 assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04"); 7466 assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04"); 7467 assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20"); 7468 7469 const cdate = Date(1999, 7, 6); 7470 immutable idate = Date(1999, 7, 6); 7471 assert(cdate.toISOExtString() == "1999-07-06"); 7472 assert(idate.toISOExtString() == "1999-07-06"); 7473 } 7474 7475 /// ditto 7476 void toISOExtString(W)(ref W writer) const 7477 if (isOutputRange!(W, char)) 7478 { 7479 import std.format.write : formattedWrite; 7480 if (_year >= 0) 7481 { 7482 if (_year < 10_000) 7483 formattedWrite(writer, "%04d-%02d-%02d", _year, _month, _day); 7484 else 7485 formattedWrite(writer, "+%05d-%02d-%02d", _year, _month, _day); 7486 } 7487 else if (_year > -10_000) 7488 formattedWrite(writer, "%05d-%02d-%02d", _year, _month, _day); 7489 else 7490 formattedWrite(writer, "%06d-%02d-%02d", _year, _month, _day); 7491 } 7492 7493 @safe pure unittest 7494 { 7495 import std.array : appender; 7496 7497 auto w = appender!(char[])(); 7498 Date(2010, 7, 4).toISOExtString(w); 7499 assert(w.data == "2010-07-04"); 7500 w.clear(); 7501 Date(-4, 1, 5).toISOExtString(w); 7502 assert(w.data == "-0004-01-05"); 7503 } 7504 7505 /++ 7506 Converts this $(LREF Date) to a string with the format `YYYY-Mon-DD`. 7507 If `writer` is set, the resulting string will be written directly 7508 to it. 7509 7510 Params: 7511 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7512 Returns: 7513 A `string` when not using an output range; `void` otherwise. 7514 +/ 7515 string toSimpleString() const @safe pure nothrow 7516 { 7517 import std.array : appender; 7518 auto w = appender!string(); 7519 w.reserve(11); 7520 try 7521 toSimpleString(w); 7522 catch (Exception e) 7523 assert(0, "toSimpleString() threw."); 7524 return w.data; 7525 } 7526 7527 /// 7528 @safe unittest 7529 { 7530 assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); 7531 assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); 7532 assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); 7533 assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); 7534 } 7535 7536 @safe unittest 7537 { 7538 // Test A.D. 7539 assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04"); 7540 assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04"); 7541 assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04"); 7542 assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04"); 7543 assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20"); 7544 7545 // Test B.C. 7546 assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04"); 7547 assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04"); 7548 assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04"); 7549 assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04"); 7550 assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04"); 7551 assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20"); 7552 7553 const cdate = Date(1999, 7, 6); 7554 immutable idate = Date(1999, 7, 6); 7555 assert(cdate.toSimpleString() == "1999-Jul-06"); 7556 assert(idate.toSimpleString() == "1999-Jul-06"); 7557 } 7558 7559 /// ditto 7560 void toSimpleString(W)(ref W writer) const 7561 if (isOutputRange!(W, char)) 7562 { 7563 import std.format.write : formattedWrite; 7564 if (_year >= 0) 7565 { 7566 if (_year < 10_000) 7567 formattedWrite(writer, "%04d-%s-%02d", _year, monthToString(_month), _day); 7568 else 7569 formattedWrite(writer, "+%05d-%s-%02d", _year, monthToString(_month), _day); 7570 } 7571 else if (_year > -10_000) 7572 formattedWrite(writer, "%05d-%s-%02d", _year, monthToString(_month), _day); 7573 else 7574 formattedWrite(writer, "%06d-%s-%02d", _year, monthToString(_month), _day); 7575 } 7576 7577 @safe pure unittest 7578 { 7579 import std.array : appender; 7580 7581 auto w = appender!(char[])(); 7582 Date(9, 12, 4).toSimpleString(w); 7583 assert(w.data == "0009-Dec-04"); 7584 w.clear(); 7585 Date(-10000, 10, 20).toSimpleString(w); 7586 assert(w.data == "-10000-Oct-20"); 7587 } 7588 7589 /++ 7590 Converts this $(LREF Date) to a string. 7591 7592 This function exists to make it easy to convert a $(LREF Date) to a 7593 string for code that does not care what the exact format is - just that 7594 it presents the information in a clear manner. It also makes it easy to 7595 simply convert a $(LREF Date) to a string when using functions such as 7596 `to!string`, `format`, or `writeln` which use toString to convert 7597 user-defined types. So, it is unlikely that much code will call 7598 toString directly. 7599 7600 The format of the string is purposefully unspecified, and code that 7601 cares about the format of the string should use `toISOString`, 7602 `toISOExtString`, `toSimpleString`, or some other custom formatting 7603 function that explicitly generates the format that the code needs. The 7604 reason is that the code is then clear about what format it's using, 7605 making it less error-prone to maintain the code and interact with other 7606 software that consumes the generated strings. It's for this same reason 7607 $(LREF Date) has no `fromString` function, whereas it does have 7608 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 7609 7610 The format returned by toString may or may not change in the future. 7611 +/ 7612 string toString() const @safe pure nothrow 7613 { 7614 return toSimpleString(); 7615 } 7616 7617 @safe unittest 7618 { 7619 auto date = Date(1999, 7, 6); 7620 const cdate = Date(1999, 7, 6); 7621 immutable idate = Date(1999, 7, 6); 7622 assert(date.toString()); 7623 assert(cdate.toString()); 7624 assert(idate.toString()); 7625 } 7626 7627 /// ditto 7628 void toString(W)(ref W writer) const 7629 if (isOutputRange!(W, char)) 7630 { 7631 toSimpleString(writer); 7632 } 7633 7634 /++ 7635 Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace 7636 is stripped from the given string. 7637 7638 Params: 7639 isoString = A string formatted in the ISO format for dates. 7640 7641 Throws: 7642 $(REF DateTimeException,std,datetime,date) if the given string is 7643 not in the ISO format or if the resulting $(LREF Date) would not be 7644 valid. 7645 +/ 7646 static Date fromISOString(S)(scope const S isoString) @safe pure 7647 if (isSomeString!S) 7648 { 7649 import std.algorithm.searching : startsWith; 7650 import std.conv : to, text, ConvException; 7651 import std.exception : enforce; 7652 import std.string : strip; 7653 7654 auto str = isoString.strip; 7655 7656 enforce!DateTimeException(str.length >= 8, text("Invalid format for Date.fromISOString: ", isoString)); 7657 7658 int day, month, year; 7659 auto yearStr = str[0 .. $ - 4]; 7660 7661 try 7662 { 7663 // using conversion to uint plus cast because it checks for +/- 7664 // for us quickly while throwing ConvException 7665 day = cast(int) to!uint(str[$ - 2 .. $]); 7666 month = cast(int) to!uint(str[$ - 4 .. $ - 2]); 7667 7668 if (yearStr.length > 4) 7669 { 7670 enforce!DateTimeException(yearStr.startsWith('-', '+'), 7671 text("Invalid format for Date.fromISOString: ", isoString)); 7672 year = to!int(yearStr); 7673 } 7674 else 7675 { 7676 year = cast(int) to!uint(yearStr); 7677 } 7678 } 7679 catch (ConvException) 7680 { 7681 throw new DateTimeException(text("Invalid format for Date.fromISOString: ", isoString)); 7682 } 7683 7684 return Date(year, month, day); 7685 } 7686 7687 /// 7688 @safe unittest 7689 { 7690 assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); 7691 assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); 7692 assert(Date.fromISOString("00000105") == Date(0, 1, 5)); 7693 assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); 7694 assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); 7695 } 7696 7697 @safe unittest 7698 { 7699 assertThrown!DateTimeException(Date.fromISOString("")); 7700 assertThrown!DateTimeException(Date.fromISOString("990704")); 7701 assertThrown!DateTimeException(Date.fromISOString("0100704")); 7702 assertThrown!DateTimeException(Date.fromISOString("2010070")); 7703 assertThrown!DateTimeException(Date.fromISOString("2010070 ")); 7704 assertThrown!DateTimeException(Date.fromISOString("120100704")); 7705 assertThrown!DateTimeException(Date.fromISOString("-0100704")); 7706 assertThrown!DateTimeException(Date.fromISOString("+0100704")); 7707 assertThrown!DateTimeException(Date.fromISOString("2010070a")); 7708 assertThrown!DateTimeException(Date.fromISOString("20100a04")); 7709 assertThrown!DateTimeException(Date.fromISOString("2010a704")); 7710 7711 assertThrown!DateTimeException(Date.fromISOString("99-07-04")); 7712 assertThrown!DateTimeException(Date.fromISOString("010-07-04")); 7713 assertThrown!DateTimeException(Date.fromISOString("2010-07-0")); 7714 assertThrown!DateTimeException(Date.fromISOString("2010-07-0 ")); 7715 assertThrown!DateTimeException(Date.fromISOString("12010-07-04")); 7716 assertThrown!DateTimeException(Date.fromISOString("-010-07-04")); 7717 assertThrown!DateTimeException(Date.fromISOString("+010-07-04")); 7718 assertThrown!DateTimeException(Date.fromISOString("2010-07-0a")); 7719 assertThrown!DateTimeException(Date.fromISOString("2010-0a-04")); 7720 assertThrown!DateTimeException(Date.fromISOString("2010-a7-04")); 7721 assertThrown!DateTimeException(Date.fromISOString("2010/07/04")); 7722 assertThrown!DateTimeException(Date.fromISOString("2010/7/04")); 7723 assertThrown!DateTimeException(Date.fromISOString("2010/7/4")); 7724 assertThrown!DateTimeException(Date.fromISOString("2010/07/4")); 7725 assertThrown!DateTimeException(Date.fromISOString("2010-7-04")); 7726 assertThrown!DateTimeException(Date.fromISOString("2010-7-4")); 7727 assertThrown!DateTimeException(Date.fromISOString("2010-07-4")); 7728 7729 assertThrown!DateTimeException(Date.fromISOString("99Jul04")); 7730 assertThrown!DateTimeException(Date.fromISOString("010Jul04")); 7731 assertThrown!DateTimeException(Date.fromISOString("2010Jul0")); 7732 assertThrown!DateTimeException(Date.fromISOString("2010Jul0 ")); 7733 assertThrown!DateTimeException(Date.fromISOString("12010Jul04")); 7734 assertThrown!DateTimeException(Date.fromISOString("-010Jul04")); 7735 assertThrown!DateTimeException(Date.fromISOString("+010Jul04")); 7736 assertThrown!DateTimeException(Date.fromISOString("2010Jul0a")); 7737 assertThrown!DateTimeException(Date.fromISOString("2010Jua04")); 7738 assertThrown!DateTimeException(Date.fromISOString("2010aul04")); 7739 7740 assertThrown!DateTimeException(Date.fromISOString("99-Jul-04")); 7741 assertThrown!DateTimeException(Date.fromISOString("010-Jul-04")); 7742 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0")); 7743 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 ")); 7744 assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04")); 7745 assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04")); 7746 assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04")); 7747 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a")); 7748 assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04")); 7749 assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04")); 7750 assertThrown!DateTimeException(Date.fromISOString("2010-aul-04")); 7751 7752 assertThrown!DateTimeException(Date.fromISOString("2010-07-04")); 7753 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04")); 7754 7755 assert(Date.fromISOString("19990706") == Date(1999, 7, 6)); 7756 assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6)); 7757 assert(Date.fromISOString("+019990706") == Date(1999, 7, 6)); 7758 assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6)); 7759 assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6)); 7760 assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6)); 7761 } 7762 7763 // https://issues.dlang.org/show_bug.cgi?id=17801 7764 @safe unittest 7765 { 7766 import std.conv : to; 7767 import std.meta : AliasSeq; 7768 static foreach (C; AliasSeq!(char, wchar, dchar)) 7769 { 7770 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7771 assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21)); 7772 } 7773 } 7774 7775 7776 /++ 7777 Creates a $(LREF Date) from a string with the format YYYY-MM-DD. 7778 Whitespace is stripped from the given string. 7779 7780 Params: 7781 isoExtString = A string formatted in the ISO Extended format for 7782 dates. 7783 7784 Throws: 7785 $(REF DateTimeException,std,datetime,date) if the given string is 7786 not in the ISO Extended format or if the resulting $(LREF Date) 7787 would not be valid. 7788 +/ 7789 static Date fromISOExtString(S)(scope const S isoExtString) @safe pure 7790 if (isSomeString!(S)) 7791 { 7792 import std.algorithm.searching : startsWith; 7793 import std.conv : to, ConvException; 7794 import std.format : format; 7795 import std.string : strip; 7796 7797 auto str = strip(isoExtString); 7798 short year; 7799 ubyte month, day; 7800 7801 if (str.length < 10 || str[$-3] != '-' || str[$-6] != '-') 7802 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7803 7804 auto yearStr = str[0 .. $-6]; 7805 auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); 7806 if ((yearStr.length > 4) != signAtBegining) 7807 { 7808 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7809 } 7810 7811 try 7812 { 7813 day = to!ubyte(str[$-2 .. $]); 7814 month = to!ubyte(str[$-5 .. $-3]); 7815 year = to!short(yearStr); 7816 } 7817 catch (ConvException) 7818 { 7819 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7820 } 7821 7822 return Date(year, month, day); 7823 } 7824 7825 /// 7826 @safe unittest 7827 { 7828 assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); 7829 assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); 7830 assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); 7831 assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); 7832 assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); 7833 } 7834 7835 @safe unittest 7836 { 7837 assertThrown!DateTimeException(Date.fromISOExtString("")); 7838 assertThrown!DateTimeException(Date.fromISOExtString("990704")); 7839 assertThrown!DateTimeException(Date.fromISOExtString("0100704")); 7840 assertThrown!DateTimeException(Date.fromISOExtString("2010070")); 7841 assertThrown!DateTimeException(Date.fromISOExtString("2010070 ")); 7842 assertThrown!DateTimeException(Date.fromISOExtString("120100704")); 7843 assertThrown!DateTimeException(Date.fromISOExtString("-0100704")); 7844 assertThrown!DateTimeException(Date.fromISOExtString("+0100704")); 7845 assertThrown!DateTimeException(Date.fromISOExtString("2010070a")); 7846 assertThrown!DateTimeException(Date.fromISOExtString("20100a04")); 7847 assertThrown!DateTimeException(Date.fromISOExtString("2010a704")); 7848 7849 assertThrown!DateTimeException(Date.fromISOExtString("99-07-04")); 7850 assertThrown!DateTimeException(Date.fromISOExtString("010-07-04")); 7851 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0")); 7852 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 ")); 7853 assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04")); 7854 assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04")); 7855 assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04")); 7856 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a")); 7857 assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04")); 7858 assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04")); 7859 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04")); 7860 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04")); 7861 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4")); 7862 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4")); 7863 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04")); 7864 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4")); 7865 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4")); 7866 7867 assertThrown!DateTimeException(Date.fromISOExtString("99Jul04")); 7868 assertThrown!DateTimeException(Date.fromISOExtString("010Jul04")); 7869 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0")); 7870 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 ")); 7871 assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04")); 7872 assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04")); 7873 assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04")); 7874 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a")); 7875 assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04")); 7876 assertThrown!DateTimeException(Date.fromISOExtString("2010aul04")); 7877 7878 assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04")); 7879 assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04")); 7880 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0")); 7881 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 ")); 7882 assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04")); 7883 assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04")); 7884 assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04")); 7885 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a")); 7886 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04")); 7887 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04")); 7888 assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04")); 7889 7890 assertThrown!DateTimeException(Date.fromISOExtString("20100704")); 7891 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04")); 7892 7893 assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6)); 7894 assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6)); 7895 assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6)); 7896 assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6)); 7897 assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6)); 7898 assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6)); 7899 } 7900 7901 // https://issues.dlang.org/show_bug.cgi?id=17801 7902 @safe unittest 7903 { 7904 import std.conv : to; 7905 import std.meta : AliasSeq; 7906 static foreach (C; AliasSeq!(char, wchar, dchar)) 7907 { 7908 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7909 assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21)); 7910 } 7911 } 7912 7913 7914 /++ 7915 Creates a $(LREF Date) from a string with the format YYYY-Mon-DD. 7916 Whitespace is stripped from the given string. 7917 7918 Params: 7919 simpleString = A string formatted in the way that toSimpleString 7920 formats dates. 7921 7922 Throws: 7923 $(REF DateTimeException,std,datetime,date) if the given string is 7924 not in the correct format or if the resulting $(LREF Date) would not 7925 be valid. 7926 +/ 7927 static Date fromSimpleString(S)(scope const S simpleString) @safe pure 7928 if (isSomeString!(S)) 7929 { 7930 import std.algorithm.searching : startsWith; 7931 import std.conv : to, ConvException; 7932 import std.format : format; 7933 import std.string : strip; 7934 7935 auto str = strip(simpleString); 7936 7937 if (str.length < 11 || str[$-3] != '-' || str[$-7] != '-') 7938 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7939 7940 int year; 7941 uint day; 7942 auto month = monthFromString(str[$ - 6 .. $ - 3]); 7943 auto yearStr = str[0 .. $ - 7]; 7944 auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); 7945 if ((yearStr.length > 4) != signAtBegining) 7946 { 7947 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7948 } 7949 7950 try 7951 { 7952 day = to!uint(str[$ - 2 .. $]); 7953 year = to!int(yearStr); 7954 } 7955 catch (ConvException) 7956 { 7957 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7958 } 7959 7960 return Date(year, month, day); 7961 } 7962 7963 /// 7964 @safe unittest 7965 { 7966 assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); 7967 assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); 7968 assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); 7969 assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); 7970 assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); 7971 } 7972 7973 @safe unittest 7974 { 7975 assertThrown!DateTimeException(Date.fromSimpleString("")); 7976 assertThrown!DateTimeException(Date.fromSimpleString("990704")); 7977 assertThrown!DateTimeException(Date.fromSimpleString("0100704")); 7978 assertThrown!DateTimeException(Date.fromSimpleString("2010070")); 7979 assertThrown!DateTimeException(Date.fromSimpleString("2010070 ")); 7980 assertThrown!DateTimeException(Date.fromSimpleString("120100704")); 7981 assertThrown!DateTimeException(Date.fromSimpleString("-0100704")); 7982 assertThrown!DateTimeException(Date.fromSimpleString("+0100704")); 7983 assertThrown!DateTimeException(Date.fromSimpleString("2010070a")); 7984 assertThrown!DateTimeException(Date.fromSimpleString("20100a04")); 7985 assertThrown!DateTimeException(Date.fromSimpleString("2010a704")); 7986 7987 assertThrown!DateTimeException(Date.fromSimpleString("99-07-04")); 7988 assertThrown!DateTimeException(Date.fromSimpleString("010-07-04")); 7989 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0")); 7990 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 ")); 7991 assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04")); 7992 assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04")); 7993 assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04")); 7994 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a")); 7995 assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04")); 7996 assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04")); 7997 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04")); 7998 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04")); 7999 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4")); 8000 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4")); 8001 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04")); 8002 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4")); 8003 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4")); 8004 8005 assertThrown!DateTimeException(Date.fromSimpleString("99Jul04")); 8006 assertThrown!DateTimeException(Date.fromSimpleString("010Jul04")); 8007 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0")); 8008 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 ")); 8009 assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04")); 8010 assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04")); 8011 assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04")); 8012 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a")); 8013 assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04")); 8014 assertThrown!DateTimeException(Date.fromSimpleString("2010aul04")); 8015 8016 assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04")); 8017 assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04")); 8018 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0")); 8019 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 ")); 8020 assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04")); 8021 assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04")); 8022 assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04")); 8023 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a")); 8024 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04")); 8025 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04")); 8026 assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04")); 8027 8028 assertThrown!DateTimeException(Date.fromSimpleString("20100704")); 8029 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04")); 8030 8031 assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6)); 8032 assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6)); 8033 assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6)); 8034 assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6)); 8035 assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6)); 8036 assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6)); 8037 } 8038 8039 // https://issues.dlang.org/show_bug.cgi?id=17801 8040 @safe unittest 8041 { 8042 import std.conv : to; 8043 import std.meta : AliasSeq; 8044 static foreach (C; AliasSeq!(char, wchar, dchar)) 8045 { 8046 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 8047 assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21)); 8048 } 8049 } 8050 8051 8052 /++ 8053 Returns the $(LREF Date) farthest in the past which is representable by 8054 $(LREF Date). 8055 +/ 8056 @property static Date min() @safe pure nothrow @nogc 8057 { 8058 auto date = Date.init; 8059 date._year = short.min; 8060 date._month = Month.jan; 8061 date._day = 1; 8062 8063 return date; 8064 } 8065 8066 @safe unittest 8067 { 8068 assert(Date.min.year < 0); 8069 assert(Date.min < Date.max); 8070 } 8071 8072 8073 /++ 8074 Returns the $(LREF Date) farthest in the future which is representable 8075 by $(LREF Date). 8076 +/ 8077 @property static Date max() @safe pure nothrow @nogc 8078 { 8079 auto date = Date.init; 8080 date._year = short.max; 8081 date._month = Month.dec; 8082 date._day = 31; 8083 8084 return date; 8085 } 8086 8087 @safe unittest 8088 { 8089 assert(Date.max.year > 0); 8090 assert(Date.max > Date.min); 8091 } 8092 8093 8094 private: 8095 8096 /+ 8097 Whether the given values form a valid date. 8098 8099 Params: 8100 year = The year to test. 8101 month = The month of the Gregorian Calendar to test. 8102 day = The day of the month to test. 8103 +/ 8104 static bool _valid(int year, int month, int day) @safe pure nothrow @nogc 8105 { 8106 if (!valid!"months"(month)) 8107 return false; 8108 return valid!"days"(year, month, day); 8109 } 8110 8111 8112 package: 8113 8114 /+ 8115 Adds the given number of days to this $(LREF Date). A negative number 8116 will subtract. 8117 8118 The month will be adjusted along with the day if the number of days 8119 added (or subtracted) would overflow (or underflow) the current month. 8120 The year will be adjusted along with the month if the increase (or 8121 decrease) to the month would cause it to overflow (or underflow) the 8122 current year. 8123 8124 `_addDays(numDays)` is effectively equivalent to 8125 $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days). 8126 8127 Params: 8128 days = The number of days to add to this Date. 8129 +/ 8130 ref Date _addDays(long days) return @safe pure nothrow @nogc 8131 { 8132 dayOfGregorianCal = cast(int)(dayOfGregorianCal + days); 8133 return this; 8134 } 8135 8136 @safe unittest 8137 { 8138 // Test A.D. 8139 { 8140 auto date = Date(1999, 2, 28); 8141 date._addDays(1); 8142 assert(date == Date(1999, 3, 1)); 8143 date._addDays(-1); 8144 assert(date == Date(1999, 2, 28)); 8145 } 8146 8147 { 8148 auto date = Date(2000, 2, 28); 8149 date._addDays(1); 8150 assert(date == Date(2000, 2, 29)); 8151 date._addDays(1); 8152 assert(date == Date(2000, 3, 1)); 8153 date._addDays(-1); 8154 assert(date == Date(2000, 2, 29)); 8155 } 8156 8157 { 8158 auto date = Date(1999, 6, 30); 8159 date._addDays(1); 8160 assert(date == Date(1999, 7, 1)); 8161 date._addDays(-1); 8162 assert(date == Date(1999, 6, 30)); 8163 } 8164 8165 { 8166 auto date = Date(1999, 7, 31); 8167 date._addDays(1); 8168 assert(date == Date(1999, 8, 1)); 8169 date._addDays(-1); 8170 assert(date == Date(1999, 7, 31)); 8171 } 8172 8173 { 8174 auto date = Date(1999, 1, 1); 8175 date._addDays(-1); 8176 assert(date == Date(1998, 12, 31)); 8177 date._addDays(1); 8178 assert(date == Date(1999, 1, 1)); 8179 } 8180 8181 { 8182 auto date = Date(1999, 7, 6); 8183 date._addDays(9); 8184 assert(date == Date(1999, 7, 15)); 8185 date._addDays(-11); 8186 assert(date == Date(1999, 7, 4)); 8187 date._addDays(30); 8188 assert(date == Date(1999, 8, 3)); 8189 date._addDays(-3); 8190 assert(date == Date(1999, 7, 31)); 8191 } 8192 8193 { 8194 auto date = Date(1999, 7, 6); 8195 date._addDays(365); 8196 assert(date == Date(2000, 7, 5)); 8197 date._addDays(-365); 8198 assert(date == Date(1999, 7, 6)); 8199 date._addDays(366); 8200 assert(date == Date(2000, 7, 6)); 8201 date._addDays(730); 8202 assert(date == Date(2002, 7, 6)); 8203 date._addDays(-1096); 8204 assert(date == Date(1999, 7, 6)); 8205 } 8206 8207 // Test B.C. 8208 { 8209 auto date = Date(-1999, 2, 28); 8210 date._addDays(1); 8211 assert(date == Date(-1999, 3, 1)); 8212 date._addDays(-1); 8213 assert(date == Date(-1999, 2, 28)); 8214 } 8215 8216 { 8217 auto date = Date(-2000, 2, 28); 8218 date._addDays(1); 8219 assert(date == Date(-2000, 2, 29)); 8220 date._addDays(1); 8221 assert(date == Date(-2000, 3, 1)); 8222 date._addDays(-1); 8223 assert(date == Date(-2000, 2, 29)); 8224 } 8225 8226 { 8227 auto date = Date(-1999, 6, 30); 8228 date._addDays(1); 8229 assert(date == Date(-1999, 7, 1)); 8230 date._addDays(-1); 8231 assert(date == Date(-1999, 6, 30)); 8232 } 8233 8234 { 8235 auto date = Date(-1999, 7, 31); 8236 date._addDays(1); 8237 assert(date == Date(-1999, 8, 1)); 8238 date._addDays(-1); 8239 assert(date == Date(-1999, 7, 31)); 8240 } 8241 8242 { 8243 auto date = Date(-1999, 1, 1); 8244 date._addDays(-1); 8245 assert(date == Date(-2000, 12, 31)); 8246 date._addDays(1); 8247 assert(date == Date(-1999, 1, 1)); 8248 } 8249 8250 { 8251 auto date = Date(-1999, 7, 6); 8252 date._addDays(9); 8253 assert(date == Date(-1999, 7, 15)); 8254 date._addDays(-11); 8255 assert(date == Date(-1999, 7, 4)); 8256 date._addDays(30); 8257 assert(date == Date(-1999, 8, 3)); 8258 date._addDays(-3); 8259 } 8260 8261 { 8262 auto date = Date(-1999, 7, 6); 8263 date._addDays(365); 8264 assert(date == Date(-1998, 7, 6)); 8265 date._addDays(-365); 8266 assert(date == Date(-1999, 7, 6)); 8267 date._addDays(366); 8268 assert(date == Date(-1998, 7, 7)); 8269 date._addDays(730); 8270 assert(date == Date(-1996, 7, 6)); 8271 date._addDays(-1096); 8272 assert(date == Date(-1999, 7, 6)); 8273 } 8274 8275 // Test Both 8276 { 8277 auto date = Date(1, 7, 6); 8278 date._addDays(-365); 8279 assert(date == Date(0, 7, 6)); 8280 date._addDays(365); 8281 assert(date == Date(1, 7, 6)); 8282 date._addDays(-731); 8283 assert(date == Date(-1, 7, 6)); 8284 date._addDays(730); 8285 assert(date == Date(1, 7, 5)); 8286 } 8287 8288 const cdate = Date(1999, 7, 6); 8289 immutable idate = Date(1999, 7, 6); 8290 static assert(!__traits(compiles, cdate._addDays(12))); 8291 static assert(!__traits(compiles, idate._addDays(12))); 8292 } 8293 8294 8295 @safe pure invariant() 8296 { 8297 import std.format : format; 8298 assert(valid!"months"(_month), 8299 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 8300 assert(valid!"days"(_year, _month, _day), 8301 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 8302 } 8303 8304 short _year = 1; 8305 Month _month = Month.jan; 8306 ubyte _day = 1; 8307 } 8308 8309 /// 8310 @safe pure unittest 8311 { 8312 import core.time : days; 8313 8314 auto d = Date(2000, 6, 1); 8315 8316 assert(d.dayOfYear == 153); 8317 assert(d.dayOfWeek == DayOfWeek.thu); 8318 8319 d += 10.days; 8320 assert(d == Date(2000, 6, 11)); 8321 8322 assert(d.toISOExtString() == "2000-06-11"); 8323 assert(d.toISOString() == "20000611"); 8324 assert(d.toSimpleString() == "2000-Jun-11"); 8325 8326 assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1)); 8327 assert(Date.fromISOString("20180101") == Date(2018, 1, 1)); 8328 assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1)); 8329 } 8330 8331 8332 /++ 8333 Represents a time of day with hours, minutes, and seconds. It uses 24 hour 8334 time. 8335 +/ 8336 struct TimeOfDay 8337 { 8338 public: 8339 8340 /++ 8341 Params: 8342 hour = Hour of the day [0 - 24$(RPAREN). 8343 minute = Minute of the hour [0 - 60$(RPAREN). 8344 second = Second of the minute [0 - 60$(RPAREN). 8345 8346 Throws: 8347 $(REF DateTimeException,std,datetime,date) if the resulting 8348 $(LREF TimeOfDay) would be not be valid. 8349 +/ 8350 this(int hour, int minute, int second = 0) @safe pure 8351 { 8352 enforceValid!"hours"(hour); 8353 enforceValid!"minutes"(minute); 8354 enforceValid!"seconds"(second); 8355 8356 _hour = cast(ubyte) hour; 8357 _minute = cast(ubyte) minute; 8358 _second = cast(ubyte) second; 8359 } 8360 8361 @safe unittest 8362 { 8363 assert(TimeOfDay(0, 0) == TimeOfDay.init); 8364 8365 { 8366 auto tod = TimeOfDay(0, 0); 8367 assert(tod._hour == 0); 8368 assert(tod._minute == 0); 8369 assert(tod._second == 0); 8370 } 8371 8372 { 8373 auto tod = TimeOfDay(12, 30, 33); 8374 assert(tod._hour == 12); 8375 assert(tod._minute == 30); 8376 assert(tod._second == 33); 8377 } 8378 8379 { 8380 auto tod = TimeOfDay(23, 59, 59); 8381 assert(tod._hour == 23); 8382 assert(tod._minute == 59); 8383 assert(tod._second == 59); 8384 } 8385 8386 assertThrown!DateTimeException(TimeOfDay(24, 0, 0)); 8387 assertThrown!DateTimeException(TimeOfDay(0, 60, 0)); 8388 assertThrown!DateTimeException(TimeOfDay(0, 0, 60)); 8389 } 8390 8391 8392 /++ 8393 Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay). 8394 8395 Returns: 8396 $(BOOKTABLE, 8397 $(TR $(TD this < rhs) $(TD < 0)) 8398 $(TR $(TD this == rhs) $(TD 0)) 8399 $(TR $(TD this > rhs) $(TD > 0)) 8400 ) 8401 +/ 8402 int opCmp(TimeOfDay rhs) const @safe pure nothrow @nogc 8403 { 8404 if (_hour < rhs._hour) 8405 return -1; 8406 if (_hour > rhs._hour) 8407 return 1; 8408 8409 if (_minute < rhs._minute) 8410 return -1; 8411 if (_minute > rhs._minute) 8412 return 1; 8413 8414 if (_second < rhs._second) 8415 return -1; 8416 if (_second > rhs._second) 8417 return 1; 8418 8419 return 0; 8420 } 8421 8422 @safe unittest 8423 { 8424 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0); 8425 8426 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0); 8427 assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0); 8428 assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0); 8429 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8430 8431 assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0); 8432 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0); 8433 8434 assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0); 8435 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8436 8437 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8438 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8439 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0); 8440 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8441 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0); 8442 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0); 8443 8444 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8445 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0); 8446 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0); 8447 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8448 8449 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8450 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0); 8451 8452 const ctod = TimeOfDay(12, 30, 33); 8453 immutable itod = TimeOfDay(12, 30, 33); 8454 assert(ctod.opCmp(itod) == 0); 8455 assert(itod.opCmp(ctod) == 0); 8456 } 8457 8458 8459 /++ 8460 Hours past midnight. 8461 +/ 8462 @property ubyte hour() const @safe pure nothrow @nogc 8463 { 8464 return _hour; 8465 } 8466 8467 @safe unittest 8468 { 8469 assert(TimeOfDay.init.hour == 0); 8470 assert(TimeOfDay(12, 0, 0).hour == 12); 8471 8472 const ctod = TimeOfDay(12, 0, 0); 8473 immutable itod = TimeOfDay(12, 0, 0); 8474 assert(ctod.hour == 12); 8475 assert(itod.hour == 12); 8476 } 8477 8478 8479 /++ 8480 Hours past midnight. 8481 8482 Params: 8483 hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to. 8484 8485 Throws: 8486 $(REF DateTimeException,std,datetime,date) if the given hour would 8487 result in an invalid $(LREF TimeOfDay). 8488 +/ 8489 @property void hour(int hour) @safe pure 8490 { 8491 enforceValid!"hours"(hour); 8492 _hour = cast(ubyte) hour; 8493 } 8494 8495 @safe unittest 8496 { 8497 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}()); 8498 8499 auto tod = TimeOfDay(0, 0, 0); 8500 tod.hour = 12; 8501 assert(tod == TimeOfDay(12, 0, 0)); 8502 8503 const ctod = TimeOfDay(0, 0, 0); 8504 immutable itod = TimeOfDay(0, 0, 0); 8505 static assert(!__traits(compiles, ctod.hour = 12)); 8506 static assert(!__traits(compiles, itod.hour = 12)); 8507 } 8508 8509 8510 /++ 8511 Minutes past the hour. 8512 +/ 8513 @property ubyte minute() const @safe pure nothrow @nogc 8514 { 8515 return _minute; 8516 } 8517 8518 @safe unittest 8519 { 8520 assert(TimeOfDay.init.minute == 0); 8521 assert(TimeOfDay(0, 30, 0).minute == 30); 8522 8523 const ctod = TimeOfDay(0, 30, 0); 8524 immutable itod = TimeOfDay(0, 30, 0); 8525 assert(ctod.minute == 30); 8526 assert(itod.minute == 30); 8527 } 8528 8529 8530 /++ 8531 Minutes past the hour. 8532 8533 Params: 8534 minute = The minute to set this $(LREF TimeOfDay)'s minute to. 8535 8536 Throws: 8537 $(REF DateTimeException,std,datetime,date) if the given minute 8538 would result in an invalid $(LREF TimeOfDay). 8539 +/ 8540 @property void minute(int minute) @safe pure 8541 { 8542 enforceValid!"minutes"(minute); 8543 _minute = cast(ubyte) minute; 8544 } 8545 8546 @safe unittest 8547 { 8548 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}()); 8549 8550 auto tod = TimeOfDay(0, 0, 0); 8551 tod.minute = 30; 8552 assert(tod == TimeOfDay(0, 30, 0)); 8553 8554 const ctod = TimeOfDay(0, 0, 0); 8555 immutable itod = TimeOfDay(0, 0, 0); 8556 static assert(!__traits(compiles, ctod.minute = 30)); 8557 static assert(!__traits(compiles, itod.minute = 30)); 8558 } 8559 8560 8561 /++ 8562 Seconds past the minute. 8563 +/ 8564 @property ubyte second() const @safe pure nothrow @nogc 8565 { 8566 return _second; 8567 } 8568 8569 @safe unittest 8570 { 8571 assert(TimeOfDay.init.second == 0); 8572 assert(TimeOfDay(0, 0, 33).second == 33); 8573 8574 const ctod = TimeOfDay(0, 0, 33); 8575 immutable itod = TimeOfDay(0, 0, 33); 8576 assert(ctod.second == 33); 8577 assert(itod.second == 33); 8578 } 8579 8580 8581 /++ 8582 Seconds past the minute. 8583 8584 Params: 8585 second = The second to set this $(LREF TimeOfDay)'s second to. 8586 8587 Throws: 8588 $(REF DateTimeException,std,datetime,date) if the given second 8589 would result in an invalid $(LREF TimeOfDay). 8590 +/ 8591 @property void second(int second) @safe pure 8592 { 8593 enforceValid!"seconds"(second); 8594 _second = cast(ubyte) second; 8595 } 8596 8597 @safe unittest 8598 { 8599 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}()); 8600 8601 auto tod = TimeOfDay(0, 0, 0); 8602 tod.second = 33; 8603 assert(tod == TimeOfDay(0, 0, 33)); 8604 8605 const ctod = TimeOfDay(0, 0, 0); 8606 immutable itod = TimeOfDay(0, 0, 0); 8607 static assert(!__traits(compiles, ctod.second = 33)); 8608 static assert(!__traits(compiles, itod.second = 33)); 8609 } 8610 8611 8612 /++ 8613 Adds the given number of units to this $(LREF TimeOfDay), mutating it. A 8614 negative number will subtract. 8615 8616 The difference between rolling and adding is that rolling does not 8617 affect larger units. For instance, rolling a $(LREF TimeOfDay) 8618 one hours's worth of minutes gets the exact same 8619 $(LREF TimeOfDay). 8620 8621 Accepted units are `"hours"`, `"minutes"`, and `"seconds"`. 8622 8623 Params: 8624 units = The units to add. 8625 value = The number of $(D_PARAM units) to add to this 8626 $(LREF TimeOfDay). 8627 8628 Returns: 8629 A reference to the `TimeOfDay` (`this`). 8630 +/ 8631 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8632 if (units == "hours") 8633 { 8634 import core.time : dur; 8635 return this += dur!"hours"(value); 8636 } 8637 8638 /// 8639 @safe unittest 8640 { 8641 auto tod1 = TimeOfDay(7, 12, 0); 8642 tod1.roll!"hours"(1); 8643 assert(tod1 == TimeOfDay(8, 12, 0)); 8644 8645 auto tod2 = TimeOfDay(7, 12, 0); 8646 tod2.roll!"hours"(-1); 8647 assert(tod2 == TimeOfDay(6, 12, 0)); 8648 8649 auto tod3 = TimeOfDay(23, 59, 0); 8650 tod3.roll!"minutes"(1); 8651 assert(tod3 == TimeOfDay(23, 0, 0)); 8652 8653 auto tod4 = TimeOfDay(0, 0, 0); 8654 tod4.roll!"minutes"(-1); 8655 assert(tod4 == TimeOfDay(0, 59, 0)); 8656 8657 auto tod5 = TimeOfDay(23, 59, 59); 8658 tod5.roll!"seconds"(1); 8659 assert(tod5 == TimeOfDay(23, 59, 0)); 8660 8661 auto tod6 = TimeOfDay(0, 0, 0); 8662 tod6.roll!"seconds"(-1); 8663 assert(tod6 == TimeOfDay(0, 0, 59)); 8664 } 8665 8666 @safe unittest 8667 { 8668 auto tod = TimeOfDay(12, 27, 2); 8669 tod.roll!"hours"(22).roll!"hours"(-7); 8670 assert(tod == TimeOfDay(3, 27, 2)); 8671 8672 const ctod = TimeOfDay(0, 0, 0); 8673 immutable itod = TimeOfDay(0, 0, 0); 8674 static assert(!__traits(compiles, ctod.roll!"hours"(53))); 8675 static assert(!__traits(compiles, itod.roll!"hours"(53))); 8676 } 8677 8678 8679 /// ditto 8680 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8681 if (units == "minutes" || units == "seconds") 8682 { 8683 import std.format : format; 8684 8685 enum memberVarStr = units[0 .. $ - 1]; 8686 value %= 60; 8687 mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr)); 8688 8689 if (value < 0) 8690 { 8691 if (newVal < 0) 8692 newVal += 60; 8693 } 8694 else if (newVal >= 60) 8695 newVal -= 60; 8696 8697 mixin(format("_%s = cast(ubyte) newVal;", memberVarStr)); 8698 return this; 8699 } 8700 8701 // Test roll!"minutes"(). 8702 @safe unittest 8703 { 8704 static void testTOD(TimeOfDay orig, int minutes, TimeOfDay expected, size_t line = __LINE__) 8705 { 8706 orig.roll!"minutes"(minutes); 8707 assert(orig == expected); 8708 } 8709 8710 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8711 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33)); 8712 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33)); 8713 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33)); 8714 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33)); 8715 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33)); 8716 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33)); 8717 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33)); 8718 testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33)); 8719 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33)); 8720 testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33)); 8721 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8722 testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33)); 8723 testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33)); 8724 testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33)); 8725 8726 testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33)); 8727 testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33)); 8728 testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33)); 8729 testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33)); 8730 testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33)); 8731 testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33)); 8732 testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33)); 8733 testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33)); 8734 8735 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33)); 8736 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33)); 8737 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33)); 8738 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33)); 8739 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33)); 8740 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33)); 8741 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33)); 8742 testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33)); 8743 testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33)); 8744 testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33)); 8745 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8746 testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33)); 8747 testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33)); 8748 testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33)); 8749 8750 testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33)); 8751 testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33)); 8752 testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33)); 8753 testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33)); 8754 testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33)); 8755 testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33)); 8756 testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33)); 8757 testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33)); 8758 8759 testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33)); 8760 testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33)); 8761 testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33)); 8762 8763 testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33)); 8764 testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33)); 8765 testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33)); 8766 8767 testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33)); 8768 testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33)); 8769 testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33)); 8770 8771 testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33)); 8772 testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33)); 8773 testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33)); 8774 8775 auto tod = TimeOfDay(12, 27, 2); 8776 tod.roll!"minutes"(97).roll!"minutes"(-102); 8777 assert(tod == TimeOfDay(12, 22, 2)); 8778 8779 const ctod = TimeOfDay(0, 0, 0); 8780 immutable itod = TimeOfDay(0, 0, 0); 8781 static assert(!__traits(compiles, ctod.roll!"minutes"(7))); 8782 static assert(!__traits(compiles, itod.roll!"minutes"(7))); 8783 } 8784 8785 // Test roll!"seconds"(). 8786 @safe unittest 8787 { 8788 static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) 8789 { 8790 orig.roll!"seconds"(seconds); 8791 assert(orig == expected); 8792 } 8793 8794 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8795 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 8796 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 8797 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 8798 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 8799 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 8800 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 8801 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 8802 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 8803 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0)); 8804 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3)); 8805 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32)); 8806 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8807 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34)); 8808 8809 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59)); 8810 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0)); 8811 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1)); 8812 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0)); 8813 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32)); 8814 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33)); 8815 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34)); 8816 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33)); 8817 8818 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 8819 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 8820 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 8821 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 8822 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 8823 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 8824 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 8825 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 8826 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59)); 8827 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58)); 8828 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34)); 8829 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8830 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32)); 8831 8832 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 8833 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 8834 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59)); 8835 8836 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 8837 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 8838 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59)); 8839 8840 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 8841 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 8842 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59)); 8843 8844 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0)); 8845 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 8846 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 8847 8848 auto tod = TimeOfDay(12, 27, 2); 8849 tod.roll!"seconds"(105).roll!"seconds"(-77); 8850 assert(tod == TimeOfDay(12, 27, 30)); 8851 8852 const ctod = TimeOfDay(0, 0, 0); 8853 immutable itod = TimeOfDay(0, 0, 0); 8854 static assert(!__traits(compiles, ctod.roll!"seconds"(7))); 8855 static assert(!__traits(compiles, itod.roll!"seconds"(7))); 8856 } 8857 8858 8859 import core.time : Duration; 8860 /++ 8861 Gives the result of adding or subtracting a $(REF Duration, core,time) 8862 from this $(LREF TimeOfDay). 8863 8864 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8865 are 8866 8867 $(BOOKTABLE, 8868 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8869 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8870 $(TR $(TD Duration) $(TD +) $(TD TimeOfDay) $(TD -->) $(TD TimeOfDay)) 8871 ) 8872 8873 Params: 8874 duration = The $(REF Duration, core,time) to add to or subtract from 8875 this $(LREF TimeOfDay). 8876 +/ 8877 TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 8878 if (op == "+" || op == "-") 8879 { 8880 TimeOfDay retval = this; 8881 immutable seconds = duration.total!"seconds"; 8882 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 8883 } 8884 8885 /// ditto 8886 TimeOfDay opBinaryRight(string op)(Duration duration) const @safe pure nothrow @nogc 8887 if (op == "+") 8888 { 8889 return this + duration; 8890 } 8891 8892 /// 8893 @safe unittest 8894 { 8895 import core.time : hours, minutes, seconds; 8896 8897 assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); 8898 assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); 8899 assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); 8900 assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); 8901 8902 assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); 8903 assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); 8904 assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); 8905 assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); 8906 8907 assert(TimeOfDay(12, 12, 12) + seconds(1) == seconds(1) + TimeOfDay(12, 12, 12)); 8908 } 8909 8910 @safe unittest 8911 { 8912 auto tod = TimeOfDay(12, 30, 33); 8913 8914 import core.time : dur; 8915 assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8916 assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8917 assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8918 assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8919 assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8920 assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8921 8922 assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8923 assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8924 assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8925 assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8926 assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8927 assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8928 8929 assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 8930 assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 8931 assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 8932 assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 8933 assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 8934 assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 8935 8936 assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 8937 assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 8938 assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 8939 assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 8940 assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 8941 assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 8942 8943 auto duration = dur!"hours"(11); 8944 const ctod = TimeOfDay(12, 30, 33); 8945 immutable itod = TimeOfDay(12, 30, 33); 8946 assert(tod + duration == TimeOfDay(23, 30, 33)); 8947 assert(ctod + duration == TimeOfDay(23, 30, 33)); 8948 assert(itod + duration == TimeOfDay(23, 30, 33)); 8949 8950 assert(tod - duration == TimeOfDay(1, 30, 33)); 8951 assert(ctod - duration == TimeOfDay(1, 30, 33)); 8952 assert(itod - duration == TimeOfDay(1, 30, 33)); 8953 } 8954 8955 8956 /++ 8957 Gives the result of adding or subtracting a $(REF Duration, core,time) 8958 from this $(LREF TimeOfDay), as well as assigning the result to this 8959 $(LREF TimeOfDay). 8960 8961 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8962 are 8963 8964 $(BOOKTABLE, 8965 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8966 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8967 ) 8968 8969 Params: 8970 duration = The $(REF Duration, core,time) to add to or subtract from 8971 this $(LREF TimeOfDay). 8972 +/ 8973 ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 8974 if (op == "+" || op == "-") 8975 { 8976 immutable seconds = duration.total!"seconds"; 8977 mixin("return _addSeconds(" ~ op ~ "seconds);"); 8978 } 8979 8980 @safe unittest 8981 { 8982 import core.time : dur; 8983 auto duration = dur!"hours"(12); 8984 8985 assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8986 assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8987 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8988 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8989 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8990 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8991 8992 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8993 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8994 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8995 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8996 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8997 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8998 8999 assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 9000 assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 9001 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 9002 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 9003 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 9004 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 9005 9006 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 9007 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 9008 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 9009 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 9010 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 9011 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 9012 9013 auto tod = TimeOfDay(19, 17, 22); 9014 (tod += dur!"seconds"(9)) += dur!"seconds"(-7292); 9015 assert(tod == TimeOfDay(17, 15, 59)); 9016 9017 const ctod = TimeOfDay(12, 33, 30); 9018 immutable itod = TimeOfDay(12, 33, 30); 9019 static assert(!__traits(compiles, ctod += duration)); 9020 static assert(!__traits(compiles, itod += duration)); 9021 static assert(!__traits(compiles, ctod -= duration)); 9022 static assert(!__traits(compiles, itod -= duration)); 9023 } 9024 9025 9026 /++ 9027 Gives the difference between two $(LREF TimeOfDay)s. 9028 9029 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 9030 are 9031 9032 $(BOOKTABLE, 9033 $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration)) 9034 ) 9035 9036 Params: 9037 rhs = The $(LREF TimeOfDay) to subtract from this one. 9038 +/ 9039 Duration opBinary(string op)(TimeOfDay rhs) const @safe pure nothrow @nogc 9040 if (op == "-") 9041 { 9042 immutable lhsSec = _hour * 3600 + _minute * 60 + _second; 9043 immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second; 9044 9045 import core.time : dur; 9046 return dur!"seconds"(lhsSec - rhsSec); 9047 } 9048 9049 @safe unittest 9050 { 9051 auto tod = TimeOfDay(12, 30, 33); 9052 9053 import core.time : dur; 9054 assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061)); 9055 assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061)); 9056 assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200)); 9057 assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200)); 9058 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240)); 9059 assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240)); 9060 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1)); 9061 assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1)); 9062 9063 const ctod = TimeOfDay(12, 30, 33); 9064 immutable itod = TimeOfDay(12, 30, 33); 9065 assert(tod - tod == Duration.zero); 9066 assert(ctod - tod == Duration.zero); 9067 assert(itod - tod == Duration.zero); 9068 9069 assert(tod - ctod == Duration.zero); 9070 assert(ctod - ctod == Duration.zero); 9071 assert(itod - ctod == Duration.zero); 9072 9073 assert(tod - itod == Duration.zero); 9074 assert(ctod - itod == Duration.zero); 9075 assert(itod - itod == Duration.zero); 9076 } 9077 9078 9079 /++ 9080 Converts this $(LREF TimeOfDay) to a string with the format `HHMMSS`. 9081 If `writer` is set, the resulting string will be written directly to it. 9082 9083 Params: 9084 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9085 Returns: 9086 A `string` when not using an output range; `void` otherwise. 9087 +/ 9088 string toISOString() const @safe pure nothrow 9089 { 9090 import std.array : appender; 9091 auto w = appender!string(); 9092 w.reserve(6); 9093 try 9094 toISOString(w); 9095 catch (Exception e) 9096 assert(0, "toISOString() threw."); 9097 return w.data; 9098 } 9099 9100 /// ditto 9101 void toISOString(W)(ref W writer) const 9102 if (isOutputRange!(W, char)) 9103 { 9104 import std.format.write : formattedWrite; 9105 formattedWrite(writer, "%02d%02d%02d", _hour, _minute, _second); 9106 } 9107 9108 /// 9109 @safe unittest 9110 { 9111 assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); 9112 assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); 9113 } 9114 9115 @safe unittest 9116 { 9117 auto tod = TimeOfDay(12, 30, 33); 9118 const ctod = TimeOfDay(12, 30, 33); 9119 immutable itod = TimeOfDay(12, 30, 33); 9120 assert(tod.toISOString() == "123033"); 9121 assert(ctod.toISOString() == "123033"); 9122 assert(itod.toISOString() == "123033"); 9123 } 9124 9125 9126 /++ 9127 Converts this $(LREF TimeOfDay) to a string with the format `HH:MM:SS`. 9128 If `writer` is set, the resulting string will be written directly to it. 9129 9130 Params: 9131 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9132 Returns: 9133 A `string` when not using an output range; `void` otherwise. 9134 +/ 9135 string toISOExtString() const @safe pure nothrow 9136 { 9137 import std.array : appender; 9138 auto w = appender!string(); 9139 w.reserve(8); 9140 try 9141 toISOExtString(w); 9142 catch (Exception e) 9143 assert(0, "toISOExtString() threw."); 9144 return w.data; 9145 } 9146 9147 /// ditto 9148 void toISOExtString(W)(ref W writer) const 9149 if (isOutputRange!(W, char)) 9150 { 9151 import std.format.write : formattedWrite; 9152 formattedWrite(writer, "%02d:%02d:%02d", _hour, _minute, _second); 9153 } 9154 9155 /// 9156 @safe unittest 9157 { 9158 assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); 9159 assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); 9160 } 9161 9162 @safe unittest 9163 { 9164 auto tod = TimeOfDay(12, 30, 33); 9165 const ctod = TimeOfDay(12, 30, 33); 9166 immutable itod = TimeOfDay(12, 30, 33); 9167 assert(tod.toISOExtString() == "12:30:33"); 9168 assert(ctod.toISOExtString() == "12:30:33"); 9169 assert(itod.toISOExtString() == "12:30:33"); 9170 } 9171 9172 9173 /++ 9174 Converts this TimeOfDay to a string. 9175 9176 This function exists to make it easy to convert a $(LREF TimeOfDay) to a 9177 string for code that does not care what the exact format is - just that 9178 it presents the information in a clear manner. It also makes it easy to 9179 simply convert a $(LREF TimeOfDay) to a string when using functions such 9180 as `to!string`, `format`, or `writeln` which use toString to convert 9181 user-defined types. So, it is unlikely that much code will call 9182 toString directly. 9183 9184 The format of the string is purposefully unspecified, and code that 9185 cares about the format of the string should use `toISOString`, 9186 `toISOExtString`, or some other custom formatting function that 9187 explicitly generates the format that the code needs. The reason is that 9188 the code is then clear about what format it's using, making it less 9189 error-prone to maintain the code and interact with other software that 9190 consumes the generated strings. It's for this same reason that 9191 $(LREF TimeOfDay) has no `fromString` function, whereas it does have 9192 `fromISOString` and `fromISOExtString`. 9193 9194 The format returned by toString may or may not change in the future. 9195 9196 Params: 9197 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9198 Returns: 9199 A `string` when not using an output range; `void` otherwise. 9200 +/ 9201 string toString() const @safe pure nothrow 9202 { 9203 return toISOExtString(); 9204 } 9205 9206 /// ditto 9207 void toString(W)(ref W writer) const 9208 if (isOutputRange!(W, char)) 9209 { 9210 toISOExtString(writer); 9211 } 9212 9213 @safe unittest 9214 { 9215 auto tod = TimeOfDay(12, 30, 33); 9216 const ctod = TimeOfDay(12, 30, 33); 9217 immutable itod = TimeOfDay(12, 30, 33); 9218 assert(tod.toString()); 9219 assert(ctod.toString()); 9220 assert(itod.toString()); 9221 } 9222 9223 9224 /++ 9225 Creates a $(LREF TimeOfDay) from a string with the format HHMMSS. 9226 Whitespace is stripped from the given string. 9227 9228 Params: 9229 isoString = A string formatted in the ISO format for times. 9230 9231 Throws: 9232 $(REF DateTimeException,std,datetime,date) if the given string is 9233 not in the ISO format or if the resulting $(LREF TimeOfDay) would 9234 not be valid. 9235 +/ 9236 static TimeOfDay fromISOString(S)(scope const S isoString) @safe pure 9237 if (isSomeString!S) 9238 { 9239 import std.conv : to, text, ConvException; 9240 import std.exception : enforce; 9241 import std.string : strip; 9242 9243 int hours, minutes, seconds; 9244 auto str = strip(isoString); 9245 9246 enforce!DateTimeException(str.length == 6, text("Invalid format for TimeOfDay.fromISOString: ", isoString)); 9247 9248 try 9249 { 9250 // cast to int from uint is used because it checks for 9251 // non digits without extra loops 9252 hours = cast(int) to!uint(str[0 .. 2]); 9253 minutes = cast(int) to!uint(str[2 .. 4]); 9254 seconds = cast(int) to!uint(str[4 .. $]); 9255 } 9256 catch (ConvException) 9257 { 9258 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOString: ", isoString)); 9259 } 9260 9261 return TimeOfDay(hours, minutes, seconds); 9262 } 9263 9264 /// 9265 @safe unittest 9266 { 9267 assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); 9268 assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); 9269 assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); 9270 } 9271 9272 @safe unittest 9273 { 9274 assertThrown!DateTimeException(TimeOfDay.fromISOString("")); 9275 assertThrown!DateTimeException(TimeOfDay.fromISOString("0")); 9276 assertThrown!DateTimeException(TimeOfDay.fromISOString("00")); 9277 assertThrown!DateTimeException(TimeOfDay.fromISOString("000")); 9278 assertThrown!DateTimeException(TimeOfDay.fromISOString("0000")); 9279 assertThrown!DateTimeException(TimeOfDay.fromISOString("00000")); 9280 assertThrown!DateTimeException(TimeOfDay.fromISOString("13033")); 9281 assertThrown!DateTimeException(TimeOfDay.fromISOString("1277")); 9282 assertThrown!DateTimeException(TimeOfDay.fromISOString("12707")); 9283 assertThrown!DateTimeException(TimeOfDay.fromISOString("12070")); 9284 assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a")); 9285 assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3")); 9286 assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33")); 9287 assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033")); 9288 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033")); 9289 assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033")); 9290 assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330")); 9291 assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033")); 9292 assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033")); 9293 assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033")); 9294 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am")); 9295 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm")); 9296 9297 assertThrown!DateTimeException(TimeOfDay.fromISOString("0::")); 9298 assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:")); 9299 assertThrown!DateTimeException(TimeOfDay.fromISOString("::0")); 9300 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0")); 9301 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00")); 9302 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0")); 9303 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0")); 9304 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0")); 9305 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00")); 9306 assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33")); 9307 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7")); 9308 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07")); 9309 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0")); 9310 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a")); 9311 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3")); 9312 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33")); 9313 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33")); 9314 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33")); 9315 assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33")); 9316 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30")); 9317 assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30")); 9318 assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33")); 9319 assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33")); 9320 assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33")); 9321 assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33")); 9322 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am")); 9323 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm")); 9324 9325 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33")); 9326 9327 assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17)); 9328 assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12)); 9329 assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7)); 9330 assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17)); 9331 assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17)); 9332 assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17)); 9333 } 9334 9335 // https://issues.dlang.org/show_bug.cgi?id=17801 9336 @safe unittest 9337 { 9338 import std.conv : to; 9339 import std.meta : AliasSeq; 9340 static foreach (C; AliasSeq!(char, wchar, dchar)) 9341 { 9342 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 9343 assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16)); 9344 } 9345 } 9346 9347 9348 /++ 9349 Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS. 9350 Whitespace is stripped from the given string. 9351 9352 Params: 9353 isoExtString = A string formatted in the ISO Extended format for 9354 times. 9355 9356 Throws: 9357 $(REF DateTimeException,std,datetime,date) if the given string is 9358 not in the ISO Extended format or if the resulting $(LREF TimeOfDay) 9359 would not be valid. 9360 +/ 9361 static TimeOfDay fromISOExtString(S)(scope const S isoExtString) @safe pure 9362 if (isSomeString!S) 9363 { 9364 import std.conv : ConvException, text, to; 9365 import std.string : strip; 9366 9367 auto str = strip(isoExtString); 9368 int hours, minutes, seconds; 9369 9370 if (str.length != 8 || str[2] != ':' || str[5] != ':') 9371 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString)); 9372 9373 try 9374 { 9375 // cast to int from uint is used because it checks for 9376 // non digits without extra loops 9377 hours = cast(int) to!uint(str[0 .. 2]); 9378 minutes = cast(int) to!uint(str[3 .. 5]); 9379 seconds = cast(int) to!uint(str[6 .. $]); 9380 } 9381 catch (ConvException) 9382 { 9383 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString)); 9384 } 9385 9386 return TimeOfDay(hours, minutes, seconds); 9387 } 9388 9389 /// 9390 @safe unittest 9391 { 9392 assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); 9393 assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); 9394 assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); 9395 } 9396 9397 @safe unittest 9398 { 9399 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("")); 9400 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0")); 9401 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00")); 9402 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000")); 9403 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000")); 9404 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000")); 9405 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033")); 9406 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277")); 9407 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707")); 9408 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070")); 9409 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a")); 9410 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3")); 9411 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33")); 9412 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033")); 9413 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033")); 9414 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033")); 9415 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330")); 9416 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033")); 9417 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033")); 9418 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033")); 9419 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am")); 9420 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm")); 9421 9422 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::")); 9423 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:")); 9424 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0")); 9425 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0")); 9426 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00")); 9427 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0")); 9428 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0")); 9429 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0")); 9430 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00")); 9431 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33")); 9432 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7")); 9433 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07")); 9434 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0")); 9435 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a")); 9436 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3")); 9437 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33")); 9438 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33")); 9439 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33")); 9440 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33")); 9441 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30")); 9442 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30")); 9443 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33")); 9444 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33")); 9445 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33")); 9446 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33")); 9447 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am")); 9448 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm")); 9449 9450 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033")); 9451 9452 assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17)); 9453 assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12)); 9454 assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7)); 9455 assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17)); 9456 assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17)); 9457 assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17)); 9458 } 9459 9460 // https://issues.dlang.org/show_bug.cgi?id=17801 9461 @safe unittest 9462 { 9463 import std.conv : to; 9464 import std.meta : AliasSeq; 9465 static foreach (C; AliasSeq!(char, wchar, dchar)) 9466 { 9467 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 9468 assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16)); 9469 } 9470 } 9471 9472 9473 /++ 9474 Returns midnight. 9475 +/ 9476 @property static TimeOfDay min() @safe pure nothrow @nogc 9477 { 9478 return TimeOfDay.init; 9479 } 9480 9481 @safe unittest 9482 { 9483 assert(TimeOfDay.min.hour == 0); 9484 assert(TimeOfDay.min.minute == 0); 9485 assert(TimeOfDay.min.second == 0); 9486 assert(TimeOfDay.min < TimeOfDay.max); 9487 } 9488 9489 9490 /++ 9491 Returns one second short of midnight. 9492 +/ 9493 @property static TimeOfDay max() @safe pure nothrow @nogc 9494 { 9495 auto tod = TimeOfDay.init; 9496 tod._hour = maxHour; 9497 tod._minute = maxMinute; 9498 tod._second = maxSecond; 9499 9500 return tod; 9501 } 9502 9503 @safe unittest 9504 { 9505 assert(TimeOfDay.max.hour == 23); 9506 assert(TimeOfDay.max.minute == 59); 9507 assert(TimeOfDay.max.second == 59); 9508 assert(TimeOfDay.max > TimeOfDay.min); 9509 } 9510 9511 9512 private: 9513 9514 /+ 9515 Add seconds to the time of day. Negative values will subtract. If the 9516 number of seconds overflows (or underflows), then the seconds will wrap, 9517 increasing (or decreasing) the number of minutes accordingly. If the 9518 number of minutes overflows (or underflows), then the minutes will wrap. 9519 If the number of minutes overflows(or underflows), then the hour will 9520 wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30). 9521 9522 Params: 9523 seconds = The number of seconds to add to this TimeOfDay. 9524 +/ 9525 ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc 9526 { 9527 import core.time : convert; 9528 long hnsecs = convert!("seconds", "hnsecs")(seconds); 9529 hnsecs += convert!("hours", "hnsecs")(_hour); 9530 hnsecs += convert!("minutes", "hnsecs")(_minute); 9531 hnsecs += convert!("seconds", "hnsecs")(_second); 9532 9533 hnsecs %= convert!("days", "hnsecs")(1); 9534 9535 if (hnsecs < 0) 9536 hnsecs += convert!("days", "hnsecs")(1); 9537 9538 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 9539 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 9540 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 9541 9542 _hour = cast(ubyte) newHours; 9543 _minute = cast(ubyte) newMinutes; 9544 _second = cast(ubyte) newSeconds; 9545 9546 return this; 9547 } 9548 9549 @safe unittest 9550 { 9551 static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) 9552 { 9553 orig._addSeconds(seconds); 9554 assert(orig == expected); 9555 } 9556 9557 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 9558 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 9559 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 9560 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 9561 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 9562 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 9563 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 9564 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 9565 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 9566 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0)); 9567 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3)); 9568 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32)); 9569 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33)); 9570 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34)); 9571 9572 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59)); 9573 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0)); 9574 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1)); 9575 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0)); 9576 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32)); 9577 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33)); 9578 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34)); 9579 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33)); 9580 9581 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 9582 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 9583 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 9584 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 9585 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 9586 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 9587 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 9588 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 9589 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59)); 9590 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58)); 9591 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34)); 9592 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33)); 9593 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32)); 9594 9595 testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0)); 9596 testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59)); 9597 testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33)); 9598 testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32)); 9599 testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59)); 9600 testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33)); 9601 9602 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 9603 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 9604 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59)); 9605 9606 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 9607 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 9608 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59)); 9609 9610 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 9611 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 9612 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59)); 9613 9614 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0)); 9615 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 9616 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 9617 9618 const ctod = TimeOfDay(0, 0, 0); 9619 immutable itod = TimeOfDay(0, 0, 0); 9620 static assert(!__traits(compiles, ctod._addSeconds(7))); 9621 static assert(!__traits(compiles, itod._addSeconds(7))); 9622 } 9623 9624 9625 /+ 9626 Whether the given values form a valid $(LREF TimeOfDay). 9627 +/ 9628 static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc 9629 { 9630 return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second); 9631 } 9632 9633 9634 @safe pure invariant() 9635 { 9636 import std.format : format; 9637 assert(_valid(_hour, _minute, _second), 9638 format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second)); 9639 } 9640 9641 9642 package: 9643 9644 ubyte _hour; 9645 ubyte _minute; 9646 ubyte _second; 9647 9648 enum ubyte maxHour = 24 - 1; 9649 enum ubyte maxMinute = 60 - 1; 9650 enum ubyte maxSecond = 60 - 1; 9651 } 9652 9653 /// 9654 @safe pure unittest 9655 { 9656 import core.time : minutes, seconds; 9657 9658 auto t = TimeOfDay(12, 30, 0); 9659 9660 t += 10.minutes + 100.seconds; 9661 assert(t == TimeOfDay(12, 41, 40)); 9662 9663 assert(t.toISOExtString() == "12:41:40"); 9664 assert(t.toISOString() == "124140"); 9665 9666 assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0)); 9667 assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0)); 9668 } 9669 9670 /++ 9671 Returns whether the given value is valid for the given unit type when in a 9672 time point. Naturally, a duration is not held to a particular range, but 9673 the values in a time point are (e.g. a month must be in the range of 9674 1 - 12 inclusive). 9675 9676 Params: 9677 units = The units of time to validate. 9678 value = The number to validate. 9679 +/ 9680 bool valid(string units)(int value) @safe pure nothrow @nogc 9681 if (units == "months" || 9682 units == "hours" || 9683 units == "minutes" || 9684 units == "seconds") 9685 { 9686 static if (units == "months") 9687 return value >= Month.jan && value <= Month.dec; 9688 else static if (units == "hours") 9689 return value >= 0 && value <= 23; 9690 else static if (units == "minutes") 9691 return value >= 0 && value <= 59; 9692 else static if (units == "seconds") 9693 return value >= 0 && value <= 59; 9694 } 9695 9696 /// 9697 @safe unittest 9698 { 9699 assert(valid!"hours"(12)); 9700 assert(!valid!"hours"(32)); 9701 assert(valid!"months"(12)); 9702 assert(!valid!"months"(13)); 9703 } 9704 9705 /++ 9706 Returns whether the given day is valid for the given year and month. 9707 9708 Params: 9709 units = The units of time to validate. 9710 year = The year of the day to validate. 9711 month = The month of the day to validate (January is 1). 9712 day = The day to validate. 9713 +/ 9714 bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc 9715 if (units == "days") 9716 { 9717 return day > 0 && day <= maxDay(year, month); 9718 } 9719 9720 /// 9721 @safe pure nothrow @nogc unittest 9722 { 9723 assert(valid!"days"(2016, 2, 29)); 9724 assert(!valid!"days"(2016, 2, 30)); 9725 assert(valid!"days"(2017, 2, 20)); 9726 assert(!valid!"days"(2017, 2, 29)); 9727 } 9728 9729 private short castToYear(int year, string file = __FILE__, size_t line = __LINE__) @safe pure 9730 { 9731 import std.conv : to, ConvOverflowException; 9732 import std.format : format; 9733 9734 try 9735 return year.to!short; 9736 catch (ConvOverflowException) 9737 throw new DateTimeException(format("year %s doesn't fit to Date.", year), file, line); 9738 } 9739 9740 /++ 9741 Params: 9742 units = The units of time to validate. 9743 value = The number to validate. 9744 file = The file that the $(LREF DateTimeException) will list if thrown. 9745 line = The line number that the $(LREF DateTimeException) will list if 9746 thrown. 9747 9748 Throws: 9749 $(LREF DateTimeException) if `valid!units(value)` is false. 9750 +/ 9751 void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure 9752 if (units == "months" || 9753 units == "hours" || 9754 units == "minutes" || 9755 units == "seconds") 9756 { 9757 import std.format : format; 9758 9759 static if (units == "months") 9760 { 9761 if (!valid!units(value)) 9762 throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line); 9763 } 9764 else static if (units == "hours") 9765 { 9766 if (!valid!units(value)) 9767 throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line); 9768 } 9769 else static if (units == "minutes") 9770 { 9771 if (!valid!units(value)) 9772 throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line); 9773 } 9774 else static if (units == "seconds") 9775 { 9776 if (!valid!units(value)) 9777 throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line); 9778 } 9779 } 9780 9781 /// 9782 @safe pure unittest 9783 { 9784 import std.exception : assertThrown, assertNotThrown; 9785 9786 assertNotThrown(enforceValid!"months"(10)); 9787 assertNotThrown(enforceValid!"seconds"(40)); 9788 9789 assertThrown!DateTimeException(enforceValid!"months"(0)); 9790 assertThrown!DateTimeException(enforceValid!"hours"(24)); 9791 assertThrown!DateTimeException(enforceValid!"minutes"(60)); 9792 assertThrown!DateTimeException(enforceValid!"seconds"(60)); 9793 } 9794 9795 9796 /++ 9797 Because the validity of the day number depends on both on the year 9798 and month of which the day is occurring, take all three variables 9799 to validate the day. 9800 9801 Params: 9802 units = The units of time to validate. 9803 year = The year of the day to validate. 9804 month = The month of the day to validate. 9805 day = The day to validate. 9806 file = The file that the $(LREF DateTimeException) will list if thrown. 9807 line = The line number that the $(LREF DateTimeException) will list if 9808 thrown. 9809 9810 Throws: 9811 $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false. 9812 +/ 9813 void enforceValid(string units) 9814 (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure 9815 if (units == "days") 9816 { 9817 import std.format : format; 9818 if (!valid!"days"(year, month, day)) 9819 throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line); 9820 } 9821 9822 /// 9823 @safe pure unittest 9824 { 9825 import std.exception : assertThrown, assertNotThrown; 9826 9827 assertNotThrown(enforceValid!"days"(2000, Month.jan, 1)); 9828 // leap year 9829 assertNotThrown(enforceValid!"days"(2000, Month.feb, 29)); 9830 9831 assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29)); 9832 assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32)); 9833 assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31)); 9834 } 9835 9836 9837 /++ 9838 Returns the number of days from the current day of the week to the given 9839 day of the week. If they are the same, then the result is 0. 9840 9841 Params: 9842 currDoW = The current day of the week. 9843 dow = The day of the week to get the number of days to. 9844 +/ 9845 int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc 9846 { 9847 if (currDoW == dow) 9848 return 0; 9849 if (currDoW < dow) 9850 return dow - currDoW; 9851 return DayOfWeek.sat - currDoW + dow + 1; 9852 } 9853 9854 /// 9855 @safe pure nothrow @nogc unittest 9856 { 9857 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9858 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9859 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9860 } 9861 9862 @safe unittest 9863 { 9864 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0); 9865 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1); 9866 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2); 9867 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3); 9868 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4); 9869 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5); 9870 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6); 9871 9872 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9873 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9874 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1); 9875 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9876 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3); 9877 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4); 9878 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5); 9879 9880 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5); 9881 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6); 9882 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0); 9883 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1); 9884 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2); 9885 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3); 9886 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4); 9887 9888 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4); 9889 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5); 9890 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6); 9891 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0); 9892 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1); 9893 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2); 9894 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3); 9895 9896 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3); 9897 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4); 9898 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5); 9899 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6); 9900 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0); 9901 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1); 9902 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2); 9903 9904 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2); 9905 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3); 9906 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4); 9907 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5); 9908 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6); 9909 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0); 9910 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1); 9911 9912 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1); 9913 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2); 9914 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3); 9915 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4); 9916 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5); 9917 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6); 9918 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0); 9919 } 9920 9921 9922 /++ 9923 Returns the number of months from the current months of the year to the 9924 given month of the year. If they are the same, then the result is 0. 9925 9926 Params: 9927 currMonth = The current month of the year. 9928 month = The month of the year to get the number of months to. 9929 +/ 9930 int monthsToMonth(int currMonth, int month) @safe pure 9931 { 9932 enforceValid!"months"(currMonth); 9933 enforceValid!"months"(month); 9934 9935 if (currMonth == month) 9936 return 0; 9937 if (currMonth < month) 9938 return month - currMonth; 9939 return Month.dec - currMonth + month; 9940 } 9941 9942 /// 9943 @safe pure unittest 9944 { 9945 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9946 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9947 assert(monthsToMonth(Month.jul, Month.oct) == 3); 9948 } 9949 9950 @safe unittest 9951 { 9952 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9953 assert(monthsToMonth(Month.jan, Month.feb) == 1); 9954 assert(monthsToMonth(Month.jan, Month.mar) == 2); 9955 assert(monthsToMonth(Month.jan, Month.apr) == 3); 9956 assert(monthsToMonth(Month.jan, Month.may) == 4); 9957 assert(monthsToMonth(Month.jan, Month.jun) == 5); 9958 assert(monthsToMonth(Month.jan, Month.jul) == 6); 9959 assert(monthsToMonth(Month.jan, Month.aug) == 7); 9960 assert(monthsToMonth(Month.jan, Month.sep) == 8); 9961 assert(monthsToMonth(Month.jan, Month.oct) == 9); 9962 assert(monthsToMonth(Month.jan, Month.nov) == 10); 9963 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9964 9965 assert(monthsToMonth(Month.may, Month.jan) == 8); 9966 assert(monthsToMonth(Month.may, Month.feb) == 9); 9967 assert(monthsToMonth(Month.may, Month.mar) == 10); 9968 assert(monthsToMonth(Month.may, Month.apr) == 11); 9969 assert(monthsToMonth(Month.may, Month.may) == 0); 9970 assert(monthsToMonth(Month.may, Month.jun) == 1); 9971 assert(monthsToMonth(Month.may, Month.jul) == 2); 9972 assert(monthsToMonth(Month.may, Month.aug) == 3); 9973 assert(monthsToMonth(Month.may, Month.sep) == 4); 9974 assert(monthsToMonth(Month.may, Month.oct) == 5); 9975 assert(monthsToMonth(Month.may, Month.nov) == 6); 9976 assert(monthsToMonth(Month.may, Month.dec) == 7); 9977 9978 assert(monthsToMonth(Month.oct, Month.jan) == 3); 9979 assert(monthsToMonth(Month.oct, Month.feb) == 4); 9980 assert(monthsToMonth(Month.oct, Month.mar) == 5); 9981 assert(monthsToMonth(Month.oct, Month.apr) == 6); 9982 assert(monthsToMonth(Month.oct, Month.may) == 7); 9983 assert(monthsToMonth(Month.oct, Month.jun) == 8); 9984 assert(monthsToMonth(Month.oct, Month.jul) == 9); 9985 assert(monthsToMonth(Month.oct, Month.aug) == 10); 9986 assert(monthsToMonth(Month.oct, Month.sep) == 11); 9987 assert(monthsToMonth(Month.oct, Month.oct) == 0); 9988 assert(monthsToMonth(Month.oct, Month.nov) == 1); 9989 assert(monthsToMonth(Month.oct, Month.dec) == 2); 9990 9991 assert(monthsToMonth(Month.dec, Month.jan) == 1); 9992 assert(monthsToMonth(Month.dec, Month.feb) == 2); 9993 assert(monthsToMonth(Month.dec, Month.mar) == 3); 9994 assert(monthsToMonth(Month.dec, Month.apr) == 4); 9995 assert(monthsToMonth(Month.dec, Month.may) == 5); 9996 assert(monthsToMonth(Month.dec, Month.jun) == 6); 9997 assert(monthsToMonth(Month.dec, Month.jul) == 7); 9998 assert(monthsToMonth(Month.dec, Month.aug) == 8); 9999 assert(monthsToMonth(Month.dec, Month.sep) == 9); 10000 assert(monthsToMonth(Month.dec, Month.oct) == 10); 10001 assert(monthsToMonth(Month.dec, Month.nov) == 11); 10002 assert(monthsToMonth(Month.dec, Month.dec) == 0); 10003 } 10004 10005 10006 /++ 10007 Whether the given Gregorian Year is a leap year. 10008 10009 Params: 10010 year = The year to to be tested. 10011 +/ 10012 bool yearIsLeapYear(int year) @safe pure nothrow @nogc 10013 { 10014 if (year % 400 == 0) 10015 return true; 10016 if (year % 100 == 0) 10017 return false; 10018 return year % 4 == 0; 10019 } 10020 10021 /// 10022 @safe unittest 10023 { 10024 foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) 10025 { 10026 assert(!yearIsLeapYear(year)); 10027 assert(!yearIsLeapYear(-year)); 10028 } 10029 10030 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 10031 { 10032 assert(yearIsLeapYear(year)); 10033 assert(yearIsLeapYear(-year)); 10034 } 10035 } 10036 10037 @safe unittest 10038 { 10039 import std.format : format; 10040 foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999, 10041 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011]) 10042 { 10043 assert(!yearIsLeapYear(year), format("year: %s.", year)); 10044 assert(!yearIsLeapYear(-year), format("year: %s.", year)); 10045 } 10046 10047 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 10048 { 10049 assert(yearIsLeapYear(year), format("year: %s.", year)); 10050 assert(yearIsLeapYear(-year), format("year: %s.", year)); 10051 } 10052 } 10053 10054 10055 /++ 10056 Whether the given type defines all of the necessary functions for it to 10057 function as a time point. 10058 10059 1. `T` must define a static property named `min` which is the smallest 10060 value of `T` as `Unqual!T`. 10061 10062 2. `T` must define a static property named `max` which is the largest 10063 value of `T` as `Unqual!T`. 10064 10065 3. `T` must define an `opBinary` for addition and subtraction that 10066 accepts $(REF Duration, core,time) and returns `Unqual!T`. 10067 10068 4. `T` must define an `opOpAssign` for addition and subtraction that 10069 accepts $(REF Duration, core,time) and returns $(D ref Unqual!T). 10070 10071 5. `T` must define a `opBinary` for subtraction which accepts `T` 10072 and returns $(REF Duration, core,time). 10073 +/ 10074 template isTimePoint(T) 10075 { 10076 import core.time : Duration; 10077 import std.traits : FunctionAttribute, functionAttributes, Unqual; 10078 10079 enum isTimePoint = hasMin && 10080 hasMax && 10081 hasOverloadedOpBinaryWithDuration && 10082 hasOverloadedOpAssignWithDuration && 10083 hasOverloadedOpBinaryWithSelf && 10084 !is(U == Duration); 10085 10086 private: 10087 10088 alias U = Unqual!T; 10089 10090 enum hasMin = __traits(hasMember, T, "min") && 10091 is(typeof(T.min) == U) && 10092 is(typeof({static assert(__traits(isStaticFunction, T.min));})); 10093 10094 enum hasMax = __traits(hasMember, T, "max") && 10095 is(typeof(T.max) == U) && 10096 is(typeof({static assert(__traits(isStaticFunction, T.max));})); 10097 10098 enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) && 10099 is(typeof(T.init - Duration.init) == U); 10100 10101 enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) && 10102 is(typeof(U.init -= Duration.init) == U) && 10103 is(typeof( 10104 { 10105 alias add = U.opOpAssign!"+"; 10106 alias sub = U.opOpAssign!"-"; 10107 alias FA = FunctionAttribute; 10108 static assert((functionAttributes!add & FA.ref_) != 0); 10109 static assert((functionAttributes!sub & FA.ref_) != 0); 10110 })); 10111 10112 enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration); 10113 } 10114 10115 /// 10116 @safe unittest 10117 { 10118 import core.time : Duration; 10119 import std.datetime.interval : Interval; 10120 import std.datetime.systime : SysTime; 10121 10122 static assert(isTimePoint!Date); 10123 static assert(isTimePoint!DateTime); 10124 static assert(isTimePoint!SysTime); 10125 static assert(isTimePoint!TimeOfDay); 10126 10127 static assert(!isTimePoint!int); 10128 static assert(!isTimePoint!Duration); 10129 static assert(!isTimePoint!(Interval!SysTime)); 10130 } 10131 10132 @safe unittest 10133 { 10134 import core.time; 10135 import std.datetime.interval; 10136 import std.datetime.systime; 10137 import std.meta : AliasSeq; 10138 10139 static foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay)) 10140 { 10141 static assert(isTimePoint!(const TP), TP.stringof); 10142 static assert(isTimePoint!(immutable TP), TP.stringof); 10143 } 10144 10145 static foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date)) 10146 static assert(!isTimePoint!T, T.stringof); 10147 } 10148 10149 10150 /++ 10151 Whether all of the given strings are valid units of time. 10152 10153 `"nsecs"` is not considered a valid unit of time. Nothing in std.datetime 10154 can handle precision greater than hnsecs, and the few functions in core.time 10155 which deal with "nsecs" deal with it explicitly. 10156 +/ 10157 bool validTimeUnits(string[] units...) @safe pure nothrow @nogc 10158 { 10159 import std.algorithm.searching : canFind; 10160 foreach (str; units) 10161 { 10162 if (!canFind(timeStrings[], str)) 10163 return false; 10164 } 10165 return true; 10166 } 10167 10168 /// 10169 @safe @nogc nothrow unittest 10170 { 10171 assert(validTimeUnits("msecs", "seconds", "minutes")); 10172 assert(validTimeUnits("days", "weeks", "months")); 10173 assert(!validTimeUnits("ms", "seconds", "minutes")); 10174 } 10175 10176 10177 /++ 10178 Compares two time unit strings. `"years"` are the largest units and 10179 `"hnsecs"` are the smallest. 10180 10181 Returns: 10182 $(BOOKTABLE, 10183 $(TR $(TD this < rhs) $(TD < 0)) 10184 $(TR $(TD this == rhs) $(TD 0)) 10185 $(TR $(TD this > rhs) $(TD > 0)) 10186 ) 10187 10188 Throws: 10189 $(LREF DateTimeException) if either of the given strings is not a valid 10190 time unit string. 10191 +/ 10192 int cmpTimeUnits(string lhs, string rhs) @safe pure 10193 { 10194 import std.algorithm.searching : countUntil; 10195 import std.exception : enforce; 10196 import std.format : format; 10197 10198 immutable indexOfLHS = countUntil(timeStrings, lhs); 10199 immutable indexOfRHS = countUntil(timeStrings, rhs); 10200 10201 enforce!DateTimeException(indexOfLHS != -1, format("%s is not a valid TimeString", lhs)); 10202 enforce!DateTimeException(indexOfRHS != -1, format("%s is not a valid TimeString", rhs)); 10203 10204 if (indexOfLHS < indexOfRHS) 10205 return -1; 10206 if (indexOfLHS > indexOfRHS) 10207 return 1; 10208 10209 return 0; 10210 } 10211 10212 /// 10213 @safe pure unittest 10214 { 10215 import std.exception : assertThrown; 10216 10217 assert(cmpTimeUnits("hours", "hours") == 0); 10218 assert(cmpTimeUnits("hours", "weeks") < 0); 10219 assert(cmpTimeUnits("months", "seconds") > 0); 10220 10221 assertThrown!DateTimeException(cmpTimeUnits("month", "second")); 10222 } 10223 10224 @safe unittest 10225 { 10226 foreach (i, outerUnits; timeStrings) 10227 { 10228 assert(cmpTimeUnits(outerUnits, outerUnits) == 0); 10229 10230 // For some reason, $ won't compile. 10231 foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length]) 10232 assert(cmpTimeUnits(outerUnits, innerUnits) == -1); 10233 } 10234 10235 foreach (i, outerUnits; timeStrings) 10236 { 10237 foreach (innerUnits; timeStrings[0 .. i]) 10238 assert(cmpTimeUnits(outerUnits, innerUnits) == 1); 10239 } 10240 } 10241 10242 10243 /++ 10244 Compares two time unit strings at compile time. `"years"` are the largest 10245 units and `"hnsecs"` are the smallest. 10246 10247 This template is used instead of `cmpTimeUnits` because exceptions 10248 can't be thrown at compile time and `cmpTimeUnits` must enforce that 10249 the strings it's given are valid time unit strings. This template uses a 10250 template constraint instead. 10251 10252 Returns: 10253 $(BOOKTABLE, 10254 $(TR $(TD this < rhs) $(TD < 0)) 10255 $(TR $(TD this == rhs) $(TD 0)) 10256 $(TR $(TD this > rhs) $(TD > 0)) 10257 ) 10258 +/ 10259 template CmpTimeUnits(string lhs, string rhs) 10260 if (validTimeUnits(lhs, rhs)) 10261 { 10262 enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs); 10263 } 10264 10265 /// 10266 @safe pure unittest 10267 { 10268 static assert(CmpTimeUnits!("years", "weeks") > 0); 10269 static assert(CmpTimeUnits!("days", "days") == 0); 10270 static assert(CmpTimeUnits!("seconds", "hours") < 0); 10271 } 10272 10273 // Helper function for CmpTimeUnits. 10274 private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc 10275 { 10276 import std.algorithm.searching : countUntil; 10277 auto tstrings = timeStrings; 10278 immutable indexOfLHS = countUntil(tstrings, lhs); 10279 immutable indexOfRHS = countUntil(tstrings, rhs); 10280 10281 if (indexOfLHS < indexOfRHS) 10282 return -1; 10283 if (indexOfLHS > indexOfRHS) 10284 return 1; 10285 10286 return 0; 10287 } 10288 10289 @safe unittest 10290 { 10291 static foreach (i; 0 .. timeStrings.length) 10292 { 10293 static assert(CmpTimeUnits!(timeStrings[i], timeStrings[i]) == 0); 10294 10295 static foreach (next; timeStrings[i + 1 .. $]) 10296 static assert(CmpTimeUnits!(timeStrings[i], next) == -1); 10297 10298 static foreach (prev; timeStrings[0 .. i]) 10299 static assert(CmpTimeUnits!(timeStrings[i], prev) == 1); 10300 } 10301 } 10302 10303 10304 package: 10305 10306 10307 /+ 10308 Array of the short (three letter) names of each month. 10309 +/ 10310 immutable string[12] _monthNames = ["Jan", 10311 "Feb", 10312 "Mar", 10313 "Apr", 10314 "May", 10315 "Jun", 10316 "Jul", 10317 "Aug", 10318 "Sep", 10319 "Oct", 10320 "Nov", 10321 "Dec"]; 10322 10323 /+ 10324 The maximum valid Day in the given month in the given year. 10325 10326 Params: 10327 year = The year to get the day for. 10328 month = The month of the Gregorian Calendar to get the day for. 10329 +/ 10330 ubyte maxDay(int year, int month) @safe pure nothrow @nogc 10331 in 10332 { 10333 assert(valid!"months"(month)); 10334 } 10335 do 10336 { 10337 switch (month) 10338 { 10339 case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec: 10340 return 31; 10341 case Month.feb: 10342 return yearIsLeapYear(year) ? 29 : 28; 10343 case Month.apr, Month.jun, Month.sep, Month.nov: 10344 return 30; 10345 default: 10346 assert(0, "Invalid month."); 10347 } 10348 } 10349 10350 @safe unittest 10351 { 10352 // Test A.D. 10353 assert(maxDay(1999, 1) == 31); 10354 assert(maxDay(1999, 2) == 28); 10355 assert(maxDay(1999, 3) == 31); 10356 assert(maxDay(1999, 4) == 30); 10357 assert(maxDay(1999, 5) == 31); 10358 assert(maxDay(1999, 6) == 30); 10359 assert(maxDay(1999, 7) == 31); 10360 assert(maxDay(1999, 8) == 31); 10361 assert(maxDay(1999, 9) == 30); 10362 assert(maxDay(1999, 10) == 31); 10363 assert(maxDay(1999, 11) == 30); 10364 assert(maxDay(1999, 12) == 31); 10365 10366 assert(maxDay(2000, 1) == 31); 10367 assert(maxDay(2000, 2) == 29); 10368 assert(maxDay(2000, 3) == 31); 10369 assert(maxDay(2000, 4) == 30); 10370 assert(maxDay(2000, 5) == 31); 10371 assert(maxDay(2000, 6) == 30); 10372 assert(maxDay(2000, 7) == 31); 10373 assert(maxDay(2000, 8) == 31); 10374 assert(maxDay(2000, 9) == 30); 10375 assert(maxDay(2000, 10) == 31); 10376 assert(maxDay(2000, 11) == 30); 10377 assert(maxDay(2000, 12) == 31); 10378 10379 // Test B.C. 10380 assert(maxDay(-1999, 1) == 31); 10381 assert(maxDay(-1999, 2) == 28); 10382 assert(maxDay(-1999, 3) == 31); 10383 assert(maxDay(-1999, 4) == 30); 10384 assert(maxDay(-1999, 5) == 31); 10385 assert(maxDay(-1999, 6) == 30); 10386 assert(maxDay(-1999, 7) == 31); 10387 assert(maxDay(-1999, 8) == 31); 10388 assert(maxDay(-1999, 9) == 30); 10389 assert(maxDay(-1999, 10) == 31); 10390 assert(maxDay(-1999, 11) == 30); 10391 assert(maxDay(-1999, 12) == 31); 10392 10393 assert(maxDay(-2000, 1) == 31); 10394 assert(maxDay(-2000, 2) == 29); 10395 assert(maxDay(-2000, 3) == 31); 10396 assert(maxDay(-2000, 4) == 30); 10397 assert(maxDay(-2000, 5) == 31); 10398 assert(maxDay(-2000, 6) == 30); 10399 assert(maxDay(-2000, 7) == 31); 10400 assert(maxDay(-2000, 8) == 31); 10401 assert(maxDay(-2000, 9) == 30); 10402 assert(maxDay(-2000, 10) == 31); 10403 assert(maxDay(-2000, 11) == 30); 10404 assert(maxDay(-2000, 12) == 31); 10405 } 10406 10407 /+ 10408 Splits out a particular unit from hnsecs and gives the value for that 10409 unit and the remaining hnsecs. It really shouldn't be used unless unless 10410 all units larger than the given units have already been split out. 10411 10412 Params: 10413 units = The units to split out. 10414 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left 10415 after splitting out the given units. 10416 10417 Returns: 10418 The number of the given units from converting hnsecs to those units. 10419 +/ 10420 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc 10421 if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) 10422 { 10423 import core.time : convert; 10424 immutable value = convert!("hnsecs", units)(hnsecs); 10425 hnsecs -= convert!(units, "hnsecs")(value); 10426 return value; 10427 } 10428 10429 @safe unittest 10430 { 10431 auto hnsecs = 2595000000007L; 10432 immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 10433 assert(days == 3); 10434 assert(hnsecs == 3000000007); 10435 10436 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 10437 assert(minutes == 5); 10438 assert(hnsecs == 7); 10439 } 10440 10441 10442 /+ 10443 Returns the day of the week for the given day of the Gregorian Calendar. 10444 10445 Params: 10446 day = The day of the Gregorian Calendar for which to get the day of 10447 the week. 10448 +/ 10449 DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc 10450 { 10451 // January 1st, 1 A.D. was a Monday 10452 if (day >= 0) 10453 return cast(DayOfWeek)(day % 7); 10454 else 10455 { 10456 immutable dow = cast(DayOfWeek)((day % 7) + 7); 10457 10458 if (dow == 7) 10459 return DayOfWeek.sun; 10460 else 10461 return dow; 10462 } 10463 } 10464 10465 @safe unittest 10466 { 10467 import std.datetime.systime : SysTime; 10468 10469 // Test A.D. 10470 assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon); 10471 assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue); 10472 assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed); 10473 assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu); 10474 assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri); 10475 assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat); 10476 assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun); 10477 assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon); 10478 assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue); 10479 assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue); 10480 assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed); 10481 assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu); 10482 assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 10483 assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 10484 assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun); 10485 assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon); 10486 assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue); 10487 assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed); 10488 assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu); 10489 assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri); 10490 assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat); 10491 assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun); 10492 10493 // Test B.C. 10494 assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun); 10495 assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat); 10496 assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri); 10497 assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu); 10498 assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed); 10499 assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue); 10500 assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon); 10501 assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun); 10502 assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat); 10503 } 10504 10505 10506 private: 10507 10508 enum daysInYear = 365; // The number of days in a non-leap year. 10509 enum daysInLeapYear = 366; // The numbef or days in a leap year. 10510 enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years. 10511 enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years. 10512 enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years. 10513 10514 /+ 10515 Array of integers representing the last days of each month in a year. 10516 +/ 10517 immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; 10518 10519 /+ 10520 Array of integers representing the last days of each month in a leap year. 10521 +/ 10522 immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; 10523 10524 10525 /+ 10526 Returns the string representation of the given month. 10527 +/ 10528 string monthToString(Month month) @safe pure 10529 { 10530 import std.format : format; 10531 assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month)); 10532 return _monthNames[month - Month.jan]; 10533 } 10534 10535 @safe unittest 10536 { 10537 assert(monthToString(Month.jan) == "Jan"); 10538 assert(monthToString(Month.feb) == "Feb"); 10539 assert(monthToString(Month.mar) == "Mar"); 10540 assert(monthToString(Month.apr) == "Apr"); 10541 assert(monthToString(Month.may) == "May"); 10542 assert(monthToString(Month.jun) == "Jun"); 10543 assert(monthToString(Month.jul) == "Jul"); 10544 assert(monthToString(Month.aug) == "Aug"); 10545 assert(monthToString(Month.sep) == "Sep"); 10546 assert(monthToString(Month.oct) == "Oct"); 10547 assert(monthToString(Month.nov) == "Nov"); 10548 assert(monthToString(Month.dec) == "Dec"); 10549 } 10550 10551 10552 /+ 10553 Returns the Month corresponding to the given string. 10554 10555 Params: 10556 monthStr = The string representation of the month to get the Month for. 10557 10558 Throws: 10559 $(REF DateTimeException,std,datetime,date) if the given month is not a 10560 valid month string. 10561 +/ 10562 Month monthFromString(T)(T monthStr) @safe pure 10563 if (isSomeString!T) 10564 { 10565 import std.format : format; 10566 switch (monthStr) 10567 { 10568 case "Jan": 10569 return Month.jan; 10570 case "Feb": 10571 return Month.feb; 10572 case "Mar": 10573 return Month.mar; 10574 case "Apr": 10575 return Month.apr; 10576 case "May": 10577 return Month.may; 10578 case "Jun": 10579 return Month.jun; 10580 case "Jul": 10581 return Month.jul; 10582 case "Aug": 10583 return Month.aug; 10584 case "Sep": 10585 return Month.sep; 10586 case "Oct": 10587 return Month.oct; 10588 case "Nov": 10589 return Month.nov; 10590 case "Dec": 10591 return Month.dec; 10592 default: 10593 throw new DateTimeException(format!"Invalid month %s"(monthStr)); 10594 } 10595 } 10596 10597 @safe unittest 10598 { 10599 import std.conv : to; 10600 import std.traits : EnumMembers; 10601 foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY", 10602 "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"]) 10603 { 10604 assertThrown!DateTimeException(monthFromString(badStr), badStr); 10605 } 10606 10607 foreach (month; EnumMembers!Month) 10608 { 10609 assert(monthFromString(monthToString(month)) == month, month.to!string); 10610 } 10611 } 10612 10613 10614 // NOTE: all the non-simple array literals are wrapped in functions, because 10615 // otherwise importing causes re-evaluation of the static initializers using 10616 // CTFE with unittests enabled 10617 version (StdUnittest) 10618 { 10619 private @safe: 10620 // All of these helper arrays are sorted in ascending order. 10621 auto testYearsBC = [-1999, -1200, -600, -4, -1, 0]; 10622 auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012]; 10623 10624 // I'd use a Tuple, but I get forward reference errors if I try. 10625 struct MonthDay 10626 { 10627 Month month; 10628 short day; 10629 10630 this(int m, short d) 10631 { 10632 month = cast(Month) m; 10633 day = d; 10634 } 10635 } 10636 10637 MonthDay[] testMonthDays() 10638 { 10639 static MonthDay[] result = [MonthDay(1, 1), 10640 MonthDay(1, 2), 10641 MonthDay(3, 17), 10642 MonthDay(7, 4), 10643 MonthDay(10, 27), 10644 MonthDay(12, 30), 10645 MonthDay(12, 31)]; 10646 return result; 10647 } 10648 10649 auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31]; 10650 10651 TimeOfDay[] testTODs() 10652 { 10653 static result = [TimeOfDay(0, 0, 0), 10654 TimeOfDay(0, 0, 1), 10655 TimeOfDay(0, 1, 0), 10656 TimeOfDay(1, 0, 0), 10657 TimeOfDay(13, 13, 13), 10658 TimeOfDay(23, 59, 59)]; 10659 return result; 10660 } 10661 10662 auto testHours = [0, 1, 12, 22, 23]; 10663 auto testMinSecs = [0, 1, 30, 58, 59]; 10664 10665 // Throwing exceptions is incredibly expensive, so we want to use a smaller 10666 // set of values for tests using assertThrown. 10667 TimeOfDay[] testTODsThrown() 10668 { 10669 static result = [TimeOfDay(0, 0, 0), 10670 TimeOfDay(13, 13, 13), 10671 TimeOfDay(23, 59, 59)]; 10672 return result; 10673 } 10674 10675 Date[] testDatesBC; 10676 Date[] testDatesAD; 10677 10678 DateTime[] testDateTimesBC; 10679 DateTime[] testDateTimesAD; 10680 10681 // I'd use a Tuple, but I get forward reference errors if I try. 10682 struct GregDay { int day; Date date; } 10683 GregDay[] testGregDaysBC() 10684 { 10685 static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar 10686 GregDay(-735_233, Date(-2012, 1, 1)), 10687 GregDay(-735_202, Date(-2012, 2, 1)), 10688 GregDay(-735_175, Date(-2012, 2, 28)), 10689 GregDay(-735_174, Date(-2012, 2, 29)), 10690 GregDay(-735_173, Date(-2012, 3, 1)), 10691 GregDay(-734_502, Date(-2010, 1, 1)), 10692 GregDay(-734_472, Date(-2010, 1, 31)), 10693 GregDay(-734_471, Date(-2010, 2, 1)), 10694 GregDay(-734_444, Date(-2010, 2, 28)), 10695 GregDay(-734_443, Date(-2010, 3, 1)), 10696 GregDay(-734_413, Date(-2010, 3, 31)), 10697 GregDay(-734_412, Date(-2010, 4, 1)), 10698 GregDay(-734_383, Date(-2010, 4, 30)), 10699 GregDay(-734_382, Date(-2010, 5, 1)), 10700 GregDay(-734_352, Date(-2010, 5, 31)), 10701 GregDay(-734_351, Date(-2010, 6, 1)), 10702 GregDay(-734_322, Date(-2010, 6, 30)), 10703 GregDay(-734_321, Date(-2010, 7, 1)), 10704 GregDay(-734_291, Date(-2010, 7, 31)), 10705 GregDay(-734_290, Date(-2010, 8, 1)), 10706 GregDay(-734_260, Date(-2010, 8, 31)), 10707 GregDay(-734_259, Date(-2010, 9, 1)), 10708 GregDay(-734_230, Date(-2010, 9, 30)), 10709 GregDay(-734_229, Date(-2010, 10, 1)), 10710 GregDay(-734_199, Date(-2010, 10, 31)), 10711 GregDay(-734_198, Date(-2010, 11, 1)), 10712 GregDay(-734_169, Date(-2010, 11, 30)), 10713 GregDay(-734_168, Date(-2010, 12, 1)), 10714 GregDay(-734_139, Date(-2010, 12, 30)), 10715 GregDay(-734_138, Date(-2010, 12, 31)), 10716 GregDay(-731_215, Date(-2001, 1, 1)), 10717 GregDay(-730_850, Date(-2000, 1, 1)), 10718 GregDay(-730_849, Date(-2000, 1, 2)), 10719 GregDay(-730_486, Date(-2000, 12, 30)), 10720 GregDay(-730_485, Date(-2000, 12, 31)), 10721 GregDay(-730_484, Date(-1999, 1, 1)), 10722 GregDay(-694_690, Date(-1901, 1, 1)), 10723 GregDay(-694_325, Date(-1900, 1, 1)), 10724 GregDay(-585_118, Date(-1601, 1, 1)), 10725 GregDay(-584_753, Date(-1600, 1, 1)), 10726 GregDay(-584_388, Date(-1600, 12, 31)), 10727 GregDay(-584_387, Date(-1599, 1, 1)), 10728 GregDay(-365_972, Date(-1001, 1, 1)), 10729 GregDay(-365_607, Date(-1000, 1, 1)), 10730 GregDay(-183_351, Date(-501, 1, 1)), 10731 GregDay(-182_986, Date(-500, 1, 1)), 10732 GregDay(-182_621, Date(-499, 1, 1)), 10733 GregDay(-146_827, Date(-401, 1, 1)), 10734 GregDay(-146_462, Date(-400, 1, 1)), 10735 GregDay(-146_097, Date(-400, 12, 31)), 10736 GregDay(-110_302, Date(-301, 1, 1)), 10737 GregDay(-109_937, Date(-300, 1, 1)), 10738 GregDay(-73_778, Date(-201, 1, 1)), 10739 GregDay(-73_413, Date(-200, 1, 1)), 10740 GregDay(-38_715, Date(-105, 1, 1)), 10741 GregDay(-37_254, Date(-101, 1, 1)), 10742 GregDay(-36_889, Date(-100, 1, 1)), 10743 GregDay(-36_524, Date(-99, 1, 1)), 10744 GregDay(-36_160, Date(-99, 12, 31)), 10745 GregDay(-35_794, Date(-97, 1, 1)), 10746 GregDay(-18_627, Date(-50, 1, 1)), 10747 GregDay(-18_262, Date(-49, 1, 1)), 10748 GregDay(-3652, Date(-9, 1, 1)), 10749 GregDay(-2191, Date(-5, 1, 1)), 10750 GregDay(-1827, Date(-5, 12, 31)), 10751 GregDay(-1826, Date(-4, 1, 1)), 10752 GregDay(-1825, Date(-4, 1, 2)), 10753 GregDay(-1462, Date(-4, 12, 30)), 10754 GregDay(-1461, Date(-4, 12, 31)), 10755 GregDay(-1460, Date(-3, 1, 1)), 10756 GregDay(-1096, Date(-3, 12, 31)), 10757 GregDay(-1095, Date(-2, 1, 1)), 10758 GregDay(-731, Date(-2, 12, 31)), 10759 GregDay(-730, Date(-1, 1, 1)), 10760 GregDay(-367, Date(-1, 12, 30)), 10761 GregDay(-366, Date(-1, 12, 31)), 10762 GregDay(-365, Date(0, 1, 1)), 10763 GregDay(-31, Date(0, 11, 30)), 10764 GregDay(-30, Date(0, 12, 1)), 10765 GregDay(-1, Date(0, 12, 30)), 10766 GregDay(0, Date(0, 12, 31))]; 10767 return result; 10768 } 10769 10770 GregDay[] testGregDaysAD() 10771 { 10772 static result = [GregDay(1, Date(1, 1, 1)), 10773 GregDay(2, Date(1, 1, 2)), 10774 GregDay(32, Date(1, 2, 1)), 10775 GregDay(365, Date(1, 12, 31)), 10776 GregDay(366, Date(2, 1, 1)), 10777 GregDay(731, Date(3, 1, 1)), 10778 GregDay(1096, Date(4, 1, 1)), 10779 GregDay(1097, Date(4, 1, 2)), 10780 GregDay(1460, Date(4, 12, 30)), 10781 GregDay(1461, Date(4, 12, 31)), 10782 GregDay(1462, Date(5, 1, 1)), 10783 GregDay(17_898, Date(50, 1, 1)), 10784 GregDay(35_065, Date(97, 1, 1)), 10785 GregDay(36_160, Date(100, 1, 1)), 10786 GregDay(36_525, Date(101, 1, 1)), 10787 GregDay(37_986, Date(105, 1, 1)), 10788 GregDay(72_684, Date(200, 1, 1)), 10789 GregDay(73_049, Date(201, 1, 1)), 10790 GregDay(109_208, Date(300, 1, 1)), 10791 GregDay(109_573, Date(301, 1, 1)), 10792 GregDay(145_732, Date(400, 1, 1)), 10793 GregDay(146_098, Date(401, 1, 1)), 10794 GregDay(182_257, Date(500, 1, 1)), 10795 GregDay(182_622, Date(501, 1, 1)), 10796 GregDay(364_878, Date(1000, 1, 1)), 10797 GregDay(365_243, Date(1001, 1, 1)), 10798 GregDay(584_023, Date(1600, 1, 1)), 10799 GregDay(584_389, Date(1601, 1, 1)), 10800 GregDay(693_596, Date(1900, 1, 1)), 10801 GregDay(693_961, Date(1901, 1, 1)), 10802 GregDay(729_755, Date(1999, 1, 1)), 10803 GregDay(730_120, Date(2000, 1, 1)), 10804 GregDay(730_121, Date(2000, 1, 2)), 10805 GregDay(730_484, Date(2000, 12, 30)), 10806 GregDay(730_485, Date(2000, 12, 31)), 10807 GregDay(730_486, Date(2001, 1, 1)), 10808 GregDay(733_773, Date(2010, 1, 1)), 10809 GregDay(733_774, Date(2010, 1, 2)), 10810 GregDay(733_803, Date(2010, 1, 31)), 10811 GregDay(733_804, Date(2010, 2, 1)), 10812 GregDay(733_831, Date(2010, 2, 28)), 10813 GregDay(733_832, Date(2010, 3, 1)), 10814 GregDay(733_862, Date(2010, 3, 31)), 10815 GregDay(733_863, Date(2010, 4, 1)), 10816 GregDay(733_892, Date(2010, 4, 30)), 10817 GregDay(733_893, Date(2010, 5, 1)), 10818 GregDay(733_923, Date(2010, 5, 31)), 10819 GregDay(733_924, Date(2010, 6, 1)), 10820 GregDay(733_953, Date(2010, 6, 30)), 10821 GregDay(733_954, Date(2010, 7, 1)), 10822 GregDay(733_984, Date(2010, 7, 31)), 10823 GregDay(733_985, Date(2010, 8, 1)), 10824 GregDay(734_015, Date(2010, 8, 31)), 10825 GregDay(734_016, Date(2010, 9, 1)), 10826 GregDay(734_045, Date(2010, 9, 30)), 10827 GregDay(734_046, Date(2010, 10, 1)), 10828 GregDay(734_076, Date(2010, 10, 31)), 10829 GregDay(734_077, Date(2010, 11, 1)), 10830 GregDay(734_106, Date(2010, 11, 30)), 10831 GregDay(734_107, Date(2010, 12, 1)), 10832 GregDay(734_136, Date(2010, 12, 30)), 10833 GregDay(734_137, Date(2010, 12, 31)), 10834 GregDay(734_503, Date(2012, 1, 1)), 10835 GregDay(734_534, Date(2012, 2, 1)), 10836 GregDay(734_561, Date(2012, 2, 28)), 10837 GregDay(734_562, Date(2012, 2, 29)), 10838 GregDay(734_563, Date(2012, 3, 1)), 10839 GregDay(734_858, Date(2012, 12, 21))]; 10840 return result; 10841 } 10842 10843 // I'd use a Tuple, but I get forward reference errors if I try. 10844 struct DayOfYear { int day; MonthDay md; } 10845 DayOfYear[] testDaysOfYear() 10846 { 10847 static result = [DayOfYear(1, MonthDay(1, 1)), 10848 DayOfYear(2, MonthDay(1, 2)), 10849 DayOfYear(3, MonthDay(1, 3)), 10850 DayOfYear(31, MonthDay(1, 31)), 10851 DayOfYear(32, MonthDay(2, 1)), 10852 DayOfYear(59, MonthDay(2, 28)), 10853 DayOfYear(60, MonthDay(3, 1)), 10854 DayOfYear(90, MonthDay(3, 31)), 10855 DayOfYear(91, MonthDay(4, 1)), 10856 DayOfYear(120, MonthDay(4, 30)), 10857 DayOfYear(121, MonthDay(5, 1)), 10858 DayOfYear(151, MonthDay(5, 31)), 10859 DayOfYear(152, MonthDay(6, 1)), 10860 DayOfYear(181, MonthDay(6, 30)), 10861 DayOfYear(182, MonthDay(7, 1)), 10862 DayOfYear(212, MonthDay(7, 31)), 10863 DayOfYear(213, MonthDay(8, 1)), 10864 DayOfYear(243, MonthDay(8, 31)), 10865 DayOfYear(244, MonthDay(9, 1)), 10866 DayOfYear(273, MonthDay(9, 30)), 10867 DayOfYear(274, MonthDay(10, 1)), 10868 DayOfYear(304, MonthDay(10, 31)), 10869 DayOfYear(305, MonthDay(11, 1)), 10870 DayOfYear(334, MonthDay(11, 30)), 10871 DayOfYear(335, MonthDay(12, 1)), 10872 DayOfYear(363, MonthDay(12, 29)), 10873 DayOfYear(364, MonthDay(12, 30)), 10874 DayOfYear(365, MonthDay(12, 31))]; 10875 return result; 10876 } 10877 10878 DayOfYear[] testDaysOfLeapYear() 10879 { 10880 static result = [DayOfYear(1, MonthDay(1, 1)), 10881 DayOfYear(2, MonthDay(1, 2)), 10882 DayOfYear(3, MonthDay(1, 3)), 10883 DayOfYear(31, MonthDay(1, 31)), 10884 DayOfYear(32, MonthDay(2, 1)), 10885 DayOfYear(59, MonthDay(2, 28)), 10886 DayOfYear(60, MonthDay(2, 29)), 10887 DayOfYear(61, MonthDay(3, 1)), 10888 DayOfYear(91, MonthDay(3, 31)), 10889 DayOfYear(92, MonthDay(4, 1)), 10890 DayOfYear(121, MonthDay(4, 30)), 10891 DayOfYear(122, MonthDay(5, 1)), 10892 DayOfYear(152, MonthDay(5, 31)), 10893 DayOfYear(153, MonthDay(6, 1)), 10894 DayOfYear(182, MonthDay(6, 30)), 10895 DayOfYear(183, MonthDay(7, 1)), 10896 DayOfYear(213, MonthDay(7, 31)), 10897 DayOfYear(214, MonthDay(8, 1)), 10898 DayOfYear(244, MonthDay(8, 31)), 10899 DayOfYear(245, MonthDay(9, 1)), 10900 DayOfYear(274, MonthDay(9, 30)), 10901 DayOfYear(275, MonthDay(10, 1)), 10902 DayOfYear(305, MonthDay(10, 31)), 10903 DayOfYear(306, MonthDay(11, 1)), 10904 DayOfYear(335, MonthDay(11, 30)), 10905 DayOfYear(336, MonthDay(12, 1)), 10906 DayOfYear(364, MonthDay(12, 29)), 10907 DayOfYear(365, MonthDay(12, 30)), 10908 DayOfYear(366, MonthDay(12, 31))]; 10909 return result; 10910 } 10911 10912 void initializeTests() 10913 { 10914 foreach (year; testYearsBC) 10915 { 10916 foreach (md; testMonthDays) 10917 testDatesBC ~= Date(year, md.month, md.day); 10918 } 10919 10920 foreach (year; testYearsAD) 10921 { 10922 foreach (md; testMonthDays) 10923 testDatesAD ~= Date(year, md.month, md.day); 10924 } 10925 10926 foreach (dt; testDatesBC) 10927 { 10928 foreach (tod; testTODs) 10929 testDateTimesBC ~= DateTime(dt, tod); 10930 } 10931 10932 foreach (dt; testDatesAD) 10933 { 10934 foreach (tod; testTODs) 10935 testDateTimesAD ~= DateTime(dt, tod); 10936 } 10937 } 10938 }