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 ) 2135 2136 Params: 2137 duration = The $(REF Duration, core,time) to add to or subtract from 2138 this $(LREF DateTime). 2139 +/ 2140 DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 2141 if (op == "+" || op == "-") 2142 { 2143 DateTime retval = this; 2144 immutable seconds = duration.total!"seconds"; 2145 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 2146 } 2147 2148 /// 2149 @safe unittest 2150 { 2151 import core.time : hours, seconds; 2152 2153 assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == 2154 DateTime(2016, 1, 1, 0, 0, 0)); 2155 2156 assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == 2157 DateTime(2016, 1, 1, 0, 59, 59)); 2158 2159 assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == 2160 DateTime(2015, 12, 31, 23, 59, 59)); 2161 2162 assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == 2163 DateTime(2015, 12, 31, 23, 59, 59)); 2164 } 2165 2166 @safe unittest 2167 { 2168 import core.time : dur; 2169 2170 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2171 2172 assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2173 assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2174 assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2175 assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2176 2177 assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2178 assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2179 assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2180 assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2181 assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2182 assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2183 assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2184 assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2185 assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2186 assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2187 assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2188 assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2189 2190 assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2191 assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2192 assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2193 assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2194 2195 assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2196 assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2197 assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2198 assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2199 assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2200 assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2201 assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2202 assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2203 assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2204 assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2205 assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2206 assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2207 2208 auto duration = dur!"seconds"(12); 2209 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2210 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2211 assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2212 assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2213 assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2214 assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2215 } 2216 2217 2218 /++ 2219 Gives the result of adding or subtracting a duration from this 2220 $(LREF DateTime), as well as assigning the result to this 2221 $(LREF DateTime). 2222 2223 The legal types of arithmetic for $(LREF DateTime) using this operator 2224 are 2225 2226 $(BOOKTABLE, 2227 $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime)) 2228 $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime)) 2229 ) 2230 2231 Params: 2232 duration = The duration to add to or subtract from this 2233 $(LREF DateTime). 2234 +/ 2235 ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 2236 if (op == "+" || op == "-") 2237 { 2238 import core.time : convert; 2239 import std.format : format; 2240 2241 DateTime retval = this; 2242 immutable hnsecs = duration.total!"hnsecs"; 2243 2244 mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op)); 2245 } 2246 2247 @safe unittest 2248 { 2249 import core.time : dur; 2250 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == 2251 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2252 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == 2253 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2254 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == 2255 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2256 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == 2257 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2258 2259 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == 2260 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2261 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == 2262 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2263 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == 2264 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2265 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == 2266 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2267 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == 2268 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2269 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == 2270 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2271 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == 2272 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2273 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == 2274 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2275 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == 2276 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2277 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == 2278 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2279 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == 2280 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2281 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == 2282 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2283 2284 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == 2285 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2286 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == 2287 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2288 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == 2289 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2290 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == 2291 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2292 2293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == 2294 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2295 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == 2296 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2297 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == 2298 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2299 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == 2300 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2301 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == 2302 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2303 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == 2304 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2305 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == 2306 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2307 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == 2308 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2309 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == 2310 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2311 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == 2312 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2313 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == 2314 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2315 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == 2316 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2317 2318 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 2319 (dt += dur!"seconds"(92)) -= dur!"days"(-500); 2320 assert(dt == DateTime(2001, 6, 14, 9, 8, 38)); 2321 2322 auto duration = dur!"seconds"(12); 2323 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2324 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2325 static assert(!__traits(compiles, cdt += duration)); 2326 static assert(!__traits(compiles, idt += duration)); 2327 static assert(!__traits(compiles, cdt -= duration)); 2328 static assert(!__traits(compiles, idt -= duration)); 2329 } 2330 2331 2332 /++ 2333 Gives the difference between two $(LREF DateTime)s. 2334 2335 The legal types of arithmetic for $(LREF DateTime) using this operator are 2336 2337 $(BOOKTABLE, 2338 $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration)) 2339 ) 2340 +/ 2341 Duration opBinary(string op)(DateTime rhs) const @safe pure nothrow @nogc 2342 if (op == "-") 2343 { 2344 immutable dateResult = _date - rhs.date; 2345 immutable todResult = _tod - rhs._tod; 2346 2347 import core.time : dur; 2348 return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs"); 2349 } 2350 2351 @safe unittest 2352 { 2353 auto dt = DateTime(1999, 7, 6, 12, 30, 33); 2354 2355 import core.time : dur; 2356 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) == 2357 dur!"seconds"(31_536_000)); 2358 assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2359 dur!"seconds"(-31_536_000)); 2360 2361 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2362 dur!"seconds"(26_78_400)); 2363 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) == 2364 dur!"seconds"(-26_78_400)); 2365 2366 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) == 2367 dur!"seconds"(86_400)); 2368 assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2369 dur!"seconds"(-86_400)); 2370 2371 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) == 2372 dur!"seconds"(3600)); 2373 assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2374 dur!"seconds"(-3600)); 2375 2376 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2377 dur!"seconds"(60)); 2378 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) == 2379 dur!"seconds"(-60)); 2380 2381 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2382 dur!"seconds"(1)); 2383 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) == 2384 dur!"seconds"(-1)); 2385 2386 assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033)); 2387 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033)); 2388 assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367)); 2389 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367)); 2390 2391 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2392 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2393 assert(dt - dt == Duration.zero); 2394 assert(cdt - dt == Duration.zero); 2395 assert(idt - dt == Duration.zero); 2396 2397 assert(dt - cdt == Duration.zero); 2398 assert(cdt - cdt == Duration.zero); 2399 assert(idt - cdt == Duration.zero); 2400 2401 assert(dt - idt == Duration.zero); 2402 assert(cdt - idt == Duration.zero); 2403 assert(idt - idt == Duration.zero); 2404 } 2405 2406 2407 /++ 2408 Returns the difference between the two $(LREF DateTime)s in months. 2409 2410 To get the difference in years, subtract the year property 2411 of two $(LREF DateTime)s. To get the difference in days or weeks, 2412 subtract the $(LREF DateTime)s themselves and use the 2413 $(REF Duration, core,time) that results. Because converting between 2414 months and smaller units requires a specific date (which 2415 $(REF Duration, core,time)s don't have), getting the difference in 2416 months requires some math using both the year and month properties, so 2417 this is a convenience function for getting the difference in months. 2418 2419 Note that the number of days in the months or how far into the month 2420 either date is is irrelevant. It is the difference in the month property 2421 combined with the difference in years * 12. So, for instance, 2422 December 31st and January 1st are one month apart just as December 1st 2423 and January 31st are one month apart. 2424 2425 Params: 2426 rhs = The $(LREF DateTime) to subtract from this one. 2427 +/ 2428 int diffMonths(DateTime rhs) const @safe pure nothrow @nogc 2429 { 2430 return _date.diffMonths(rhs._date); 2431 } 2432 2433 /// 2434 @safe unittest 2435 { 2436 assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( 2437 DateTime(1999, 1, 31, 23, 59, 59)) == 1); 2438 2439 assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( 2440 DateTime(1999, 2, 1, 12, 3, 42)) == -1); 2441 2442 assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( 2443 DateTime(1999, 1, 1, 2, 4, 7)) == 2); 2444 2445 assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( 2446 DateTime(1999, 3, 31, 0, 30, 58)) == -2); 2447 } 2448 2449 @safe unittest 2450 { 2451 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2452 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2453 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2454 assert(dt.diffMonths(dt) == 0); 2455 assert(cdt.diffMonths(dt) == 0); 2456 assert(idt.diffMonths(dt) == 0); 2457 2458 assert(dt.diffMonths(cdt) == 0); 2459 assert(cdt.diffMonths(cdt) == 0); 2460 assert(idt.diffMonths(cdt) == 0); 2461 2462 assert(dt.diffMonths(idt) == 0); 2463 assert(cdt.diffMonths(idt) == 0); 2464 assert(idt.diffMonths(idt) == 0); 2465 } 2466 2467 2468 /++ 2469 Whether this $(LREF DateTime) is in a leap year. 2470 +/ 2471 @property bool isLeapYear() const @safe pure nothrow @nogc 2472 { 2473 return _date.isLeapYear; 2474 } 2475 2476 @safe unittest 2477 { 2478 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2479 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2480 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2481 assert(!dt.isLeapYear); 2482 assert(!cdt.isLeapYear); 2483 assert(!idt.isLeapYear); 2484 } 2485 2486 2487 /++ 2488 Day of the week this $(LREF DateTime) is on. 2489 +/ 2490 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 2491 { 2492 return _date.dayOfWeek; 2493 } 2494 2495 @safe unittest 2496 { 2497 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2498 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2499 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2500 assert(dt.dayOfWeek == DayOfWeek.tue); 2501 assert(cdt.dayOfWeek == DayOfWeek.tue); 2502 assert(idt.dayOfWeek == DayOfWeek.tue); 2503 } 2504 2505 2506 /++ 2507 Day of the year this $(LREF DateTime) is on. 2508 +/ 2509 @property ushort dayOfYear() const @safe pure nothrow @nogc 2510 { 2511 return _date.dayOfYear; 2512 } 2513 2514 /// 2515 @safe unittest 2516 { 2517 assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); 2518 assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); 2519 assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); 2520 } 2521 2522 @safe unittest 2523 { 2524 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2525 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2526 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2527 assert(dt.dayOfYear == 187); 2528 assert(cdt.dayOfYear == 187); 2529 assert(idt.dayOfYear == 187); 2530 } 2531 2532 2533 /++ 2534 Day of the year. 2535 2536 Params: 2537 day = The day of the year to set which day of the year this 2538 $(LREF DateTime) is on. 2539 +/ 2540 @property void dayOfYear(int day) @safe pure 2541 { 2542 _date.dayOfYear = day; 2543 } 2544 2545 @safe unittest 2546 { 2547 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2548 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2549 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2550 dt.dayOfYear = 12; 2551 assert(dt.dayOfYear == 12); 2552 static assert(!__traits(compiles, cdt.dayOfYear = 12)); 2553 static assert(!__traits(compiles, idt.dayOfYear = 12)); 2554 } 2555 2556 2557 /++ 2558 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2559 +/ 2560 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 2561 { 2562 return _date.dayOfGregorianCal; 2563 } 2564 2565 /// 2566 @safe unittest 2567 { 2568 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); 2569 assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); 2570 assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); 2571 2572 assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); 2573 assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); 2574 assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); 2575 2576 assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); 2577 assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); 2578 } 2579 2580 @safe unittest 2581 { 2582 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2583 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2584 assert(cdt.dayOfGregorianCal == 729_941); 2585 assert(idt.dayOfGregorianCal == 729_941); 2586 } 2587 2588 2589 /++ 2590 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2591 Setting this property does not affect the time portion of 2592 $(LREF DateTime). 2593 2594 Params: 2595 days = The day of the Gregorian Calendar to set this $(LREF DateTime) 2596 to. 2597 +/ 2598 @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc 2599 { 2600 _date.dayOfGregorianCal = days; 2601 } 2602 2603 /// 2604 @safe unittest 2605 { 2606 auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); 2607 dt.dayOfGregorianCal = 1; 2608 assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); 2609 2610 dt.dayOfGregorianCal = 365; 2611 assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); 2612 2613 dt.dayOfGregorianCal = 366; 2614 assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); 2615 2616 dt.dayOfGregorianCal = 0; 2617 assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); 2618 2619 dt.dayOfGregorianCal = -365; 2620 assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); 2621 2622 dt.dayOfGregorianCal = -366; 2623 assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); 2624 2625 dt.dayOfGregorianCal = 730_120; 2626 assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); 2627 2628 dt.dayOfGregorianCal = 734_137; 2629 assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); 2630 } 2631 2632 @safe unittest 2633 { 2634 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2635 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2636 static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7)); 2637 static assert(!__traits(compiles, idt.dayOfGregorianCal = 7)); 2638 } 2639 2640 2641 /++ 2642 The ISO 8601 week of the year that this $(LREF DateTime) is in. 2643 2644 See_Also: 2645 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 2646 +/ 2647 @property ubyte isoWeek() const @safe pure nothrow 2648 { 2649 return _date.isoWeek; 2650 } 2651 2652 @safe unittest 2653 { 2654 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2655 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2656 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2657 assert(dt.isoWeek == 27); 2658 assert(cdt.isoWeek == 27); 2659 assert(idt.isoWeek == 27); 2660 } 2661 2662 2663 /++ 2664 The year of the ISO 8601 week calendar that this $(LREF DateTime) is in. 2665 2666 See_Also: 2667 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 2668 +/ 2669 @property short isoWeekYear() const @safe pure nothrow 2670 { 2671 return _date.isoWeekYear; 2672 } 2673 2674 2675 /++ 2676 $(LREF DateTime) for the last day in the month that this 2677 $(LREF DateTime) is in. The time portion of endOfMonth is always 2678 23:59:59. 2679 +/ 2680 @property DateTime endOfMonth() const @safe pure nothrow 2681 { 2682 try 2683 return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59)); 2684 catch (Exception e) 2685 assert(0, "DateTime constructor threw."); 2686 } 2687 2688 /// 2689 @safe unittest 2690 { 2691 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == 2692 DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); 2693 2694 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == 2695 DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); 2696 2697 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == 2698 DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); 2699 2700 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == 2701 DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); 2702 } 2703 2704 @safe unittest 2705 { 2706 // Test A.D. 2707 assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59)); 2708 assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59)); 2709 assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59)); 2710 assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59)); 2711 assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59)); 2712 assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59)); 2713 assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59)); 2714 assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2715 assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59)); 2716 assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59)); 2717 assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59)); 2718 assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59)); 2719 assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59)); 2720 2721 // Test B.C. 2722 assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59)); 2723 assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59)); 2724 assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59)); 2725 assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59)); 2726 assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59)); 2727 assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59)); 2728 assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59)); 2729 assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59)); 2730 assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59)); 2731 assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59)); 2732 assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59)); 2733 assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59)); 2734 assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59)); 2735 2736 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2737 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2738 assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2739 assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2740 } 2741 2742 2743 /++ 2744 The last day in the month that this $(LREF DateTime) is in. 2745 +/ 2746 @property ubyte daysInMonth() const @safe pure nothrow @nogc 2747 { 2748 return _date.daysInMonth; 2749 } 2750 2751 /// 2752 @safe unittest 2753 { 2754 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); 2755 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); 2756 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); 2757 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); 2758 } 2759 2760 @safe unittest 2761 { 2762 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2763 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2764 assert(cdt.daysInMonth == 31); 2765 assert(idt.daysInMonth == 31); 2766 } 2767 2768 2769 /++ 2770 Whether the current year is a date in A.D. 2771 +/ 2772 @property bool isAD() const @safe pure nothrow @nogc 2773 { 2774 return _date.isAD; 2775 } 2776 2777 /// 2778 @safe unittest 2779 { 2780 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); 2781 assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); 2782 assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); 2783 assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); 2784 } 2785 2786 @safe unittest 2787 { 2788 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2789 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2790 assert(cdt.isAD); 2791 assert(idt.isAD); 2792 } 2793 2794 2795 /++ 2796 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 2797 $(LREF DateTime) at the given time. For example, prior to noon, 2798 1996-03-31 would be the Julian day number 2_450_173, so this function 2799 returns 2_450_173, while from noon onward, the julian day number would 2800 be 2_450_174, so this function returns 2_450_174. 2801 +/ 2802 @property long julianDay() const @safe pure nothrow @nogc 2803 { 2804 if (_tod._hour < 12) 2805 return _date.julianDay - 1; 2806 else 2807 return _date.julianDay; 2808 } 2809 2810 @safe unittest 2811 { 2812 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1); 2813 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0); 2814 2815 assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424); 2816 assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425); 2817 2818 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425); 2819 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426); 2820 2821 assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160); 2822 assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161); 2823 2824 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000); 2825 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001); 2826 2827 assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973); 2828 assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974); 2829 2830 assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173); 2831 assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174); 2832 2833 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432); 2834 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433); 2835 2836 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2837 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2838 assert(cdt.julianDay == 2_451_366); 2839 assert(idt.julianDay == 2_451_366); 2840 } 2841 2842 2843 /++ 2844 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any 2845 time on this date (since, the modified Julian day changes at midnight). 2846 +/ 2847 @property long modJulianDay() const @safe pure nothrow @nogc 2848 { 2849 return _date.modJulianDay; 2850 } 2851 2852 @safe unittest 2853 { 2854 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0); 2855 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0); 2856 2857 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432); 2858 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432); 2859 2860 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2861 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2862 assert(cdt.modJulianDay == 51_365); 2863 assert(idt.modJulianDay == 51_365); 2864 } 2865 2866 2867 /++ 2868 Converts this $(LREF DateTime) to a string with the format `YYYYMMDDTHHMMSS`. 2869 If `writer` is set, the resulting string will be written directly to it. 2870 2871 Params: 2872 writer = A `char` accepting 2873 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 2874 Returns: 2875 A `string` when not using an output range; `void` otherwise. 2876 +/ 2877 string toISOString() const @safe pure nothrow 2878 { 2879 import std.array : appender; 2880 auto w = appender!string(); 2881 w.reserve(18); 2882 try 2883 toISOString(w); 2884 catch (Exception e) 2885 assert(0, "toISOString() threw."); 2886 return w.data; 2887 } 2888 2889 /// ditto 2890 void toISOString(W)(ref W writer) const 2891 if (isOutputRange!(W, char)) 2892 { 2893 import std.format.write : formattedWrite; 2894 _date.toISOString(writer); 2895 formattedWrite!("T%02d%02d%02d")( 2896 writer, 2897 _tod._hour, 2898 _tod._minute, 2899 _tod._second 2900 ); 2901 } 2902 2903 /// 2904 @safe unittest 2905 { 2906 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == 2907 "20100704T070612"); 2908 2909 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == 2910 "19981225T021500"); 2911 2912 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == 2913 "00000105T230959"); 2914 2915 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == 2916 "-00040105T000002"); 2917 } 2918 2919 @safe unittest 2920 { 2921 // Test A.D. 2922 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000"); 2923 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612"); 2924 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459"); 2925 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959"); 2926 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101"); 2927 2928 // Test B.C. 2929 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204"); 2930 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000"); 2931 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612"); 2932 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459"); 2933 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959"); 2934 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101"); 2935 2936 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2937 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2938 assert(cdt.toISOString() == "19990706T123033"); 2939 assert(idt.toISOString() == "19990706T123033"); 2940 } 2941 2942 2943 /++ 2944 Converts this $(LREF DateTime) to a string with the format 2945 `YYYY-MM-DDTHH:MM:SS`. If `writer` is set, the resulting 2946 string will be written directly to it. 2947 2948 Params: 2949 writer = A `char` accepting 2950 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 2951 Returns: 2952 A `string` when not using an output range; `void` otherwise. 2953 +/ 2954 string toISOExtString() const @safe pure nothrow 2955 { 2956 import std.array : appender; 2957 auto w = appender!string(); 2958 w.reserve(20); 2959 try 2960 toISOExtString(w); 2961 catch (Exception e) 2962 assert(0, "toISOExtString() threw."); 2963 return w.data; 2964 } 2965 2966 /// ditto 2967 void toISOExtString(W)(ref W writer) const 2968 if (isOutputRange!(W, char)) 2969 { 2970 import std.format.write : formattedWrite; 2971 _date.toISOExtString(writer); 2972 formattedWrite!("T%02d:%02d:%02d")( 2973 writer, 2974 _tod._hour, 2975 _tod._minute, 2976 _tod._second 2977 ); 2978 } 2979 2980 /// 2981 @safe unittest 2982 { 2983 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == 2984 "2010-07-04T07:06:12"); 2985 2986 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == 2987 "1998-12-25T02:15:00"); 2988 2989 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == 2990 "0000-01-05T23:09:59"); 2991 2992 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == 2993 "-0004-01-05T00:00:02"); 2994 } 2995 2996 @safe unittest 2997 { 2998 // Test A.D. 2999 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); 3000 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); 3001 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); 3002 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); 3003 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); 3004 3005 // Test B.C. 3006 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); 3007 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); 3008 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); 3009 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); 3010 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); 3011 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); 3012 3013 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3014 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3015 assert(cdt.toISOExtString() == "1999-07-06T12:30:33"); 3016 assert(idt.toISOExtString() == "1999-07-06T12:30:33"); 3017 } 3018 3019 /++ 3020 Converts this $(LREF DateTime) to a string with the format 3021 `YYYY-Mon-DD HH:MM:SS`. If `writer` is set, the resulting 3022 string will be written directly to it. 3023 3024 Params: 3025 writer = A `char` accepting 3026 $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 3027 Returns: 3028 A `string` when not using an output range; `void` otherwise. 3029 +/ 3030 string toSimpleString() const @safe pure nothrow 3031 { 3032 import std.array : appender; 3033 auto w = appender!string(); 3034 w.reserve(22); 3035 try 3036 toSimpleString(w); 3037 catch (Exception e) 3038 assert(0, "toSimpleString() threw."); 3039 return w.data; 3040 } 3041 3042 /// ditto 3043 void toSimpleString(W)(ref W writer) const 3044 if (isOutputRange!(W, char)) 3045 { 3046 import std.format.write : formattedWrite; 3047 _date.toSimpleString(writer); 3048 formattedWrite!(" %02d:%02d:%02d")( 3049 writer, 3050 _tod._hour, 3051 _tod._minute, 3052 _tod._second 3053 ); 3054 } 3055 3056 /// 3057 @safe unittest 3058 { 3059 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == 3060 "2010-Jul-04 07:06:12"); 3061 3062 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == 3063 "1998-Dec-25 02:15:00"); 3064 3065 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == 3066 "0000-Jan-05 23:09:59"); 3067 3068 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == 3069 "-0004-Jan-05 00:00:02"); 3070 } 3071 3072 @safe unittest 3073 { 3074 // Test A.D. 3075 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); 3076 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); 3077 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); 3078 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); 3079 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); 3080 3081 // Test B.C. 3082 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); 3083 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); 3084 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); 3085 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); 3086 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); 3087 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); 3088 3089 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3090 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3091 assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33"); 3092 assert(idt.toSimpleString() == "1999-Jul-06 12:30:33"); 3093 } 3094 3095 3096 /++ 3097 Converts this $(LREF DateTime) to a string. 3098 3099 This function exists to make it easy to convert a $(LREF DateTime) to a 3100 string for code that does not care what the exact format is - just that 3101 it presents the information in a clear manner. It also makes it easy to 3102 simply convert a $(LREF DateTime) to a string when using functions such 3103 as `to!string`, `format`, or `writeln` which use toString to convert 3104 user-defined types. So, it is unlikely that much code will call 3105 toString directly. 3106 3107 The format of the string is purposefully unspecified, and code that 3108 cares about the format of the string should use `toISOString`, 3109 `toISOExtString`, `toSimpleString`, or some other custom formatting 3110 function that explicitly generates the format that the code needs. The 3111 reason is that the code is then clear about what format it's using, 3112 making it less error-prone to maintain the code and interact with other 3113 software that consumes the generated strings. It's for this same reason 3114 that $(LREF DateTime) has no `fromString` function, whereas it does have 3115 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 3116 3117 The format returned by toString may or may not change in the future. 3118 +/ 3119 string toString() const @safe pure nothrow 3120 { 3121 return toSimpleString(); 3122 } 3123 3124 @safe unittest 3125 { 3126 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3127 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3128 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3129 assert(dt.toString()); 3130 assert(cdt.toString()); 3131 assert(idt.toString()); 3132 } 3133 3134 /// ditto 3135 void toString(W)(ref W writer) const 3136 if (isOutputRange!(W, char)) 3137 { 3138 toSimpleString(writer); 3139 } 3140 3141 /++ 3142 Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS. 3143 Whitespace is stripped from the given string. 3144 3145 Params: 3146 isoString = A string formatted in the ISO format for dates and times. 3147 3148 Throws: 3149 $(REF DateTimeException,std,datetime,date) if the given string is 3150 not in the ISO format or if the resulting $(LREF DateTime) would not 3151 be valid. 3152 +/ 3153 static DateTime fromISOString(S)(scope const S isoString) @safe pure 3154 if (isSomeString!S) 3155 { 3156 import std.algorithm.searching : countUntil; 3157 import std.exception : enforce; 3158 import std.format : format; 3159 import std.string : strip; 3160 import std.utf : byCodeUnit; 3161 3162 auto str = strip(isoString); 3163 3164 enforce!DateTimeException(str.length >= 15, format("Invalid format for DateTime.fromISOString %s", isoString)); 3165 auto t = str.byCodeUnit.countUntil('T'); 3166 3167 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOString: %s", isoString)); 3168 3169 immutable date = Date.fromISOString(str[0 .. t]); 3170 immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]); 3171 3172 return DateTime(date, tod); 3173 } 3174 3175 /// 3176 @safe unittest 3177 { 3178 assert(DateTime.fromISOString("20100704T070612") == 3179 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3180 3181 assert(DateTime.fromISOString("19981225T021500") == 3182 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3183 3184 assert(DateTime.fromISOString("00000105T230959") == 3185 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3186 3187 assert(DateTime.fromISOString("-00040105T000002") == 3188 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3189 3190 assert(DateTime.fromISOString(" 20100704T070612 ") == 3191 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3192 } 3193 3194 @safe unittest 3195 { 3196 assertThrown!DateTimeException(DateTime.fromISOString("")); 3197 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3198 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3199 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3200 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3201 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3202 3203 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3204 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3205 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3206 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3207 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3208 3209 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3210 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3211 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3212 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3213 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3214 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3215 3216 assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201")); 3217 assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01")); 3218 3219 assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3220 assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3221 assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3222 assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3223 assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3224 assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3225 assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3226 } 3227 3228 // https://issues.dlang.org/show_bug.cgi?id=17801 3229 @safe unittest 3230 { 3231 import std.conv : to; 3232 import std.meta : AliasSeq; 3233 static foreach (C; AliasSeq!(char, wchar, dchar)) 3234 { 3235 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3236 assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16)); 3237 } 3238 } 3239 3240 3241 /++ 3242 Creates a $(LREF DateTime) from a string with the format 3243 YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string. 3244 3245 Params: 3246 isoExtString = A string formatted in the ISO Extended format for dates 3247 and times. 3248 3249 Throws: 3250 $(REF DateTimeException,std,datetime,date) if the given string is 3251 not in the ISO Extended format or if the resulting $(LREF DateTime) 3252 would not be valid. 3253 +/ 3254 static DateTime fromISOExtString(S)(scope const S isoExtString) @safe pure 3255 if (isSomeString!(S)) 3256 { 3257 import std.algorithm.searching : countUntil; 3258 import std.exception : enforce; 3259 import std.format : format; 3260 import std.string : strip; 3261 import std.utf : byCodeUnit; 3262 3263 auto str = strip(isoExtString); 3264 3265 enforce!DateTimeException(str.length >= 15, 3266 format("Invalid format for DateTime.fromISOExtString: %s", isoExtString)); 3267 auto t = str.byCodeUnit.countUntil('T'); 3268 3269 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromISOExtString: %s", isoExtString)); 3270 3271 immutable date = Date.fromISOExtString(str[0 .. t]); 3272 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3273 3274 return DateTime(date, tod); 3275 } 3276 3277 /// 3278 @safe unittest 3279 { 3280 assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == 3281 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3282 3283 assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == 3284 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3285 3286 assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == 3287 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3288 3289 assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == 3290 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3291 3292 assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == 3293 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3294 } 3295 3296 @safe unittest 3297 { 3298 assertThrown!DateTimeException(DateTime.fromISOExtString("")); 3299 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000")); 3300 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000")); 3301 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000")); 3302 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.")); 3303 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0")); 3304 3305 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00")); 3306 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3307 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3308 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00")); 3309 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.")); 3310 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0")); 3311 3312 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00")); 3313 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00")); 3314 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.")); 3315 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0")); 3316 3317 assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201")); 3318 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01")); 3319 3320 assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3321 assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3322 assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3323 assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3324 assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3325 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3326 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3327 } 3328 3329 // https://issues.dlang.org/show_bug.cgi?id=17801 3330 @safe unittest 3331 { 3332 import std.conv : to; 3333 import std.meta : AliasSeq; 3334 static foreach (C; AliasSeq!(char, wchar, dchar)) 3335 { 3336 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3337 assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3338 } 3339 } 3340 3341 3342 /++ 3343 Creates a $(LREF DateTime) from a string with the format 3344 YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string. 3345 3346 Params: 3347 simpleString = A string formatted in the way that toSimpleString 3348 formats dates and times. 3349 3350 Throws: 3351 $(REF DateTimeException,std,datetime,date) if the given string is 3352 not in the correct format or if the resulting $(LREF DateTime) 3353 would not be valid. 3354 +/ 3355 static DateTime fromSimpleString(S)(scope const S simpleString) @safe pure 3356 if (isSomeString!(S)) 3357 { 3358 import std.algorithm.searching : countUntil; 3359 import std.exception : enforce; 3360 import std.format : format; 3361 import std.string : strip; 3362 import std.utf : byCodeUnit; 3363 3364 auto str = strip(simpleString); 3365 3366 enforce!DateTimeException(str.length >= 15, 3367 format("Invalid format for DateTime.fromSimpleString: %s", simpleString)); 3368 auto t = str.byCodeUnit.countUntil(' '); 3369 3370 enforce!DateTimeException(t != -1, format("Invalid format for DateTime.fromSimpleString: %s", simpleString)); 3371 3372 immutable date = Date.fromSimpleString(str[0 .. t]); 3373 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3374 3375 return DateTime(date, tod); 3376 } 3377 3378 /// 3379 @safe unittest 3380 { 3381 assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == 3382 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3383 assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == 3384 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3385 assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == 3386 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3387 assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == 3388 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3389 assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == 3390 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3391 } 3392 3393 @safe unittest 3394 { 3395 assertThrown!DateTimeException(DateTime.fromISOString("")); 3396 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3397 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3398 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3399 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3400 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3401 3402 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3403 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3404 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3405 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3406 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3407 3408 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3409 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3410 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3411 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3412 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3413 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3414 3415 assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201")); 3416 assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201")); 3417 3418 assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == 3419 DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1))); 3420 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == 3421 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3422 assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == 3423 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3424 assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == 3425 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3426 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == 3427 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3428 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == 3429 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3430 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == 3431 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3432 } 3433 3434 // https://issues.dlang.org/show_bug.cgi?id=17801 3435 @safe unittest 3436 { 3437 import std.conv : to; 3438 import std.meta : AliasSeq; 3439 static foreach (C; AliasSeq!(char, wchar, dchar)) 3440 { 3441 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3442 assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3443 } 3444 } 3445 3446 3447 /++ 3448 Returns the $(LREF DateTime) farthest in the past which is representable 3449 by $(LREF DateTime). 3450 +/ 3451 @property static DateTime min() @safe pure nothrow @nogc 3452 out(result) 3453 { 3454 assert(result._date == Date.min); 3455 assert(result._tod == TimeOfDay.min); 3456 } 3457 do 3458 { 3459 auto dt = DateTime.init; 3460 dt._date._year = short.min; 3461 dt._date._month = Month.jan; 3462 dt._date._day = 1; 3463 3464 return dt; 3465 } 3466 3467 @safe unittest 3468 { 3469 assert(DateTime.min.year < 0); 3470 assert(DateTime.min < DateTime.max); 3471 } 3472 3473 3474 /++ 3475 Returns the $(LREF DateTime) farthest in the future which is 3476 representable by $(LREF DateTime). 3477 +/ 3478 @property static DateTime max() @safe pure nothrow @nogc 3479 out(result) 3480 { 3481 assert(result._date == Date.max); 3482 assert(result._tod == TimeOfDay.max); 3483 } 3484 do 3485 { 3486 auto dt = DateTime.init; 3487 dt._date._year = short.max; 3488 dt._date._month = Month.dec; 3489 dt._date._day = 31; 3490 dt._tod._hour = TimeOfDay.maxHour; 3491 dt._tod._minute = TimeOfDay.maxMinute; 3492 dt._tod._second = TimeOfDay.maxSecond; 3493 3494 return dt; 3495 } 3496 3497 @safe unittest 3498 { 3499 assert(DateTime.max.year > 0); 3500 assert(DateTime.max > DateTime.min); 3501 } 3502 3503 3504 private: 3505 3506 /+ 3507 Add seconds to the time of day. Negative values will subtract. If the 3508 number of seconds overflows (or underflows), then the seconds will wrap, 3509 increasing (or decreasing) the number of minutes accordingly. The 3510 same goes for any larger units. 3511 3512 Params: 3513 seconds = The number of seconds to add to this $(LREF DateTime). 3514 +/ 3515 ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc 3516 { 3517 import core.time : convert; 3518 long hnsecs = convert!("seconds", "hnsecs")(seconds); 3519 hnsecs += convert!("hours", "hnsecs")(_tod._hour); 3520 hnsecs += convert!("minutes", "hnsecs")(_tod._minute); 3521 hnsecs += convert!("seconds", "hnsecs")(_tod._second); 3522 3523 auto days = splitUnitsFromHNSecs!"days"(hnsecs); 3524 3525 if (hnsecs < 0) 3526 { 3527 hnsecs += convert!("days", "hnsecs")(1); 3528 --days; 3529 } 3530 3531 _date._addDays(days); 3532 3533 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 3534 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 3535 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 3536 3537 _tod._hour = cast(ubyte) newHours; 3538 _tod._minute = cast(ubyte) newMinutes; 3539 _tod._second = cast(ubyte) newSeconds; 3540 3541 return this; 3542 } 3543 3544 @safe unittest 3545 { 3546 static void testDT(DateTime orig, int seconds, DateTime expected, size_t line = __LINE__) 3547 { 3548 orig._addSeconds(seconds); 3549 assert(orig == expected); 3550 } 3551 3552 // Test A.D. 3553 testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33)); 3554 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34)); 3555 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35)); 3556 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36)); 3557 testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37)); 3558 testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38)); 3559 testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43)); 3560 testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48)); 3561 testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59)); 3562 testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0)); 3563 testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3)); 3564 testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32)); 3565 testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33)); 3566 testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34)); 3567 3568 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59)); 3569 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0)); 3570 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1)); 3571 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0)); 3572 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32)); 3573 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33)); 3574 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34)); 3575 testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33)); 3576 testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3)); 3577 3578 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32)); 3579 testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31)); 3580 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30)); 3581 testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29)); 3582 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28)); 3583 testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23)); 3584 testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18)); 3585 testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0)); 3586 testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59)); 3587 testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58)); 3588 testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34)); 3589 testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33)); 3590 testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32)); 3591 3592 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0)); 3593 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59)); 3594 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33)); 3595 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32)); 3596 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59)); 3597 testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57)); 3598 3599 testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1)); 3600 testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0)); 3601 testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59)); 3602 3603 testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1)); 3604 testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0)); 3605 testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59)); 3606 3607 testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1)); 3608 testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0)); 3609 testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59)); 3610 3611 testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0)); 3612 testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59)); 3613 testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58)); 3614 3615 testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0)); 3616 testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59)); 3617 testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58)); 3618 3619 testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1)); 3620 testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0)); 3621 testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59)); 3622 3623 // Test B.C. 3624 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33)); 3625 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34)); 3626 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35)); 3627 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36)); 3628 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37)); 3629 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38)); 3630 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43)); 3631 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48)); 3632 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59)); 3633 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0)); 3634 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3)); 3635 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32)); 3636 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33)); 3637 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34)); 3638 3639 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59)); 3640 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0)); 3641 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1)); 3642 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0)); 3643 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32)); 3644 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33)); 3645 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34)); 3646 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33)); 3647 testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3)); 3648 3649 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32)); 3650 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31)); 3651 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30)); 3652 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29)); 3653 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28)); 3654 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23)); 3655 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18)); 3656 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0)); 3657 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59)); 3658 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58)); 3659 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34)); 3660 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33)); 3661 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32)); 3662 3663 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0)); 3664 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59)); 3665 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33)); 3666 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32)); 3667 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59)); 3668 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33)); 3669 testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57)); 3670 3671 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1)); 3672 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0)); 3673 testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59)); 3674 3675 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1)); 3676 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0)); 3677 testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59)); 3678 3679 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1)); 3680 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0)); 3681 testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59)); 3682 3683 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0)); 3684 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59)); 3685 testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58)); 3686 3687 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0)); 3688 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59)); 3689 testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58)); 3690 3691 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1)); 3692 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0)); 3693 testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59)); 3694 3695 // Test Both 3696 testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59)); 3697 testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0)); 3698 3699 testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59)); 3700 testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0)); 3701 3702 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33)); 3703 testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33)); 3704 3705 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50)); 3706 testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33)); 3707 3708 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3709 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3710 static assert(!__traits(compiles, cdt._addSeconds(4))); 3711 static assert(!__traits(compiles, idt._addSeconds(4))); 3712 } 3713 3714 3715 Date _date; 3716 TimeOfDay _tod; 3717 } 3718 3719 /// 3720 @safe pure unittest 3721 { 3722 import core.time : days, seconds; 3723 3724 auto dt = DateTime(2000, 6, 1, 10, 30, 0); 3725 3726 assert(dt.date == Date(2000, 6, 1)); 3727 assert(dt.timeOfDay == TimeOfDay(10, 30, 0)); 3728 assert(dt.dayOfYear == 153); 3729 assert(dt.dayOfWeek == DayOfWeek.thu); 3730 3731 dt += 10.days + 100.seconds; 3732 assert(dt == DateTime(2000, 6, 11, 10, 31, 40)); 3733 3734 assert(dt.toISOExtString() == "2000-06-11T10:31:40"); 3735 assert(dt.toISOString() == "20000611T103140"); 3736 assert(dt.toSimpleString() == "2000-Jun-11 10:31:40"); 3737 3738 assert(DateTime.fromISOExtString("2018-01-01T12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); 3739 assert(DateTime.fromISOString("20180101T120000") == DateTime(2018, 1, 1, 12, 0, 0)); 3740 assert(DateTime.fromSimpleString("2018-Jan-01 12:00:00") == DateTime(2018, 1, 1, 12, 0, 0)); 3741 } 3742 3743 /++ 3744 Represents a date in the 3745 $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic 3746 Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years 3747 are A.D. Non-positive years are B.C. 3748 3749 Year, month, and day are kept separately internally so that `Date` is 3750 optimized for calendar-based operations. 3751 3752 `Date` uses the Proleptic Gregorian Calendar, so it assumes the Gregorian 3753 leap year calculations for its entire length. As per 3754 $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as 3755 year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C. 3756 as a positive integer with 1 B.C. being the year prior to 1 A.D. 3757 3758 Year 0 is a leap year. 3759 +/ 3760 struct Date 3761 { 3762 public: 3763 3764 /++ 3765 Throws: 3766 $(REF DateTimeException,std,datetime,date) if the resulting 3767 $(LREF Date) would not be valid. 3768 3769 Params: 3770 year = Year of the Gregorian Calendar. Positive values are A.D. 3771 Non-positive values are B.C. with year 0 being the year 3772 prior to 1 A.D. 3773 month = Month of the year (January is 1). 3774 day = Day of the month. 3775 +/ 3776 this(int year, int month, int day) @safe pure 3777 { 3778 enforceValid!"months"(cast(Month) month); 3779 enforceValid!"days"(year, cast(Month) month, day); 3780 3781 _year = year.castToYear; 3782 _month = cast(Month) month; 3783 _day = cast(ubyte) day; 3784 } 3785 3786 @safe unittest 3787 { 3788 import std.exception : assertNotThrown; 3789 assert(Date(1, 1, 1) == Date.init); 3790 3791 static void testDate(Date date, int year, int month, int day) 3792 { 3793 assert(date._year == year); 3794 assert(date._month == month); 3795 assert(date._day == day); 3796 } 3797 3798 testDate(Date(1999, 1 , 1), 1999, Month.jan, 1); 3799 testDate(Date(1999, 7 , 1), 1999, Month.jul, 1); 3800 testDate(Date(1999, 7 , 6), 1999, Month.jul, 6); 3801 3802 // Test A.D. 3803 assertThrown!DateTimeException(Date(1, 0, 1)); 3804 assertThrown!DateTimeException(Date(1, 1, 0)); 3805 assertThrown!DateTimeException(Date(1999, 13, 1)); 3806 assertThrown!DateTimeException(Date(1999, 1, 32)); 3807 assertThrown!DateTimeException(Date(1999, 2, 29)); 3808 assertThrown!DateTimeException(Date(2000, 2, 30)); 3809 assertThrown!DateTimeException(Date(1999, 3, 32)); 3810 assertThrown!DateTimeException(Date(1999, 4, 31)); 3811 assertThrown!DateTimeException(Date(1999, 5, 32)); 3812 assertThrown!DateTimeException(Date(1999, 6, 31)); 3813 assertThrown!DateTimeException(Date(1999, 7, 32)); 3814 assertThrown!DateTimeException(Date(1999, 8, 32)); 3815 assertThrown!DateTimeException(Date(1999, 9, 31)); 3816 assertThrown!DateTimeException(Date(1999, 10, 32)); 3817 assertThrown!DateTimeException(Date(1999, 11, 31)); 3818 assertThrown!DateTimeException(Date(1999, 12, 32)); 3819 assertThrown!DateTimeException(Date(short.max+1, 1, 1)); 3820 3821 assertNotThrown!DateTimeException(Date(1999, 1, 31)); 3822 assertNotThrown!DateTimeException(Date(1999, 2, 28)); 3823 assertNotThrown!DateTimeException(Date(2000, 2, 29)); 3824 assertNotThrown!DateTimeException(Date(1999, 3, 31)); 3825 assertNotThrown!DateTimeException(Date(1999, 4, 30)); 3826 assertNotThrown!DateTimeException(Date(1999, 5, 31)); 3827 assertNotThrown!DateTimeException(Date(1999, 6, 30)); 3828 assertNotThrown!DateTimeException(Date(1999, 7, 31)); 3829 assertNotThrown!DateTimeException(Date(1999, 8, 31)); 3830 assertNotThrown!DateTimeException(Date(1999, 9, 30)); 3831 assertNotThrown!DateTimeException(Date(1999, 10, 31)); 3832 assertNotThrown!DateTimeException(Date(1999, 11, 30)); 3833 assertNotThrown!DateTimeException(Date(1999, 12, 31)); 3834 3835 // Test B.C. 3836 assertNotThrown!DateTimeException(Date(0, 1, 1)); 3837 assertNotThrown!DateTimeException(Date(-1, 1, 1)); 3838 assertNotThrown!DateTimeException(Date(-1, 12, 31)); 3839 assertNotThrown!DateTimeException(Date(-1, 2, 28)); 3840 assertNotThrown!DateTimeException(Date(-4, 2, 29)); 3841 3842 assertThrown!DateTimeException(Date(-1, 2, 29)); 3843 assertThrown!DateTimeException(Date(-2, 2, 29)); 3844 assertThrown!DateTimeException(Date(-3, 2, 29)); 3845 assertThrown!DateTimeException(Date(short.min-1, 1, 1)); 3846 } 3847 3848 3849 /++ 3850 Params: 3851 day = The Xth day of the Gregorian Calendar that the constructed 3852 $(LREF Date) will be for. 3853 +/ 3854 this(int day) @safe pure nothrow @nogc 3855 { 3856 if (day > 0) 3857 { 3858 int years = (day / daysIn400Years) * 400 + 1; 3859 day %= daysIn400Years; 3860 3861 { 3862 immutable tempYears = day / daysIn100Years; 3863 3864 if (tempYears == 4) 3865 { 3866 years += 300; 3867 day -= daysIn100Years * 3; 3868 } 3869 else 3870 { 3871 years += tempYears * 100; 3872 day %= daysIn100Years; 3873 } 3874 } 3875 3876 years += (day / daysIn4Years) * 4; 3877 day %= daysIn4Years; 3878 3879 { 3880 immutable tempYears = day / daysInYear; 3881 3882 if (tempYears == 4) 3883 { 3884 years += 3; 3885 day -= daysInYear * 3; 3886 } 3887 else 3888 { 3889 years += tempYears; 3890 day %= daysInYear; 3891 } 3892 } 3893 3894 if (day == 0) 3895 { 3896 _year = cast(short)(years - 1); 3897 _month = Month.dec; 3898 _day = 31; 3899 } 3900 else 3901 { 3902 _year = cast(short) years; 3903 3904 setDayOfYear(day); 3905 } 3906 } 3907 else if (day <= 0 && -day < daysInLeapYear) 3908 { 3909 _year = 0; 3910 3911 setDayOfYear(daysInLeapYear + day); 3912 } 3913 else 3914 { 3915 day += daysInLeapYear - 1; 3916 int years = (day / daysIn400Years) * 400 - 1; 3917 day %= daysIn400Years; 3918 3919 { 3920 immutable tempYears = day / daysIn100Years; 3921 3922 if (tempYears == -4) 3923 { 3924 years -= 300; 3925 day += daysIn100Years * 3; 3926 } 3927 else 3928 { 3929 years += tempYears * 100; 3930 day %= daysIn100Years; 3931 } 3932 } 3933 3934 years += (day / daysIn4Years) * 4; 3935 day %= daysIn4Years; 3936 3937 { 3938 immutable tempYears = day / daysInYear; 3939 3940 if (tempYears == -4) 3941 { 3942 years -= 3; 3943 day += daysInYear * 3; 3944 } 3945 else 3946 { 3947 years += tempYears; 3948 day %= daysInYear; 3949 } 3950 } 3951 3952 if (day == 0) 3953 { 3954 _year = cast(short)(years + 1); 3955 _month = Month.jan; 3956 _day = 1; 3957 } 3958 else 3959 { 3960 _year = cast(short) years; 3961 immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1; 3962 3963 setDayOfYear(newDoY); 3964 } 3965 } 3966 } 3967 3968 @safe unittest 3969 { 3970 import std.range : chain; 3971 3972 // Test A.D. 3973 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 3974 assert(Date(gd.day) == gd.date); 3975 } 3976 3977 3978 /++ 3979 Compares this $(LREF Date) with the given $(LREF Date). 3980 3981 Returns: 3982 $(BOOKTABLE, 3983 $(TR $(TD this < rhs) $(TD < 0)) 3984 $(TR $(TD this == rhs) $(TD 0)) 3985 $(TR $(TD this > rhs) $(TD > 0)) 3986 ) 3987 +/ 3988 int opCmp(Date rhs) const @safe pure nothrow @nogc 3989 { 3990 if (_year < rhs._year) 3991 return -1; 3992 if (_year > rhs._year) 3993 return 1; 3994 3995 if (_month < rhs._month) 3996 return -1; 3997 if (_month > rhs._month) 3998 return 1; 3999 4000 if (_day < rhs._day) 4001 return -1; 4002 if (_day > rhs._day) 4003 return 1; 4004 4005 return 0; 4006 } 4007 4008 @safe unittest 4009 { 4010 // Test A.D. 4011 assert(Date(1, 1, 1).opCmp(Date.init) == 0); 4012 4013 assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0); 4014 assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0); 4015 assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0); 4016 4017 assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0); 4018 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0); 4019 4020 assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0); 4021 4022 assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0); 4023 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0); 4024 assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0); 4025 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0); 4026 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0); 4027 assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0); 4028 4029 assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0); 4030 assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 4031 assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0); 4032 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0); 4033 assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0); 4034 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 4035 4036 // Test B.C. 4037 assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0); 4038 assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0); 4039 assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0); 4040 assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0); 4041 4042 assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0); 4043 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0); 4044 4045 assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0); 4046 4047 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0); 4048 assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0); 4049 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0); 4050 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0); 4051 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 4052 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0); 4053 4054 assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0); 4055 assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0); 4056 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 4057 assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0); 4058 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0); 4059 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0); 4060 4061 // Test Both 4062 assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0); 4063 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0); 4064 4065 assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0); 4066 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0); 4067 4068 assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0); 4069 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0); 4070 4071 assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0); 4072 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0); 4073 4074 assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0); 4075 assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0); 4076 4077 auto date = Date(1999, 7, 6); 4078 const cdate = Date(1999, 7, 6); 4079 immutable idate = Date(1999, 7, 6); 4080 assert(date.opCmp(date) == 0); 4081 assert(date.opCmp(cdate) == 0); 4082 assert(date.opCmp(idate) == 0); 4083 assert(cdate.opCmp(date) == 0); 4084 assert(cdate.opCmp(cdate) == 0); 4085 assert(cdate.opCmp(idate) == 0); 4086 assert(idate.opCmp(date) == 0); 4087 assert(idate.opCmp(cdate) == 0); 4088 assert(idate.opCmp(idate) == 0); 4089 } 4090 4091 4092 /++ 4093 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 4094 are B.C. 4095 +/ 4096 @property short year() const @safe pure nothrow @nogc 4097 { 4098 return _year; 4099 } 4100 4101 /// 4102 @safe unittest 4103 { 4104 assert(Date(1999, 7, 6).year == 1999); 4105 assert(Date(2010, 10, 4).year == 2010); 4106 assert(Date(-7, 4, 5).year == -7); 4107 } 4108 4109 @safe unittest 4110 { 4111 assert(Date.init.year == 1); 4112 assert(Date(1999, 7, 6).year == 1999); 4113 assert(Date(-1999, 7, 6).year == -1999); 4114 4115 const cdate = Date(1999, 7, 6); 4116 immutable idate = Date(1999, 7, 6); 4117 assert(cdate.year == 1999); 4118 assert(idate.year == 1999); 4119 } 4120 4121 /++ 4122 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 4123 are B.C. 4124 4125 Params: 4126 year = The year to set this Date's year to. 4127 4128 Throws: 4129 $(REF DateTimeException,std,datetime,date) if the new year is not 4130 a leap year and the resulting date would be on February 29th. 4131 +/ 4132 @property void year(int year) @safe pure 4133 { 4134 enforceValid!"days"(year, _month, _day); 4135 _year = year.castToYear; 4136 } 4137 4138 /// 4139 @safe unittest 4140 { 4141 assert(Date(1999, 7, 6).year == 1999); 4142 assert(Date(2010, 10, 4).year == 2010); 4143 assert(Date(-7, 4, 5).year == -7); 4144 } 4145 4146 @safe unittest 4147 { 4148 static void testDateInvalid(Date date, int year) 4149 { 4150 date.year = year; 4151 } 4152 4153 static void testDate(Date date, int year, Date expected) 4154 { 4155 date.year = year; 4156 assert(date == expected); 4157 } 4158 4159 assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1)); 4160 4161 testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1)); 4162 testDate(Date(1, 1, 1), 0, Date(0, 1, 1)); 4163 testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1)); 4164 4165 const cdate = Date(1999, 7, 6); 4166 immutable idate = Date(1999, 7, 6); 4167 static assert(!__traits(compiles, cdate.year = 1999)); 4168 static assert(!__traits(compiles, idate.year = 1999)); 4169 } 4170 4171 4172 /++ 4173 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4174 4175 Throws: 4176 $(REF DateTimeException,std,datetime,date) if `isAD` is true. 4177 +/ 4178 @property ushort yearBC() const @safe pure 4179 { 4180 import std.format : format; 4181 4182 if (isAD) 4183 throw new DateTimeException(format("Year %s is A.D.", _year)); 4184 return cast(ushort)((_year * -1) + 1); 4185 } 4186 4187 /// 4188 @safe unittest 4189 { 4190 assert(Date(0, 1, 1).yearBC == 1); 4191 assert(Date(-1, 1, 1).yearBC == 2); 4192 assert(Date(-100, 1, 1).yearBC == 101); 4193 } 4194 4195 @safe unittest 4196 { 4197 assertThrown!DateTimeException((Date date){date.yearBC;}(Date(1, 1, 1))); 4198 4199 auto date = Date(0, 7, 6); 4200 const cdate = Date(0, 7, 6); 4201 immutable idate = Date(0, 7, 6); 4202 assert(date.yearBC == 1); 4203 assert(cdate.yearBC == 1); 4204 assert(idate.yearBC == 1); 4205 } 4206 4207 4208 /++ 4209 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4210 4211 Params: 4212 year = The year B.C. to set this $(LREF Date)'s year to. 4213 4214 Throws: 4215 $(REF DateTimeException,std,datetime,date) if a non-positive value 4216 is given. 4217 +/ 4218 @property void yearBC(int year) @safe pure 4219 { 4220 if (year <= 0) 4221 throw new DateTimeException("The given year is not a year B.C."); 4222 _year = castToYear((year - 1) * -1); 4223 } 4224 4225 /// 4226 @safe unittest 4227 { 4228 auto date = Date(2010, 1, 1); 4229 date.yearBC = 1; 4230 assert(date == Date(0, 1, 1)); 4231 4232 date.yearBC = 10; 4233 assert(date == Date(-9, 1, 1)); 4234 } 4235 4236 @safe unittest 4237 { 4238 assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1))); 4239 4240 auto date = Date(0, 7, 6); 4241 const cdate = Date(0, 7, 6); 4242 immutable idate = Date(0, 7, 6); 4243 date.yearBC = 7; 4244 assert(date.yearBC == 7); 4245 static assert(!__traits(compiles, cdate.yearBC = 7)); 4246 static assert(!__traits(compiles, idate.yearBC = 7)); 4247 } 4248 4249 4250 /++ 4251 Month of a Gregorian Year. 4252 +/ 4253 @property Month month() const @safe pure nothrow @nogc 4254 { 4255 return _month; 4256 } 4257 4258 /// 4259 @safe unittest 4260 { 4261 assert(Date(1999, 7, 6).month == 7); 4262 assert(Date(2010, 10, 4).month == 10); 4263 assert(Date(-7, 4, 5).month == 4); 4264 } 4265 4266 @safe unittest 4267 { 4268 assert(Date.init.month == 1); 4269 assert(Date(1999, 7, 6).month == 7); 4270 assert(Date(-1999, 7, 6).month == 7); 4271 4272 const cdate = Date(1999, 7, 6); 4273 immutable idate = Date(1999, 7, 6); 4274 assert(cdate.month == 7); 4275 assert(idate.month == 7); 4276 } 4277 4278 /++ 4279 Month of a Gregorian Year. 4280 4281 Params: 4282 month = The month to set this $(LREF Date)'s month to. 4283 4284 Throws: 4285 $(REF DateTimeException,std,datetime,date) if the given month is 4286 not a valid month or if the current day would not be valid in the 4287 given month. 4288 +/ 4289 @property void month(Month month) @safe pure 4290 { 4291 enforceValid!"months"(month); 4292 enforceValid!"days"(_year, month, _day); 4293 _month = cast(Month) month; 4294 } 4295 4296 @safe unittest 4297 { 4298 static void testDate(Date date, Month month, Date expected = Date.init) 4299 { 4300 date.month = month; 4301 assert(expected != Date.init); 4302 assert(date == expected); 4303 } 4304 4305 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0)); 4306 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13)); 4307 assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2)); 4308 assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2)); 4309 4310 testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1)); 4311 testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1)); 4312 4313 const cdate = Date(1999, 7, 6); 4314 immutable idate = Date(1999, 7, 6); 4315 static assert(!__traits(compiles, cdate.month = 7)); 4316 static assert(!__traits(compiles, idate.month = 7)); 4317 } 4318 4319 4320 /++ 4321 Day of a Gregorian Month. 4322 +/ 4323 @property ubyte day() const @safe pure nothrow @nogc 4324 { 4325 return _day; 4326 } 4327 4328 /// 4329 @safe unittest 4330 { 4331 assert(Date(1999, 7, 6).day == 6); 4332 assert(Date(2010, 10, 4).day == 4); 4333 assert(Date(-7, 4, 5).day == 5); 4334 } 4335 4336 @safe unittest 4337 { 4338 import std.format : format; 4339 import std.range : chain; 4340 4341 static void test(Date date, int expected) 4342 { 4343 assert(date.day == expected, format("Value given: %s", date)); 4344 } 4345 4346 foreach (year; chain(testYearsBC, testYearsAD)) 4347 { 4348 foreach (md; testMonthDays) 4349 test(Date(year, md.month, md.day), md.day); 4350 } 4351 4352 const cdate = Date(1999, 7, 6); 4353 immutable idate = Date(1999, 7, 6); 4354 assert(cdate.day == 6); 4355 assert(idate.day == 6); 4356 } 4357 4358 /++ 4359 Day of a Gregorian Month. 4360 4361 Params: 4362 day = The day of the month to set this $(LREF Date)'s day to. 4363 4364 Throws: 4365 $(REF DateTimeException,std,datetime,date) if the given day is not 4366 a valid day of the current month. 4367 +/ 4368 @property void day(int day) @safe pure 4369 { 4370 enforceValid!"days"(_year, _month, day); 4371 _day = cast(ubyte) day; 4372 } 4373 4374 @safe unittest 4375 { 4376 import std.exception : assertNotThrown; 4377 4378 static void testDate(Date date, int day) 4379 { 4380 date.day = day; 4381 } 4382 4383 // Test A.D. 4384 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0)); 4385 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32)); 4386 assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29)); 4387 assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30)); 4388 assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32)); 4389 assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31)); 4390 assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32)); 4391 assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31)); 4392 assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32)); 4393 assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32)); 4394 assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31)); 4395 assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32)); 4396 assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31)); 4397 assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32)); 4398 4399 assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31)); 4400 assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28)); 4401 assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29)); 4402 assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31)); 4403 assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30)); 4404 assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31)); 4405 assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30)); 4406 assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31)); 4407 assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31)); 4408 assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30)); 4409 assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31)); 4410 assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30)); 4411 assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31)); 4412 4413 { 4414 auto date = Date(1, 1, 1); 4415 date.day = 6; 4416 assert(date == Date(1, 1, 6)); 4417 } 4418 4419 // Test B.C. 4420 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0)); 4421 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32)); 4422 assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29)); 4423 assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30)); 4424 assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32)); 4425 assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31)); 4426 assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32)); 4427 assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31)); 4428 assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32)); 4429 assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32)); 4430 assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31)); 4431 assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32)); 4432 assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31)); 4433 assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32)); 4434 4435 assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31)); 4436 assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28)); 4437 assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29)); 4438 assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31)); 4439 assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30)); 4440 assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31)); 4441 assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30)); 4442 assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31)); 4443 assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31)); 4444 assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30)); 4445 assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31)); 4446 assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30)); 4447 assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31)); 4448 4449 { 4450 auto date = Date(-1, 1, 1); 4451 date.day = 6; 4452 assert(date == Date(-1, 1, 6)); 4453 } 4454 4455 const cdate = Date(1999, 7, 6); 4456 immutable idate = Date(1999, 7, 6); 4457 static assert(!__traits(compiles, cdate.day = 6)); 4458 static assert(!__traits(compiles, idate.day = 6)); 4459 } 4460 4461 4462 /++ 4463 Adds the given number of years or months to this $(LREF Date), mutating 4464 it. A negative number will subtract. 4465 4466 Note that if day overflow is allowed, and the date with the adjusted 4467 year/month overflows the number of days in the new month, then the month 4468 will be incremented by one, and the day set to the number of days 4469 overflowed. (e.g. if the day were 31 and the new month were June, then 4470 the month would be incremented to July, and the new day would be 1). If 4471 day overflow is not allowed, then the day will be set to the last valid 4472 day in the month (e.g. June 31st would become June 30th). 4473 4474 Params: 4475 units = The type of units to add ("years" or "months"). 4476 value = The number of months or years to add to this 4477 $(LREF Date). 4478 allowOverflow = Whether the day should be allowed to overflow, 4479 causing the month to increment. 4480 4481 Returns: 4482 A reference to the `Date` (`this`). 4483 +/ 4484 @safe pure nothrow @nogc 4485 ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4486 if (units == "years") 4487 { 4488 _year += value; 4489 4490 if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year)) 4491 { 4492 if (allowOverflow == AllowDayOverflow.yes) 4493 { 4494 _month = Month.mar; 4495 _day = 1; 4496 } 4497 else 4498 _day = 28; 4499 } 4500 4501 return this; 4502 } 4503 4504 /// 4505 @safe unittest 4506 { 4507 auto d1 = Date(2010, 1, 1); 4508 d1.add!"months"(11); 4509 assert(d1 == Date(2010, 12, 1)); 4510 4511 auto d2 = Date(2010, 1, 1); 4512 d2.add!"months"(-11); 4513 assert(d2 == Date(2009, 2, 1)); 4514 4515 auto d3 = Date(2000, 2, 29); 4516 d3.add!"years"(1); 4517 assert(d3 == Date(2001, 3, 1)); 4518 4519 auto d4 = Date(2000, 2, 29); 4520 d4.add!"years"(1, AllowDayOverflow.no); 4521 assert(d4 == Date(2001, 2, 28)); 4522 } 4523 4524 // Test add!"years"() with AllowDayOverflow.yes 4525 @safe unittest 4526 { 4527 // Test A.D. 4528 { 4529 auto date = Date(1999, 7, 6); 4530 date.add!"years"(7); 4531 assert(date == Date(2006, 7, 6)); 4532 date.add!"years"(-9); 4533 assert(date == Date(1997, 7, 6)); 4534 } 4535 4536 { 4537 auto date = Date(1999, 2, 28); 4538 date.add!"years"(1); 4539 assert(date == Date(2000, 2, 28)); 4540 } 4541 4542 { 4543 auto date = Date(2000, 2, 29); 4544 date.add!"years"(-1); 4545 assert(date == Date(1999, 3, 1)); 4546 } 4547 4548 // Test B.C. 4549 { 4550 auto date = Date(-1999, 7, 6); 4551 date.add!"years"(-7); 4552 assert(date == Date(-2006, 7, 6)); 4553 date.add!"years"(9); 4554 assert(date == Date(-1997, 7, 6)); 4555 } 4556 4557 { 4558 auto date = Date(-1999, 2, 28); 4559 date.add!"years"(-1); 4560 assert(date == Date(-2000, 2, 28)); 4561 } 4562 4563 { 4564 auto date = Date(-2000, 2, 29); 4565 date.add!"years"(1); 4566 assert(date == Date(-1999, 3, 1)); 4567 } 4568 4569 // Test Both 4570 { 4571 auto date = Date(4, 7, 6); 4572 date.add!"years"(-5); 4573 assert(date == Date(-1, 7, 6)); 4574 date.add!"years"(5); 4575 assert(date == Date(4, 7, 6)); 4576 } 4577 4578 { 4579 auto date = Date(-4, 7, 6); 4580 date.add!"years"(5); 4581 assert(date == Date(1, 7, 6)); 4582 date.add!"years"(-5); 4583 assert(date == Date(-4, 7, 6)); 4584 } 4585 4586 { 4587 auto date = Date(4, 7, 6); 4588 date.add!"years"(-8); 4589 assert(date == Date(-4, 7, 6)); 4590 date.add!"years"(8); 4591 assert(date == Date(4, 7, 6)); 4592 } 4593 4594 { 4595 auto date = Date(-4, 7, 6); 4596 date.add!"years"(8); 4597 assert(date == Date(4, 7, 6)); 4598 date.add!"years"(-8); 4599 assert(date == Date(-4, 7, 6)); 4600 } 4601 4602 { 4603 auto date = Date(-4, 2, 29); 4604 date.add!"years"(5); 4605 assert(date == Date(1, 3, 1)); 4606 } 4607 4608 { 4609 auto date = Date(4, 2, 29); 4610 date.add!"years"(-5); 4611 assert(date == Date(-1, 3, 1)); 4612 } 4613 4614 { 4615 auto date = Date(4, 2, 29); 4616 date.add!"years"(-5).add!"years"(7); 4617 assert(date == Date(6, 3, 1)); 4618 } 4619 4620 const cdate = Date(1999, 7, 6); 4621 immutable idate = Date(1999, 7, 6); 4622 static assert(!__traits(compiles, cdate.add!"years"(7))); 4623 static assert(!__traits(compiles, idate.add!"years"(7))); 4624 } 4625 4626 // Test add!"years"() with AllowDayOverflow.no 4627 @safe unittest 4628 { 4629 // Test A.D. 4630 { 4631 auto date = Date(1999, 7, 6); 4632 date.add!"years"(7, AllowDayOverflow.no); 4633 assert(date == Date(2006, 7, 6)); 4634 date.add!"years"(-9, AllowDayOverflow.no); 4635 assert(date == Date(1997, 7, 6)); 4636 } 4637 4638 { 4639 auto date = Date(1999, 2, 28); 4640 date.add!"years"(1, AllowDayOverflow.no); 4641 assert(date == Date(2000, 2, 28)); 4642 } 4643 4644 { 4645 auto date = Date(2000, 2, 29); 4646 date.add!"years"(-1, AllowDayOverflow.no); 4647 assert(date == Date(1999, 2, 28)); 4648 } 4649 4650 // Test B.C. 4651 { 4652 auto date = Date(-1999, 7, 6); 4653 date.add!"years"(-7, AllowDayOverflow.no); 4654 assert(date == Date(-2006, 7, 6)); 4655 date.add!"years"(9, AllowDayOverflow.no); 4656 assert(date == Date(-1997, 7, 6)); 4657 } 4658 4659 { 4660 auto date = Date(-1999, 2, 28); 4661 date.add!"years"(-1, AllowDayOverflow.no); 4662 assert(date == Date(-2000, 2, 28)); 4663 } 4664 4665 { 4666 auto date = Date(-2000, 2, 29); 4667 date.add!"years"(1, AllowDayOverflow.no); 4668 assert(date == Date(-1999, 2, 28)); 4669 } 4670 4671 // Test Both 4672 { 4673 auto date = Date(4, 7, 6); 4674 date.add!"years"(-5, AllowDayOverflow.no); 4675 assert(date == Date(-1, 7, 6)); 4676 date.add!"years"(5, AllowDayOverflow.no); 4677 assert(date == Date(4, 7, 6)); 4678 } 4679 4680 { 4681 auto date = Date(-4, 7, 6); 4682 date.add!"years"(5, AllowDayOverflow.no); 4683 assert(date == Date(1, 7, 6)); 4684 date.add!"years"(-5, AllowDayOverflow.no); 4685 assert(date == Date(-4, 7, 6)); 4686 } 4687 4688 { 4689 auto date = Date(4, 7, 6); 4690 date.add!"years"(-8, AllowDayOverflow.no); 4691 assert(date == Date(-4, 7, 6)); 4692 date.add!"years"(8, AllowDayOverflow.no); 4693 assert(date == Date(4, 7, 6)); 4694 } 4695 4696 { 4697 auto date = Date(-4, 7, 6); 4698 date.add!"years"(8, AllowDayOverflow.no); 4699 assert(date == Date(4, 7, 6)); 4700 date.add!"years"(-8, AllowDayOverflow.no); 4701 assert(date == Date(-4, 7, 6)); 4702 } 4703 4704 { 4705 auto date = Date(-4, 2, 29); 4706 date.add!"years"(5, AllowDayOverflow.no); 4707 assert(date == Date(1, 2, 28)); 4708 } 4709 4710 { 4711 auto date = Date(4, 2, 29); 4712 date.add!"years"(-5, AllowDayOverflow.no); 4713 assert(date == Date(-1, 2, 28)); 4714 } 4715 4716 { 4717 auto date = Date(4, 2, 29); 4718 date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); 4719 assert(date == Date(6, 2, 28)); 4720 } 4721 } 4722 4723 4724 // Shares documentation with "years" version. 4725 @safe pure nothrow @nogc 4726 ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4727 if (units == "months") 4728 { 4729 auto years = months / 12; 4730 months %= 12; 4731 auto newMonth = _month + months; 4732 4733 if (months < 0) 4734 { 4735 if (newMonth < 1) 4736 { 4737 newMonth += 12; 4738 --years; 4739 } 4740 } 4741 else if (newMonth > 12) 4742 { 4743 newMonth -= 12; 4744 ++years; 4745 } 4746 4747 _year += years; 4748 _month = cast(Month) newMonth; 4749 4750 immutable currMaxDay = maxDay(_year, _month); 4751 immutable overflow = _day - currMaxDay; 4752 4753 if (overflow > 0) 4754 { 4755 if (allowOverflow == AllowDayOverflow.yes) 4756 { 4757 ++_month; 4758 _day = cast(ubyte) overflow; 4759 } 4760 else 4761 _day = cast(ubyte) currMaxDay; 4762 } 4763 4764 return this; 4765 } 4766 4767 // Test add!"months"() with AllowDayOverflow.yes 4768 @safe unittest 4769 { 4770 // Test A.D. 4771 { 4772 auto date = Date(1999, 7, 6); 4773 date.add!"months"(3); 4774 assert(date == Date(1999, 10, 6)); 4775 date.add!"months"(-4); 4776 assert(date == Date(1999, 6, 6)); 4777 } 4778 4779 { 4780 auto date = Date(1999, 7, 6); 4781 date.add!"months"(6); 4782 assert(date == Date(2000, 1, 6)); 4783 date.add!"months"(-6); 4784 assert(date == Date(1999, 7, 6)); 4785 } 4786 4787 { 4788 auto date = Date(1999, 7, 6); 4789 date.add!"months"(27); 4790 assert(date == Date(2001, 10, 6)); 4791 date.add!"months"(-28); 4792 assert(date == Date(1999, 6, 6)); 4793 } 4794 4795 { 4796 auto date = Date(1999, 5, 31); 4797 date.add!"months"(1); 4798 assert(date == Date(1999, 7, 1)); 4799 } 4800 4801 { 4802 auto date = Date(1999, 5, 31); 4803 date.add!"months"(-1); 4804 assert(date == Date(1999, 5, 1)); 4805 } 4806 4807 { 4808 auto date = Date(1999, 2, 28); 4809 date.add!"months"(12); 4810 assert(date == Date(2000, 2, 28)); 4811 } 4812 4813 { 4814 auto date = Date(2000, 2, 29); 4815 date.add!"months"(12); 4816 assert(date == Date(2001, 3, 1)); 4817 } 4818 4819 { 4820 auto date = Date(1999, 7, 31); 4821 date.add!"months"(1); 4822 assert(date == Date(1999, 8, 31)); 4823 date.add!"months"(1); 4824 assert(date == Date(1999, 10, 1)); 4825 } 4826 4827 { 4828 auto date = Date(1998, 8, 31); 4829 date.add!"months"(13); 4830 assert(date == Date(1999, 10, 1)); 4831 date.add!"months"(-13); 4832 assert(date == Date(1998, 9, 1)); 4833 } 4834 4835 { 4836 auto date = Date(1997, 12, 31); 4837 date.add!"months"(13); 4838 assert(date == Date(1999, 1, 31)); 4839 date.add!"months"(-13); 4840 assert(date == Date(1997, 12, 31)); 4841 } 4842 4843 { 4844 auto date = Date(1997, 12, 31); 4845 date.add!"months"(14); 4846 assert(date == Date(1999, 3, 3)); 4847 date.add!"months"(-14); 4848 assert(date == Date(1998, 1, 3)); 4849 } 4850 4851 { 4852 auto date = Date(1998, 12, 31); 4853 date.add!"months"(14); 4854 assert(date == Date(2000, 3, 2)); 4855 date.add!"months"(-14); 4856 assert(date == Date(1999, 1, 2)); 4857 } 4858 4859 { 4860 auto date = Date(1999, 12, 31); 4861 date.add!"months"(14); 4862 assert(date == Date(2001, 3, 3)); 4863 date.add!"months"(-14); 4864 assert(date == Date(2000, 1, 3)); 4865 } 4866 4867 // Test B.C. 4868 { 4869 auto date = Date(-1999, 7, 6); 4870 date.add!"months"(3); 4871 assert(date == Date(-1999, 10, 6)); 4872 date.add!"months"(-4); 4873 assert(date == Date(-1999, 6, 6)); 4874 } 4875 4876 { 4877 auto date = Date(-1999, 7, 6); 4878 date.add!"months"(6); 4879 assert(date == Date(-1998, 1, 6)); 4880 date.add!"months"(-6); 4881 assert(date == Date(-1999, 7, 6)); 4882 } 4883 4884 { 4885 auto date = Date(-1999, 7, 6); 4886 date.add!"months"(-27); 4887 assert(date == Date(-2001, 4, 6)); 4888 date.add!"months"(28); 4889 assert(date == Date(-1999, 8, 6)); 4890 } 4891 4892 { 4893 auto date = Date(-1999, 5, 31); 4894 date.add!"months"(1); 4895 assert(date == Date(-1999, 7, 1)); 4896 } 4897 4898 { 4899 auto date = Date(-1999, 5, 31); 4900 date.add!"months"(-1); 4901 assert(date == Date(-1999, 5, 1)); 4902 } 4903 4904 { 4905 auto date = Date(-1999, 2, 28); 4906 date.add!"months"(-12); 4907 assert(date == Date(-2000, 2, 28)); 4908 } 4909 4910 { 4911 auto date = Date(-2000, 2, 29); 4912 date.add!"months"(-12); 4913 assert(date == Date(-2001, 3, 1)); 4914 } 4915 4916 { 4917 auto date = Date(-1999, 7, 31); 4918 date.add!"months"(1); 4919 assert(date == Date(-1999, 8, 31)); 4920 date.add!"months"(1); 4921 assert(date == Date(-1999, 10, 1)); 4922 } 4923 4924 { 4925 auto date = Date(-1998, 8, 31); 4926 date.add!"months"(13); 4927 assert(date == Date(-1997, 10, 1)); 4928 date.add!"months"(-13); 4929 assert(date == Date(-1998, 9, 1)); 4930 } 4931 4932 { 4933 auto date = Date(-1997, 12, 31); 4934 date.add!"months"(13); 4935 assert(date == Date(-1995, 1, 31)); 4936 date.add!"months"(-13); 4937 assert(date == Date(-1997, 12, 31)); 4938 } 4939 4940 { 4941 auto date = Date(-1997, 12, 31); 4942 date.add!"months"(14); 4943 assert(date == Date(-1995, 3, 3)); 4944 date.add!"months"(-14); 4945 assert(date == Date(-1996, 1, 3)); 4946 } 4947 4948 { 4949 auto date = Date(-2002, 12, 31); 4950 date.add!"months"(14); 4951 assert(date == Date(-2000, 3, 2)); 4952 date.add!"months"(-14); 4953 assert(date == Date(-2001, 1, 2)); 4954 } 4955 4956 { 4957 auto date = Date(-2001, 12, 31); 4958 date.add!"months"(14); 4959 assert(date == Date(-1999, 3, 3)); 4960 date.add!"months"(-14); 4961 assert(date == Date(-2000, 1, 3)); 4962 } 4963 4964 // Test Both 4965 { 4966 auto date = Date(1, 1, 1); 4967 date.add!"months"(-1); 4968 assert(date == Date(0, 12, 1)); 4969 date.add!"months"(1); 4970 assert(date == Date(1, 1, 1)); 4971 } 4972 4973 { 4974 auto date = Date(4, 1, 1); 4975 date.add!"months"(-48); 4976 assert(date == Date(0, 1, 1)); 4977 date.add!"months"(48); 4978 assert(date == Date(4, 1, 1)); 4979 } 4980 4981 { 4982 auto date = Date(4, 3, 31); 4983 date.add!"months"(-49); 4984 assert(date == Date(0, 3, 2)); 4985 date.add!"months"(49); 4986 assert(date == Date(4, 4, 2)); 4987 } 4988 4989 { 4990 auto date = Date(4, 3, 31); 4991 date.add!"months"(-85); 4992 assert(date == Date(-3, 3, 3)); 4993 date.add!"months"(85); 4994 assert(date == Date(4, 4, 3)); 4995 } 4996 4997 { 4998 auto date = Date(-3, 3, 31); 4999 date.add!"months"(85).add!"months"(-83); 5000 assert(date == Date(-3, 6, 1)); 5001 } 5002 5003 const cdate = Date(1999, 7, 6); 5004 immutable idate = Date(1999, 7, 6); 5005 static assert(!__traits(compiles, cdate.add!"months"(3))); 5006 static assert(!__traits(compiles, idate.add!"months"(3))); 5007 } 5008 5009 // Test add!"months"() with AllowDayOverflow.no 5010 @safe unittest 5011 { 5012 // Test A.D. 5013 { 5014 auto date = Date(1999, 7, 6); 5015 date.add!"months"(3, AllowDayOverflow.no); 5016 assert(date == Date(1999, 10, 6)); 5017 date.add!"months"(-4, AllowDayOverflow.no); 5018 assert(date == Date(1999, 6, 6)); 5019 } 5020 5021 { 5022 auto date = Date(1999, 7, 6); 5023 date.add!"months"(6, AllowDayOverflow.no); 5024 assert(date == Date(2000, 1, 6)); 5025 date.add!"months"(-6, AllowDayOverflow.no); 5026 assert(date == Date(1999, 7, 6)); 5027 } 5028 5029 { 5030 auto date = Date(1999, 7, 6); 5031 date.add!"months"(27, AllowDayOverflow.no); 5032 assert(date == Date(2001, 10, 6)); 5033 date.add!"months"(-28, AllowDayOverflow.no); 5034 assert(date == Date(1999, 6, 6)); 5035 } 5036 5037 { 5038 auto date = Date(1999, 5, 31); 5039 date.add!"months"(1, AllowDayOverflow.no); 5040 assert(date == Date(1999, 6, 30)); 5041 } 5042 5043 { 5044 auto date = Date(1999, 5, 31); 5045 date.add!"months"(-1, AllowDayOverflow.no); 5046 assert(date == Date(1999, 4, 30)); 5047 } 5048 5049 { 5050 auto date = Date(1999, 2, 28); 5051 date.add!"months"(12, AllowDayOverflow.no); 5052 assert(date == Date(2000, 2, 28)); 5053 } 5054 5055 { 5056 auto date = Date(2000, 2, 29); 5057 date.add!"months"(12, AllowDayOverflow.no); 5058 assert(date == Date(2001, 2, 28)); 5059 } 5060 5061 { 5062 auto date = Date(1999, 7, 31); 5063 date.add!"months"(1, AllowDayOverflow.no); 5064 assert(date == Date(1999, 8, 31)); 5065 date.add!"months"(1, AllowDayOverflow.no); 5066 assert(date == Date(1999, 9, 30)); 5067 } 5068 5069 { 5070 auto date = Date(1998, 8, 31); 5071 date.add!"months"(13, AllowDayOverflow.no); 5072 assert(date == Date(1999, 9, 30)); 5073 date.add!"months"(-13, AllowDayOverflow.no); 5074 assert(date == Date(1998, 8, 30)); 5075 } 5076 5077 { 5078 auto date = Date(1997, 12, 31); 5079 date.add!"months"(13, AllowDayOverflow.no); 5080 assert(date == Date(1999, 1, 31)); 5081 date.add!"months"(-13, AllowDayOverflow.no); 5082 assert(date == Date(1997, 12, 31)); 5083 } 5084 5085 { 5086 auto date = Date(1997, 12, 31); 5087 date.add!"months"(14, AllowDayOverflow.no); 5088 assert(date == Date(1999, 2, 28)); 5089 date.add!"months"(-14, AllowDayOverflow.no); 5090 assert(date == Date(1997, 12, 28)); 5091 } 5092 5093 { 5094 auto date = Date(1998, 12, 31); 5095 date.add!"months"(14, AllowDayOverflow.no); 5096 assert(date == Date(2000, 2, 29)); 5097 date.add!"months"(-14, AllowDayOverflow.no); 5098 assert(date == Date(1998, 12, 29)); 5099 } 5100 5101 { 5102 auto date = Date(1999, 12, 31); 5103 date.add!"months"(14, AllowDayOverflow.no); 5104 assert(date == Date(2001, 2, 28)); 5105 date.add!"months"(-14, AllowDayOverflow.no); 5106 assert(date == Date(1999, 12, 28)); 5107 } 5108 5109 // Test B.C. 5110 { 5111 auto date = Date(-1999, 7, 6); 5112 date.add!"months"(3, AllowDayOverflow.no); 5113 assert(date == Date(-1999, 10, 6)); 5114 date.add!"months"(-4, AllowDayOverflow.no); 5115 assert(date == Date(-1999, 6, 6)); 5116 } 5117 5118 { 5119 auto date = Date(-1999, 7, 6); 5120 date.add!"months"(6, AllowDayOverflow.no); 5121 assert(date == Date(-1998, 1, 6)); 5122 date.add!"months"(-6, AllowDayOverflow.no); 5123 assert(date == Date(-1999, 7, 6)); 5124 } 5125 5126 { 5127 auto date = Date(-1999, 7, 6); 5128 date.add!"months"(-27, AllowDayOverflow.no); 5129 assert(date == Date(-2001, 4, 6)); 5130 date.add!"months"(28, AllowDayOverflow.no); 5131 assert(date == Date(-1999, 8, 6)); 5132 } 5133 5134 { 5135 auto date = Date(-1999, 5, 31); 5136 date.add!"months"(1, AllowDayOverflow.no); 5137 assert(date == Date(-1999, 6, 30)); 5138 } 5139 5140 { 5141 auto date = Date(-1999, 5, 31); 5142 date.add!"months"(-1, AllowDayOverflow.no); 5143 assert(date == Date(-1999, 4, 30)); 5144 } 5145 5146 { 5147 auto date = Date(-1999, 2, 28); 5148 date.add!"months"(-12, AllowDayOverflow.no); 5149 assert(date == Date(-2000, 2, 28)); 5150 } 5151 5152 { 5153 auto date = Date(-2000, 2, 29); 5154 date.add!"months"(-12, AllowDayOverflow.no); 5155 assert(date == Date(-2001, 2, 28)); 5156 } 5157 5158 { 5159 auto date = Date(-1999, 7, 31); 5160 date.add!"months"(1, AllowDayOverflow.no); 5161 assert(date == Date(-1999, 8, 31)); 5162 date.add!"months"(1, AllowDayOverflow.no); 5163 assert(date == Date(-1999, 9, 30)); 5164 } 5165 5166 { 5167 auto date = Date(-1998, 8, 31); 5168 date.add!"months"(13, AllowDayOverflow.no); 5169 assert(date == Date(-1997, 9, 30)); 5170 date.add!"months"(-13, AllowDayOverflow.no); 5171 assert(date == Date(-1998, 8, 30)); 5172 } 5173 5174 { 5175 auto date = Date(-1997, 12, 31); 5176 date.add!"months"(13, AllowDayOverflow.no); 5177 assert(date == Date(-1995, 1, 31)); 5178 date.add!"months"(-13, AllowDayOverflow.no); 5179 assert(date == Date(-1997, 12, 31)); 5180 } 5181 5182 { 5183 auto date = Date(-1997, 12, 31); 5184 date.add!"months"(14, AllowDayOverflow.no); 5185 assert(date == Date(-1995, 2, 28)); 5186 date.add!"months"(-14, AllowDayOverflow.no); 5187 assert(date == Date(-1997, 12, 28)); 5188 } 5189 5190 { 5191 auto date = Date(-2002, 12, 31); 5192 date.add!"months"(14, AllowDayOverflow.no); 5193 assert(date == Date(-2000, 2, 29)); 5194 date.add!"months"(-14, AllowDayOverflow.no); 5195 assert(date == Date(-2002, 12, 29)); 5196 } 5197 5198 { 5199 auto date = Date(-2001, 12, 31); 5200 date.add!"months"(14, AllowDayOverflow.no); 5201 assert(date == Date(-1999, 2, 28)); 5202 date.add!"months"(-14, AllowDayOverflow.no); 5203 assert(date == Date(-2001, 12, 28)); 5204 } 5205 5206 // Test Both 5207 { 5208 auto date = Date(1, 1, 1); 5209 date.add!"months"(-1, AllowDayOverflow.no); 5210 assert(date == Date(0, 12, 1)); 5211 date.add!"months"(1, AllowDayOverflow.no); 5212 assert(date == Date(1, 1, 1)); 5213 } 5214 5215 { 5216 auto date = Date(4, 1, 1); 5217 date.add!"months"(-48, AllowDayOverflow.no); 5218 assert(date == Date(0, 1, 1)); 5219 date.add!"months"(48, AllowDayOverflow.no); 5220 assert(date == Date(4, 1, 1)); 5221 } 5222 5223 { 5224 auto date = Date(4, 3, 31); 5225 date.add!"months"(-49, AllowDayOverflow.no); 5226 assert(date == Date(0, 2, 29)); 5227 date.add!"months"(49, AllowDayOverflow.no); 5228 assert(date == Date(4, 3, 29)); 5229 } 5230 5231 { 5232 auto date = Date(4, 3, 31); 5233 date.add!"months"(-85, AllowDayOverflow.no); 5234 assert(date == Date(-3, 2, 28)); 5235 date.add!"months"(85, AllowDayOverflow.no); 5236 assert(date == Date(4, 3, 28)); 5237 } 5238 5239 { 5240 auto date = Date(-3, 3, 31); 5241 date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); 5242 assert(date == Date(-3, 5, 30)); 5243 } 5244 } 5245 5246 5247 /++ 5248 Adds the given number of years or months to this $(LREF Date), mutating 5249 it. A negative number will subtract. 5250 5251 The difference between rolling and adding is that rolling does not 5252 affect larger units. Rolling a $(LREF Date) 12 months gets 5253 the exact same $(LREF Date). However, the days can still be affected due 5254 to the differing number of days in each month. 5255 5256 Because there are no units larger than years, there is no difference 5257 between adding and rolling years. 5258 5259 Params: 5260 units = The type of units to add ("years" or "months"). 5261 value = The number of months or years to add to this 5262 $(LREF Date). 5263 allowOverflow = Whether the day should be allowed to overflow, 5264 causing the month to increment. 5265 5266 Returns: 5267 A reference to the `Date` (`this`). 5268 +/ 5269 @safe pure nothrow @nogc 5270 ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5271 if (units == "years") 5272 { 5273 return add!"years"(value, allowOverflow); 5274 } 5275 5276 /// 5277 @safe unittest 5278 { 5279 auto d1 = Date(2010, 1, 1); 5280 d1.roll!"months"(1); 5281 assert(d1 == Date(2010, 2, 1)); 5282 5283 auto d2 = Date(2010, 1, 1); 5284 d2.roll!"months"(-1); 5285 assert(d2 == Date(2010, 12, 1)); 5286 5287 auto d3 = Date(1999, 1, 29); 5288 d3.roll!"months"(1); 5289 assert(d3 == Date(1999, 3, 1)); 5290 5291 auto d4 = Date(1999, 1, 29); 5292 d4.roll!"months"(1, AllowDayOverflow.no); 5293 assert(d4 == Date(1999, 2, 28)); 5294 5295 auto d5 = Date(2000, 2, 29); 5296 d5.roll!"years"(1); 5297 assert(d5 == Date(2001, 3, 1)); 5298 5299 auto d6 = Date(2000, 2, 29); 5300 d6.roll!"years"(1, AllowDayOverflow.no); 5301 assert(d6 == Date(2001, 2, 28)); 5302 } 5303 5304 @safe unittest 5305 { 5306 const cdate = Date(1999, 7, 6); 5307 immutable idate = Date(1999, 7, 6); 5308 static assert(!__traits(compiles, cdate.roll!"years"(3))); 5309 static assert(!__traits(compiles, idate.rolYears(3))); 5310 } 5311 5312 5313 // Shares documentation with "years" version. 5314 @safe pure nothrow @nogc 5315 ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5316 if (units == "months") 5317 { 5318 months %= 12; 5319 auto newMonth = _month + months; 5320 5321 if (months < 0) 5322 { 5323 if (newMonth < 1) 5324 newMonth += 12; 5325 } 5326 else 5327 { 5328 if (newMonth > 12) 5329 newMonth -= 12; 5330 } 5331 5332 _month = cast(Month) newMonth; 5333 5334 immutable currMaxDay = maxDay(_year, _month); 5335 immutable overflow = _day - currMaxDay; 5336 5337 if (overflow > 0) 5338 { 5339 if (allowOverflow == AllowDayOverflow.yes) 5340 { 5341 ++_month; 5342 _day = cast(ubyte) overflow; 5343 } 5344 else 5345 _day = cast(ubyte) currMaxDay; 5346 } 5347 5348 return this; 5349 } 5350 5351 // Test roll!"months"() with AllowDayOverflow.yes 5352 @safe unittest 5353 { 5354 // Test A.D. 5355 { 5356 auto date = Date(1999, 7, 6); 5357 date.roll!"months"(3); 5358 assert(date == Date(1999, 10, 6)); 5359 date.roll!"months"(-4); 5360 assert(date == Date(1999, 6, 6)); 5361 } 5362 5363 { 5364 auto date = Date(1999, 7, 6); 5365 date.roll!"months"(6); 5366 assert(date == Date(1999, 1, 6)); 5367 date.roll!"months"(-6); 5368 assert(date == Date(1999, 7, 6)); 5369 } 5370 5371 { 5372 auto date = Date(1999, 7, 6); 5373 date.roll!"months"(27); 5374 assert(date == Date(1999, 10, 6)); 5375 date.roll!"months"(-28); 5376 assert(date == Date(1999, 6, 6)); 5377 } 5378 5379 { 5380 auto date = Date(1999, 5, 31); 5381 date.roll!"months"(1); 5382 assert(date == Date(1999, 7, 1)); 5383 } 5384 5385 { 5386 auto date = Date(1999, 5, 31); 5387 date.roll!"months"(-1); 5388 assert(date == Date(1999, 5, 1)); 5389 } 5390 5391 { 5392 auto date = Date(1999, 2, 28); 5393 date.roll!"months"(12); 5394 assert(date == Date(1999, 2, 28)); 5395 } 5396 5397 { 5398 auto date = Date(2000, 2, 29); 5399 date.roll!"months"(12); 5400 assert(date == Date(2000, 2, 29)); 5401 } 5402 5403 { 5404 auto date = Date(1999, 7, 31); 5405 date.roll!"months"(1); 5406 assert(date == Date(1999, 8, 31)); 5407 date.roll!"months"(1); 5408 assert(date == Date(1999, 10, 1)); 5409 } 5410 5411 { 5412 auto date = Date(1998, 8, 31); 5413 date.roll!"months"(13); 5414 assert(date == Date(1998, 10, 1)); 5415 date.roll!"months"(-13); 5416 assert(date == Date(1998, 9, 1)); 5417 } 5418 5419 { 5420 auto date = Date(1997, 12, 31); 5421 date.roll!"months"(13); 5422 assert(date == Date(1997, 1, 31)); 5423 date.roll!"months"(-13); 5424 assert(date == Date(1997, 12, 31)); 5425 } 5426 5427 { 5428 auto date = Date(1997, 12, 31); 5429 date.roll!"months"(14); 5430 assert(date == Date(1997, 3, 3)); 5431 date.roll!"months"(-14); 5432 assert(date == Date(1997, 1, 3)); 5433 } 5434 5435 { 5436 auto date = Date(1998, 12, 31); 5437 date.roll!"months"(14); 5438 assert(date == Date(1998, 3, 3)); 5439 date.roll!"months"(-14); 5440 assert(date == Date(1998, 1, 3)); 5441 } 5442 5443 { 5444 auto date = Date(1999, 12, 31); 5445 date.roll!"months"(14); 5446 assert(date == Date(1999, 3, 3)); 5447 date.roll!"months"(-14); 5448 assert(date == Date(1999, 1, 3)); 5449 } 5450 5451 // Test B.C. 5452 { 5453 auto date = Date(-1999, 7, 6); 5454 date.roll!"months"(3); 5455 assert(date == Date(-1999, 10, 6)); 5456 date.roll!"months"(-4); 5457 assert(date == Date(-1999, 6, 6)); 5458 } 5459 5460 { 5461 auto date = Date(-1999, 7, 6); 5462 date.roll!"months"(6); 5463 assert(date == Date(-1999, 1, 6)); 5464 date.roll!"months"(-6); 5465 assert(date == Date(-1999, 7, 6)); 5466 } 5467 5468 { 5469 auto date = Date(-1999, 7, 6); 5470 date.roll!"months"(-27); 5471 assert(date == Date(-1999, 4, 6)); 5472 date.roll!"months"(28); 5473 assert(date == Date(-1999, 8, 6)); 5474 } 5475 5476 { 5477 auto date = Date(-1999, 5, 31); 5478 date.roll!"months"(1); 5479 assert(date == Date(-1999, 7, 1)); 5480 } 5481 5482 { 5483 auto date = Date(-1999, 5, 31); 5484 date.roll!"months"(-1); 5485 assert(date == Date(-1999, 5, 1)); 5486 } 5487 5488 { 5489 auto date = Date(-1999, 2, 28); 5490 date.roll!"months"(-12); 5491 assert(date == Date(-1999, 2, 28)); 5492 } 5493 5494 { 5495 auto date = Date(-2000, 2, 29); 5496 date.roll!"months"(-12); 5497 assert(date == Date(-2000, 2, 29)); 5498 } 5499 5500 { 5501 auto date = Date(-1999, 7, 31); 5502 date.roll!"months"(1); 5503 assert(date == Date(-1999, 8, 31)); 5504 date.roll!"months"(1); 5505 assert(date == Date(-1999, 10, 1)); 5506 } 5507 5508 { 5509 auto date = Date(-1998, 8, 31); 5510 date.roll!"months"(13); 5511 assert(date == Date(-1998, 10, 1)); 5512 date.roll!"months"(-13); 5513 assert(date == Date(-1998, 9, 1)); 5514 } 5515 5516 { 5517 auto date = Date(-1997, 12, 31); 5518 date.roll!"months"(13); 5519 assert(date == Date(-1997, 1, 31)); 5520 date.roll!"months"(-13); 5521 assert(date == Date(-1997, 12, 31)); 5522 } 5523 5524 { 5525 auto date = Date(-1997, 12, 31); 5526 date.roll!"months"(14); 5527 assert(date == Date(-1997, 3, 3)); 5528 date.roll!"months"(-14); 5529 assert(date == Date(-1997, 1, 3)); 5530 } 5531 5532 { 5533 auto date = Date(-2002, 12, 31); 5534 date.roll!"months"(14); 5535 assert(date == Date(-2002, 3, 3)); 5536 date.roll!"months"(-14); 5537 assert(date == Date(-2002, 1, 3)); 5538 } 5539 5540 { 5541 auto date = Date(-2001, 12, 31); 5542 date.roll!"months"(14); 5543 assert(date == Date(-2001, 3, 3)); 5544 date.roll!"months"(-14); 5545 assert(date == Date(-2001, 1, 3)); 5546 } 5547 5548 // Test Both 5549 { 5550 auto date = Date(1, 1, 1); 5551 date.roll!"months"(-1); 5552 assert(date == Date(1, 12, 1)); 5553 date.roll!"months"(1); 5554 assert(date == Date(1, 1, 1)); 5555 } 5556 5557 { 5558 auto date = Date(4, 1, 1); 5559 date.roll!"months"(-48); 5560 assert(date == Date(4, 1, 1)); 5561 date.roll!"months"(48); 5562 assert(date == Date(4, 1, 1)); 5563 } 5564 5565 { 5566 auto date = Date(4, 3, 31); 5567 date.roll!"months"(-49); 5568 assert(date == Date(4, 3, 2)); 5569 date.roll!"months"(49); 5570 assert(date == Date(4, 4, 2)); 5571 } 5572 5573 { 5574 auto date = Date(4, 3, 31); 5575 date.roll!"months"(-85); 5576 assert(date == Date(4, 3, 2)); 5577 date.roll!"months"(85); 5578 assert(date == Date(4, 4, 2)); 5579 } 5580 5581 { 5582 auto date = Date(-1, 1, 1); 5583 date.roll!"months"(-1); 5584 assert(date == Date(-1, 12, 1)); 5585 date.roll!"months"(1); 5586 assert(date == Date(-1, 1, 1)); 5587 } 5588 5589 { 5590 auto date = Date(-4, 1, 1); 5591 date.roll!"months"(-48); 5592 assert(date == Date(-4, 1, 1)); 5593 date.roll!"months"(48); 5594 assert(date == Date(-4, 1, 1)); 5595 } 5596 5597 { 5598 auto date = Date(-4, 3, 31); 5599 date.roll!"months"(-49); 5600 assert(date == Date(-4, 3, 2)); 5601 date.roll!"months"(49); 5602 assert(date == Date(-4, 4, 2)); 5603 } 5604 5605 { 5606 auto date = Date(-4, 3, 31); 5607 date.roll!"months"(-85); 5608 assert(date == Date(-4, 3, 2)); 5609 date.roll!"months"(85); 5610 assert(date == Date(-4, 4, 2)); 5611 } 5612 5613 { 5614 auto date = Date(-3, 3, 31); 5615 date.roll!"months"(85).roll!"months"(-83); 5616 assert(date == Date(-3, 6, 1)); 5617 } 5618 5619 const cdate = Date(1999, 7, 6); 5620 immutable idate = Date(1999, 7, 6); 5621 static assert(!__traits(compiles, cdate.roll!"months"(3))); 5622 static assert(!__traits(compiles, idate.roll!"months"(3))); 5623 } 5624 5625 // Test roll!"months"() with AllowDayOverflow.no 5626 @safe unittest 5627 { 5628 // Test A.D. 5629 { 5630 auto date = Date(1999, 7, 6); 5631 date.roll!"months"(3, AllowDayOverflow.no); 5632 assert(date == Date(1999, 10, 6)); 5633 date.roll!"months"(-4, AllowDayOverflow.no); 5634 assert(date == Date(1999, 6, 6)); 5635 } 5636 5637 { 5638 auto date = Date(1999, 7, 6); 5639 date.roll!"months"(6, AllowDayOverflow.no); 5640 assert(date == Date(1999, 1, 6)); 5641 date.roll!"months"(-6, AllowDayOverflow.no); 5642 assert(date == Date(1999, 7, 6)); 5643 } 5644 5645 { 5646 auto date = Date(1999, 7, 6); 5647 date.roll!"months"(27, AllowDayOverflow.no); 5648 assert(date == Date(1999, 10, 6)); 5649 date.roll!"months"(-28, AllowDayOverflow.no); 5650 assert(date == Date(1999, 6, 6)); 5651 } 5652 5653 { 5654 auto date = Date(1999, 5, 31); 5655 date.roll!"months"(1, AllowDayOverflow.no); 5656 assert(date == Date(1999, 6, 30)); 5657 } 5658 5659 { 5660 auto date = Date(1999, 5, 31); 5661 date.roll!"months"(-1, AllowDayOverflow.no); 5662 assert(date == Date(1999, 4, 30)); 5663 } 5664 5665 { 5666 auto date = Date(1999, 2, 28); 5667 date.roll!"months"(12, AllowDayOverflow.no); 5668 assert(date == Date(1999, 2, 28)); 5669 } 5670 5671 { 5672 auto date = Date(2000, 2, 29); 5673 date.roll!"months"(12, AllowDayOverflow.no); 5674 assert(date == Date(2000, 2, 29)); 5675 } 5676 5677 { 5678 auto date = Date(1999, 7, 31); 5679 date.roll!"months"(1, AllowDayOverflow.no); 5680 assert(date == Date(1999, 8, 31)); 5681 date.roll!"months"(1, AllowDayOverflow.no); 5682 assert(date == Date(1999, 9, 30)); 5683 } 5684 5685 { 5686 auto date = Date(1998, 8, 31); 5687 date.roll!"months"(13, AllowDayOverflow.no); 5688 assert(date == Date(1998, 9, 30)); 5689 date.roll!"months"(-13, AllowDayOverflow.no); 5690 assert(date == Date(1998, 8, 30)); 5691 } 5692 5693 { 5694 auto date = Date(1997, 12, 31); 5695 date.roll!"months"(13, AllowDayOverflow.no); 5696 assert(date == Date(1997, 1, 31)); 5697 date.roll!"months"(-13, AllowDayOverflow.no); 5698 assert(date == Date(1997, 12, 31)); 5699 } 5700 5701 { 5702 auto date = Date(1997, 12, 31); 5703 date.roll!"months"(14, AllowDayOverflow.no); 5704 assert(date == Date(1997, 2, 28)); 5705 date.roll!"months"(-14, AllowDayOverflow.no); 5706 assert(date == Date(1997, 12, 28)); 5707 } 5708 5709 { 5710 auto date = Date(1998, 12, 31); 5711 date.roll!"months"(14, AllowDayOverflow.no); 5712 assert(date == Date(1998, 2, 28)); 5713 date.roll!"months"(-14, AllowDayOverflow.no); 5714 assert(date == Date(1998, 12, 28)); 5715 } 5716 5717 { 5718 auto date = Date(1999, 12, 31); 5719 date.roll!"months"(14, AllowDayOverflow.no); 5720 assert(date == Date(1999, 2, 28)); 5721 date.roll!"months"(-14, AllowDayOverflow.no); 5722 assert(date == Date(1999, 12, 28)); 5723 } 5724 5725 // Test B.C. 5726 { 5727 auto date = Date(-1999, 7, 6); 5728 date.roll!"months"(3, AllowDayOverflow.no); 5729 assert(date == Date(-1999, 10, 6)); 5730 date.roll!"months"(-4, AllowDayOverflow.no); 5731 assert(date == Date(-1999, 6, 6)); 5732 } 5733 5734 { 5735 auto date = Date(-1999, 7, 6); 5736 date.roll!"months"(6, AllowDayOverflow.no); 5737 assert(date == Date(-1999, 1, 6)); 5738 date.roll!"months"(-6, AllowDayOverflow.no); 5739 assert(date == Date(-1999, 7, 6)); 5740 } 5741 5742 { 5743 auto date = Date(-1999, 7, 6); 5744 date.roll!"months"(-27, AllowDayOverflow.no); 5745 assert(date == Date(-1999, 4, 6)); 5746 date.roll!"months"(28, AllowDayOverflow.no); 5747 assert(date == Date(-1999, 8, 6)); 5748 } 5749 5750 { 5751 auto date = Date(-1999, 5, 31); 5752 date.roll!"months"(1, AllowDayOverflow.no); 5753 assert(date == Date(-1999, 6, 30)); 5754 } 5755 5756 { 5757 auto date = Date(-1999, 5, 31); 5758 date.roll!"months"(-1, AllowDayOverflow.no); 5759 assert(date == Date(-1999, 4, 30)); 5760 } 5761 5762 { 5763 auto date = Date(-1999, 2, 28); 5764 date.roll!"months"(-12, AllowDayOverflow.no); 5765 assert(date == Date(-1999, 2, 28)); 5766 } 5767 5768 { 5769 auto date = Date(-2000, 2, 29); 5770 date.roll!"months"(-12, AllowDayOverflow.no); 5771 assert(date == Date(-2000, 2, 29)); 5772 } 5773 5774 { 5775 auto date = Date(-1999, 7, 31); 5776 date.roll!"months"(1, AllowDayOverflow.no); 5777 assert(date == Date(-1999, 8, 31)); 5778 date.roll!"months"(1, AllowDayOverflow.no); 5779 assert(date == Date(-1999, 9, 30)); 5780 } 5781 5782 { 5783 auto date = Date(-1998, 8, 31); 5784 date.roll!"months"(13, AllowDayOverflow.no); 5785 assert(date == Date(-1998, 9, 30)); 5786 date.roll!"months"(-13, AllowDayOverflow.no); 5787 assert(date == Date(-1998, 8, 30)); 5788 } 5789 5790 { 5791 auto date = Date(-1997, 12, 31); 5792 date.roll!"months"(13, AllowDayOverflow.no); 5793 assert(date == Date(-1997, 1, 31)); 5794 date.roll!"months"(-13, AllowDayOverflow.no); 5795 assert(date == Date(-1997, 12, 31)); 5796 } 5797 5798 { 5799 auto date = Date(-1997, 12, 31); 5800 date.roll!"months"(14, AllowDayOverflow.no); 5801 assert(date == Date(-1997, 2, 28)); 5802 date.roll!"months"(-14, AllowDayOverflow.no); 5803 assert(date == Date(-1997, 12, 28)); 5804 } 5805 5806 { 5807 auto date = Date(-2002, 12, 31); 5808 date.roll!"months"(14, AllowDayOverflow.no); 5809 assert(date == Date(-2002, 2, 28)); 5810 date.roll!"months"(-14, AllowDayOverflow.no); 5811 assert(date == Date(-2002, 12, 28)); 5812 } 5813 5814 { 5815 auto date = Date(-2001, 12, 31); 5816 date.roll!"months"(14, AllowDayOverflow.no); 5817 assert(date == Date(-2001, 2, 28)); 5818 date.roll!"months"(-14, AllowDayOverflow.no); 5819 assert(date == Date(-2001, 12, 28)); 5820 } 5821 5822 // Test Both 5823 { 5824 auto date = Date(1, 1, 1); 5825 date.roll!"months"(-1, AllowDayOverflow.no); 5826 assert(date == Date(1, 12, 1)); 5827 date.roll!"months"(1, AllowDayOverflow.no); 5828 assert(date == Date(1, 1, 1)); 5829 } 5830 5831 { 5832 auto date = Date(4, 1, 1); 5833 date.roll!"months"(-48, AllowDayOverflow.no); 5834 assert(date == Date(4, 1, 1)); 5835 date.roll!"months"(48, AllowDayOverflow.no); 5836 assert(date == Date(4, 1, 1)); 5837 } 5838 5839 { 5840 auto date = Date(4, 3, 31); 5841 date.roll!"months"(-49, AllowDayOverflow.no); 5842 assert(date == Date(4, 2, 29)); 5843 date.roll!"months"(49, AllowDayOverflow.no); 5844 assert(date == Date(4, 3, 29)); 5845 } 5846 5847 { 5848 auto date = Date(4, 3, 31); 5849 date.roll!"months"(-85, AllowDayOverflow.no); 5850 assert(date == Date(4, 2, 29)); 5851 date.roll!"months"(85, AllowDayOverflow.no); 5852 assert(date == Date(4, 3, 29)); 5853 } 5854 5855 { 5856 auto date = Date(-1, 1, 1); 5857 date.roll!"months"(-1, AllowDayOverflow.no); 5858 assert(date == Date(-1, 12, 1)); 5859 date.roll!"months"(1, AllowDayOverflow.no); 5860 assert(date == Date(-1, 1, 1)); 5861 } 5862 5863 { 5864 auto date = Date(-4, 1, 1); 5865 date.roll!"months"(-48, AllowDayOverflow.no); 5866 assert(date == Date(-4, 1, 1)); 5867 date.roll!"months"(48, AllowDayOverflow.no); 5868 assert(date == Date(-4, 1, 1)); 5869 } 5870 5871 { 5872 auto date = Date(-4, 3, 31); 5873 date.roll!"months"(-49, AllowDayOverflow.no); 5874 assert(date == Date(-4, 2, 29)); 5875 date.roll!"months"(49, AllowDayOverflow.no); 5876 assert(date == Date(-4, 3, 29)); 5877 } 5878 5879 { 5880 auto date = Date(-4, 3, 31); 5881 date.roll!"months"(-85, AllowDayOverflow.no); 5882 assert(date == Date(-4, 2, 29)); 5883 date.roll!"months"(85, AllowDayOverflow.no); 5884 assert(date == Date(-4, 3, 29)); 5885 } 5886 5887 { 5888 auto date = Date(-3, 3, 31); 5889 date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); 5890 assert(date == Date(-3, 5, 30)); 5891 } 5892 } 5893 5894 5895 /++ 5896 Adds the given number of units to this $(LREF Date), mutating it. A 5897 negative number will subtract. 5898 5899 The difference between rolling and adding is that rolling does not 5900 affect larger units. For instance, rolling a $(LREF Date) one 5901 year's worth of days gets the exact same $(LREF Date). 5902 5903 The only accepted units are `"days"`. 5904 5905 Params: 5906 units = The units to add. Must be `"days"`. 5907 days = The number of days to add to this $(LREF Date). 5908 5909 Returns: 5910 A reference to the `Date` (`this`). 5911 +/ 5912 ref Date roll(string units)(long days) @safe pure nothrow @nogc 5913 if (units == "days") 5914 { 5915 immutable limit = maxDay(_year, _month); 5916 days %= limit; 5917 auto newDay = _day + days; 5918 5919 if (days < 0) 5920 { 5921 if (newDay < 1) 5922 newDay += limit; 5923 } 5924 else if (newDay > limit) 5925 newDay -= limit; 5926 5927 _day = cast(ubyte) newDay; 5928 return this; 5929 } 5930 5931 /// 5932 @safe unittest 5933 { 5934 auto d = Date(2010, 1, 1); 5935 d.roll!"days"(1); 5936 assert(d == Date(2010, 1, 2)); 5937 d.roll!"days"(365); 5938 assert(d == Date(2010, 1, 26)); 5939 d.roll!"days"(-32); 5940 assert(d == Date(2010, 1, 25)); 5941 } 5942 5943 @safe unittest 5944 { 5945 // Test A.D. 5946 { 5947 auto date = Date(1999, 2, 28); 5948 date.roll!"days"(1); 5949 assert(date == Date(1999, 2, 1)); 5950 date.roll!"days"(-1); 5951 assert(date == Date(1999, 2, 28)); 5952 } 5953 5954 { 5955 auto date = Date(2000, 2, 28); 5956 date.roll!"days"(1); 5957 assert(date == Date(2000, 2, 29)); 5958 date.roll!"days"(1); 5959 assert(date == Date(2000, 2, 1)); 5960 date.roll!"days"(-1); 5961 assert(date == Date(2000, 2, 29)); 5962 } 5963 5964 { 5965 auto date = Date(1999, 6, 30); 5966 date.roll!"days"(1); 5967 assert(date == Date(1999, 6, 1)); 5968 date.roll!"days"(-1); 5969 assert(date == Date(1999, 6, 30)); 5970 } 5971 5972 { 5973 auto date = Date(1999, 7, 31); 5974 date.roll!"days"(1); 5975 assert(date == Date(1999, 7, 1)); 5976 date.roll!"days"(-1); 5977 assert(date == Date(1999, 7, 31)); 5978 } 5979 5980 { 5981 auto date = Date(1999, 1, 1); 5982 date.roll!"days"(-1); 5983 assert(date == Date(1999, 1, 31)); 5984 date.roll!"days"(1); 5985 assert(date == Date(1999, 1, 1)); 5986 } 5987 5988 { 5989 auto date = Date(1999, 7, 6); 5990 date.roll!"days"(9); 5991 assert(date == Date(1999, 7, 15)); 5992 date.roll!"days"(-11); 5993 assert(date == Date(1999, 7, 4)); 5994 date.roll!"days"(30); 5995 assert(date == Date(1999, 7, 3)); 5996 date.roll!"days"(-3); 5997 assert(date == Date(1999, 7, 31)); 5998 } 5999 6000 { 6001 auto date = Date(1999, 7, 6); 6002 date.roll!"days"(365); 6003 assert(date == Date(1999, 7, 30)); 6004 date.roll!"days"(-365); 6005 assert(date == Date(1999, 7, 6)); 6006 date.roll!"days"(366); 6007 assert(date == Date(1999, 7, 31)); 6008 date.roll!"days"(730); 6009 assert(date == Date(1999, 7, 17)); 6010 date.roll!"days"(-1096); 6011 assert(date == Date(1999, 7, 6)); 6012 } 6013 6014 { 6015 auto date = Date(1999, 2, 6); 6016 date.roll!"days"(365); 6017 assert(date == Date(1999, 2, 7)); 6018 date.roll!"days"(-365); 6019 assert(date == Date(1999, 2, 6)); 6020 date.roll!"days"(366); 6021 assert(date == Date(1999, 2, 8)); 6022 date.roll!"days"(730); 6023 assert(date == Date(1999, 2, 10)); 6024 date.roll!"days"(-1096); 6025 assert(date == Date(1999, 2, 6)); 6026 } 6027 6028 // Test B.C. 6029 { 6030 auto date = Date(-1999, 2, 28); 6031 date.roll!"days"(1); 6032 assert(date == Date(-1999, 2, 1)); 6033 date.roll!"days"(-1); 6034 assert(date == Date(-1999, 2, 28)); 6035 } 6036 6037 { 6038 auto date = Date(-2000, 2, 28); 6039 date.roll!"days"(1); 6040 assert(date == Date(-2000, 2, 29)); 6041 date.roll!"days"(1); 6042 assert(date == Date(-2000, 2, 1)); 6043 date.roll!"days"(-1); 6044 assert(date == Date(-2000, 2, 29)); 6045 } 6046 6047 { 6048 auto date = Date(-1999, 6, 30); 6049 date.roll!"days"(1); 6050 assert(date == Date(-1999, 6, 1)); 6051 date.roll!"days"(-1); 6052 assert(date == Date(-1999, 6, 30)); 6053 } 6054 6055 { 6056 auto date = Date(-1999, 7, 31); 6057 date.roll!"days"(1); 6058 assert(date == Date(-1999, 7, 1)); 6059 date.roll!"days"(-1); 6060 assert(date == Date(-1999, 7, 31)); 6061 } 6062 6063 { 6064 auto date = Date(-1999, 1, 1); 6065 date.roll!"days"(-1); 6066 assert(date == Date(-1999, 1, 31)); 6067 date.roll!"days"(1); 6068 assert(date == Date(-1999, 1, 1)); 6069 } 6070 6071 { 6072 auto date = Date(-1999, 7, 6); 6073 date.roll!"days"(9); 6074 assert(date == Date(-1999, 7, 15)); 6075 date.roll!"days"(-11); 6076 assert(date == Date(-1999, 7, 4)); 6077 date.roll!"days"(30); 6078 assert(date == Date(-1999, 7, 3)); 6079 date.roll!"days"(-3); 6080 assert(date == Date(-1999, 7, 31)); 6081 } 6082 6083 { 6084 auto date = Date(-1999, 7, 6); 6085 date.roll!"days"(365); 6086 assert(date == Date(-1999, 7, 30)); 6087 date.roll!"days"(-365); 6088 assert(date == Date(-1999, 7, 6)); 6089 date.roll!"days"(366); 6090 assert(date == Date(-1999, 7, 31)); 6091 date.roll!"days"(730); 6092 assert(date == Date(-1999, 7, 17)); 6093 date.roll!"days"(-1096); 6094 assert(date == Date(-1999, 7, 6)); 6095 } 6096 6097 // Test Both 6098 { 6099 auto date = Date(1, 7, 6); 6100 date.roll!"days"(-365); 6101 assert(date == Date(1, 7, 13)); 6102 date.roll!"days"(365); 6103 assert(date == Date(1, 7, 6)); 6104 date.roll!"days"(-731); 6105 assert(date == Date(1, 7, 19)); 6106 date.roll!"days"(730); 6107 assert(date == Date(1, 7, 5)); 6108 } 6109 6110 { 6111 auto date = Date(0, 7, 6); 6112 date.roll!"days"(-365); 6113 assert(date == Date(0, 7, 13)); 6114 date.roll!"days"(365); 6115 assert(date == Date(0, 7, 6)); 6116 date.roll!"days"(-731); 6117 assert(date == Date(0, 7, 19)); 6118 date.roll!"days"(730); 6119 assert(date == Date(0, 7, 5)); 6120 } 6121 6122 { 6123 auto date = Date(0, 7, 6); 6124 date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); 6125 assert(date == Date(0, 7, 8)); 6126 } 6127 6128 const cdate = Date(1999, 7, 6); 6129 immutable idate = Date(1999, 7, 6); 6130 static assert(!__traits(compiles, cdate.roll!"days"(12))); 6131 static assert(!__traits(compiles, idate.roll!"days"(12))); 6132 } 6133 6134 import core.time : Duration; 6135 /++ 6136 Gives the result of adding or subtracting a $(REF Duration, core,time) 6137 from 6138 6139 The legal types of arithmetic for $(LREF Date) using this operator are 6140 6141 $(BOOKTABLE, 6142 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 6143 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 6144 ) 6145 6146 Params: 6147 duration = The $(REF Duration, core,time) to add to or subtract from 6148 this $(LREF Date). 6149 +/ 6150 Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 6151 if (op == "+" || op == "-") 6152 { 6153 Date retval = this; 6154 immutable days = duration.total!"days"; 6155 mixin("return retval._addDays(" ~ op ~ "days);"); 6156 } 6157 6158 /// 6159 @safe unittest 6160 { 6161 import core.time : days; 6162 6163 assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); 6164 assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); 6165 6166 assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); 6167 assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); 6168 } 6169 6170 @safe unittest 6171 { 6172 auto date = Date(1999, 7, 6); 6173 6174 import core.time : dur; 6175 assert(date + dur!"weeks"(7) == Date(1999, 8, 24)); 6176 assert(date + dur!"weeks"(-7) == Date(1999, 5, 18)); 6177 assert(date + dur!"days"(7) == Date(1999, 7, 13)); 6178 assert(date + dur!"days"(-7) == Date(1999, 6, 29)); 6179 6180 assert(date + dur!"hours"(24) == Date(1999, 7, 7)); 6181 assert(date + dur!"hours"(-24) == Date(1999, 7, 5)); 6182 assert(date + dur!"minutes"(1440) == Date(1999, 7, 7)); 6183 assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6184 assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6185 assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6186 assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6187 assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6188 assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6189 assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6190 assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6191 assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6192 6193 assert(date - dur!"weeks"(-7) == Date(1999, 8, 24)); 6194 assert(date - dur!"weeks"(7) == Date(1999, 5, 18)); 6195 assert(date - dur!"days"(-7) == Date(1999, 7, 13)); 6196 assert(date - dur!"days"(7) == Date(1999, 6, 29)); 6197 6198 assert(date - dur!"hours"(-24) == Date(1999, 7, 7)); 6199 assert(date - dur!"hours"(24) == Date(1999, 7, 5)); 6200 assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6201 assert(date - dur!"minutes"(1440) == Date(1999, 7, 5)); 6202 assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6203 assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6204 assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6205 assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6206 assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6207 assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6208 assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6209 assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6210 6211 auto duration = dur!"days"(12); 6212 const cdate = Date(1999, 7, 6); 6213 immutable idate = Date(1999, 7, 6); 6214 assert(date + duration == Date(1999, 7, 18)); 6215 assert(cdate + duration == Date(1999, 7, 18)); 6216 assert(idate + duration == Date(1999, 7, 18)); 6217 6218 assert(date - duration == Date(1999, 6, 24)); 6219 assert(cdate - duration == Date(1999, 6, 24)); 6220 assert(idate - duration == Date(1999, 6, 24)); 6221 } 6222 6223 6224 /++ 6225 Gives the result of adding or subtracting a $(REF Duration, core,time) 6226 from this $(LREF Date), as well as assigning the result to this 6227 $(LREF Date). 6228 6229 The legal types of arithmetic for $(LREF Date) using this operator are 6230 6231 $(BOOKTABLE, 6232 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 6233 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 6234 ) 6235 6236 Params: 6237 duration = The $(REF Duration, core,time) to add to or subtract from 6238 this $(LREF Date). 6239 +/ 6240 ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 6241 if (op == "+" || op == "-") 6242 { 6243 immutable days = duration.total!"days"; 6244 mixin("return _addDays(" ~ op ~ "days);"); 6245 } 6246 6247 @safe unittest 6248 { 6249 import core.time : dur; 6250 assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24)); 6251 assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18)); 6252 assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13)); 6253 assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29)); 6254 6255 assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7)); 6256 assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5)); 6257 assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7)); 6258 assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6259 assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6260 assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6261 assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6262 assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6263 assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6264 assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6265 assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6266 assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6267 6268 assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24)); 6269 assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18)); 6270 assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13)); 6271 assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29)); 6272 6273 assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7)); 6274 assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5)); 6275 assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6276 assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5)); 6277 assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6278 assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6279 assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6280 assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6281 assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6282 assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6283 assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6284 assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6285 6286 { 6287 auto date = Date(0, 1, 31); 6288 (date += dur!"days"(507)) += dur!"days"(-2); 6289 assert(date == Date(1, 6, 19)); 6290 } 6291 6292 auto duration = dur!"days"(12); 6293 auto date = Date(1999, 7, 6); 6294 const cdate = Date(1999, 7, 6); 6295 immutable idate = Date(1999, 7, 6); 6296 date += duration; 6297 static assert(!__traits(compiles, cdate += duration)); 6298 static assert(!__traits(compiles, idate += duration)); 6299 6300 date -= duration; 6301 static assert(!__traits(compiles, cdate -= duration)); 6302 static assert(!__traits(compiles, idate -= duration)); 6303 } 6304 6305 6306 /++ 6307 Gives the difference between two $(LREF Date)s. 6308 6309 The legal types of arithmetic for $(LREF Date) using this operator are 6310 6311 $(BOOKTABLE, 6312 $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration)) 6313 ) 6314 +/ 6315 Duration opBinary(string op)(Date rhs) const @safe pure nothrow @nogc 6316 if (op == "-") 6317 { 6318 import core.time : dur; 6319 return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal); 6320 } 6321 6322 @safe unittest 6323 { 6324 auto date = Date(1999, 7, 6); 6325 6326 import core.time : dur; 6327 assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365)); 6328 assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365)); 6329 assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31)); 6330 assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31)); 6331 assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1)); 6332 assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1)); 6333 6334 const cdate = Date(1999, 7, 6); 6335 immutable idate = Date(1999, 7, 6); 6336 assert(date - date == Duration.zero); 6337 assert(cdate - date == Duration.zero); 6338 assert(idate - date == Duration.zero); 6339 6340 assert(date - cdate == Duration.zero); 6341 assert(cdate - cdate == Duration.zero); 6342 assert(idate - cdate == Duration.zero); 6343 6344 assert(date - idate == Duration.zero); 6345 assert(cdate - idate == Duration.zero); 6346 assert(idate - idate == Duration.zero); 6347 } 6348 6349 6350 /++ 6351 Returns the difference between the two $(LREF Date)s in months. 6352 6353 To get the difference in years, subtract the year property 6354 of two $(LREF Date)s. To get the difference in days or weeks, 6355 subtract the $(LREF Date)s themselves and use the 6356 $(REF Duration, core,time) that results. Because converting between 6357 months and smaller units requires a specific date (which 6358 $(REF Duration, core,time)s don't have), getting the difference in 6359 months requires some math using both the year and month properties, so 6360 this is a convenience function for getting the difference in months. 6361 6362 Note that the number of days in the months or how far into the month 6363 either $(LREF Date) is is irrelevant. It is the difference in the month 6364 property combined with the difference in years * 12. So, for instance, 6365 December 31st and January 1st are one month apart just as December 1st 6366 and January 31st are one month apart. 6367 6368 Params: 6369 rhs = The $(LREF Date) to subtract from this one. 6370 +/ 6371 int diffMonths(Date rhs) const @safe pure nothrow @nogc 6372 { 6373 immutable yearDiff = _year - rhs._year; 6374 immutable monthDiff = _month - rhs._month; 6375 6376 return yearDiff * 12 + monthDiff; 6377 } 6378 6379 /// 6380 @safe unittest 6381 { 6382 assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); 6383 assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); 6384 assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); 6385 assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); 6386 } 6387 6388 @safe unittest 6389 { 6390 auto date = Date(1999, 7, 6); 6391 6392 // Test A.D. 6393 assert(date.diffMonths(Date(1998, 6, 5)) == 13); 6394 assert(date.diffMonths(Date(1998, 7, 5)) == 12); 6395 assert(date.diffMonths(Date(1998, 8, 5)) == 11); 6396 assert(date.diffMonths(Date(1998, 9, 5)) == 10); 6397 assert(date.diffMonths(Date(1998, 10, 5)) == 9); 6398 assert(date.diffMonths(Date(1998, 11, 5)) == 8); 6399 assert(date.diffMonths(Date(1998, 12, 5)) == 7); 6400 assert(date.diffMonths(Date(1999, 1, 5)) == 6); 6401 assert(date.diffMonths(Date(1999, 2, 6)) == 5); 6402 assert(date.diffMonths(Date(1999, 3, 6)) == 4); 6403 assert(date.diffMonths(Date(1999, 4, 6)) == 3); 6404 assert(date.diffMonths(Date(1999, 5, 6)) == 2); 6405 assert(date.diffMonths(Date(1999, 6, 6)) == 1); 6406 assert(date.diffMonths(date) == 0); 6407 assert(date.diffMonths(Date(1999, 8, 6)) == -1); 6408 assert(date.diffMonths(Date(1999, 9, 6)) == -2); 6409 assert(date.diffMonths(Date(1999, 10, 6)) == -3); 6410 assert(date.diffMonths(Date(1999, 11, 6)) == -4); 6411 assert(date.diffMonths(Date(1999, 12, 6)) == -5); 6412 assert(date.diffMonths(Date(2000, 1, 6)) == -6); 6413 assert(date.diffMonths(Date(2000, 2, 6)) == -7); 6414 assert(date.diffMonths(Date(2000, 3, 6)) == -8); 6415 assert(date.diffMonths(Date(2000, 4, 6)) == -9); 6416 assert(date.diffMonths(Date(2000, 5, 6)) == -10); 6417 assert(date.diffMonths(Date(2000, 6, 6)) == -11); 6418 assert(date.diffMonths(Date(2000, 7, 6)) == -12); 6419 assert(date.diffMonths(Date(2000, 8, 6)) == -13); 6420 6421 assert(Date(1998, 6, 5).diffMonths(date) == -13); 6422 assert(Date(1998, 7, 5).diffMonths(date) == -12); 6423 assert(Date(1998, 8, 5).diffMonths(date) == -11); 6424 assert(Date(1998, 9, 5).diffMonths(date) == -10); 6425 assert(Date(1998, 10, 5).diffMonths(date) == -9); 6426 assert(Date(1998, 11, 5).diffMonths(date) == -8); 6427 assert(Date(1998, 12, 5).diffMonths(date) == -7); 6428 assert(Date(1999, 1, 5).diffMonths(date) == -6); 6429 assert(Date(1999, 2, 6).diffMonths(date) == -5); 6430 assert(Date(1999, 3, 6).diffMonths(date) == -4); 6431 assert(Date(1999, 4, 6).diffMonths(date) == -3); 6432 assert(Date(1999, 5, 6).diffMonths(date) == -2); 6433 assert(Date(1999, 6, 6).diffMonths(date) == -1); 6434 assert(Date(1999, 8, 6).diffMonths(date) == 1); 6435 assert(Date(1999, 9, 6).diffMonths(date) == 2); 6436 assert(Date(1999, 10, 6).diffMonths(date) == 3); 6437 assert(Date(1999, 11, 6).diffMonths(date) == 4); 6438 assert(Date(1999, 12, 6).diffMonths(date) == 5); 6439 assert(Date(2000, 1, 6).diffMonths(date) == 6); 6440 assert(Date(2000, 2, 6).diffMonths(date) == 7); 6441 assert(Date(2000, 3, 6).diffMonths(date) == 8); 6442 assert(Date(2000, 4, 6).diffMonths(date) == 9); 6443 assert(Date(2000, 5, 6).diffMonths(date) == 10); 6444 assert(Date(2000, 6, 6).diffMonths(date) == 11); 6445 assert(Date(2000, 7, 6).diffMonths(date) == 12); 6446 assert(Date(2000, 8, 6).diffMonths(date) == 13); 6447 6448 assert(date.diffMonths(Date(1999, 6, 30)) == 1); 6449 assert(date.diffMonths(Date(1999, 7, 1)) == 0); 6450 assert(date.diffMonths(Date(1999, 7, 6)) == 0); 6451 assert(date.diffMonths(Date(1999, 7, 11)) == 0); 6452 assert(date.diffMonths(Date(1999, 7, 16)) == 0); 6453 assert(date.diffMonths(Date(1999, 7, 21)) == 0); 6454 assert(date.diffMonths(Date(1999, 7, 26)) == 0); 6455 assert(date.diffMonths(Date(1999, 7, 31)) == 0); 6456 assert(date.diffMonths(Date(1999, 8, 1)) == -1); 6457 6458 assert(date.diffMonths(Date(1990, 6, 30)) == 109); 6459 assert(date.diffMonths(Date(1990, 7, 1)) == 108); 6460 assert(date.diffMonths(Date(1990, 7, 6)) == 108); 6461 assert(date.diffMonths(Date(1990, 7, 11)) == 108); 6462 assert(date.diffMonths(Date(1990, 7, 16)) == 108); 6463 assert(date.diffMonths(Date(1990, 7, 21)) == 108); 6464 assert(date.diffMonths(Date(1990, 7, 26)) == 108); 6465 assert(date.diffMonths(Date(1990, 7, 31)) == 108); 6466 assert(date.diffMonths(Date(1990, 8, 1)) == 107); 6467 6468 assert(Date(1999, 6, 30).diffMonths(date) == -1); 6469 assert(Date(1999, 7, 1).diffMonths(date) == 0); 6470 assert(Date(1999, 7, 6).diffMonths(date) == 0); 6471 assert(Date(1999, 7, 11).diffMonths(date) == 0); 6472 assert(Date(1999, 7, 16).diffMonths(date) == 0); 6473 assert(Date(1999, 7, 21).diffMonths(date) == 0); 6474 assert(Date(1999, 7, 26).diffMonths(date) == 0); 6475 assert(Date(1999, 7, 31).diffMonths(date) == 0); 6476 assert(Date(1999, 8, 1).diffMonths(date) == 1); 6477 6478 assert(Date(1990, 6, 30).diffMonths(date) == -109); 6479 assert(Date(1990, 7, 1).diffMonths(date) == -108); 6480 assert(Date(1990, 7, 6).diffMonths(date) == -108); 6481 assert(Date(1990, 7, 11).diffMonths(date) == -108); 6482 assert(Date(1990, 7, 16).diffMonths(date) == -108); 6483 assert(Date(1990, 7, 21).diffMonths(date) == -108); 6484 assert(Date(1990, 7, 26).diffMonths(date) == -108); 6485 assert(Date(1990, 7, 31).diffMonths(date) == -108); 6486 assert(Date(1990, 8, 1).diffMonths(date) == -107); 6487 6488 // Test B.C. 6489 auto dateBC = Date(-1999, 7, 6); 6490 6491 assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13); 6492 assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12); 6493 assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11); 6494 assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10); 6495 assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9); 6496 assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8); 6497 assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7); 6498 assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6); 6499 assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5); 6500 assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4); 6501 assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3); 6502 assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2); 6503 assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1); 6504 assert(dateBC.diffMonths(dateBC) == 0); 6505 assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1); 6506 assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2); 6507 assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3); 6508 assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4); 6509 assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5); 6510 assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6); 6511 assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7); 6512 assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8); 6513 assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9); 6514 assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10); 6515 assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11); 6516 assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12); 6517 assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13); 6518 6519 assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13); 6520 assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12); 6521 assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11); 6522 assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10); 6523 assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9); 6524 assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8); 6525 assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7); 6526 assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6); 6527 assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5); 6528 assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4); 6529 assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3); 6530 assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2); 6531 assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1); 6532 assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1); 6533 assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2); 6534 assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3); 6535 assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4); 6536 assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5); 6537 assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6); 6538 assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7); 6539 assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8); 6540 assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9); 6541 assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10); 6542 assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11); 6543 assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12); 6544 assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13); 6545 6546 assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1); 6547 assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0); 6548 assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0); 6549 assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0); 6550 assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0); 6551 assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0); 6552 assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0); 6553 assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0); 6554 assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1); 6555 6556 assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109); 6557 assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108); 6558 assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108); 6559 assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108); 6560 assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108); 6561 assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108); 6562 assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108); 6563 assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108); 6564 assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107); 6565 6566 assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1); 6567 assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0); 6568 assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0); 6569 assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0); 6570 assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0); 6571 assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0); 6572 assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0); 6573 assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0); 6574 assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1); 6575 6576 assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109); 6577 assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108); 6578 assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108); 6579 assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108); 6580 assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108); 6581 assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108); 6582 assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108); 6583 assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108); 6584 assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107); 6585 6586 // Test Both 6587 assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94); 6588 assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94); 6589 6590 const cdate = Date(1999, 7, 6); 6591 immutable idate = Date(1999, 7, 6); 6592 assert(date.diffMonths(date) == 0); 6593 assert(cdate.diffMonths(date) == 0); 6594 assert(idate.diffMonths(date) == 0); 6595 6596 assert(date.diffMonths(cdate) == 0); 6597 assert(cdate.diffMonths(cdate) == 0); 6598 assert(idate.diffMonths(cdate) == 0); 6599 6600 assert(date.diffMonths(idate) == 0); 6601 assert(cdate.diffMonths(idate) == 0); 6602 assert(idate.diffMonths(idate) == 0); 6603 } 6604 6605 6606 /++ 6607 Whether this $(LREF Date) is in a leap year. 6608 +/ 6609 @property bool isLeapYear() const @safe pure nothrow @nogc 6610 { 6611 return yearIsLeapYear(_year); 6612 } 6613 6614 @safe unittest 6615 { 6616 auto date = Date(1999, 7, 6); 6617 const cdate = Date(1999, 7, 6); 6618 immutable idate = Date(1999, 7, 6); 6619 static assert(!__traits(compiles, date.isLeapYear = true)); 6620 static assert(!__traits(compiles, cdate.isLeapYear = true)); 6621 static assert(!__traits(compiles, idate.isLeapYear = true)); 6622 } 6623 6624 6625 /++ 6626 Day of the week this $(LREF Date) is on. 6627 +/ 6628 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 6629 { 6630 return getDayOfWeek(dayOfGregorianCal); 6631 } 6632 6633 @safe unittest 6634 { 6635 const cdate = Date(1999, 7, 6); 6636 immutable idate = Date(1999, 7, 6); 6637 assert(cdate.dayOfWeek == DayOfWeek.tue); 6638 static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun)); 6639 assert(idate.dayOfWeek == DayOfWeek.tue); 6640 static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun)); 6641 } 6642 6643 6644 /++ 6645 Day of the year this $(LREF Date) is on. 6646 +/ 6647 @property ushort dayOfYear() const @safe pure nothrow @nogc 6648 { 6649 if (_month >= Month.jan && _month <= Month.dec) 6650 { 6651 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6652 auto monthIndex = _month - Month.jan; 6653 6654 return cast(ushort)(lastDay[monthIndex] + _day); 6655 } 6656 assert(0, "Invalid month."); 6657 } 6658 6659 /// 6660 @safe unittest 6661 { 6662 assert(Date(1999, 1, 1).dayOfYear == 1); 6663 assert(Date(1999, 12, 31).dayOfYear == 365); 6664 assert(Date(2000, 12, 31).dayOfYear == 366); 6665 } 6666 6667 @safe unittest 6668 { 6669 import std.algorithm.iteration : filter; 6670 import std.range : chain; 6671 6672 foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6673 { 6674 foreach (doy; testDaysOfYear) 6675 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6676 } 6677 6678 foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6679 { 6680 foreach (doy; testDaysOfLeapYear) 6681 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6682 } 6683 6684 const cdate = Date(1999, 7, 6); 6685 immutable idate = Date(1999, 7, 6); 6686 assert(cdate.dayOfYear == 187); 6687 assert(idate.dayOfYear == 187); 6688 } 6689 6690 /++ 6691 Day of the year. 6692 6693 Params: 6694 day = The day of the year to set which day of the year this 6695 $(LREF Date) is on. 6696 6697 Throws: 6698 $(REF DateTimeException,std,datetime,date) if the given day is an 6699 invalid day of the year. 6700 +/ 6701 @property void dayOfYear(int day) @safe pure 6702 { 6703 setDayOfYear!true(day); 6704 } 6705 6706 private void setDayOfYear(bool useExceptions = false)(int day) 6707 { 6708 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6709 6710 bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear); 6711 enum errorMsg = "Invalid day of the year."; 6712 6713 static if (useExceptions) 6714 { 6715 if (dayOutOfRange) throw new DateTimeException(errorMsg); 6716 } 6717 else 6718 { 6719 assert(!dayOutOfRange, errorMsg); 6720 } 6721 6722 foreach (i; 1 .. lastDay.length) 6723 { 6724 if (day <= lastDay[i]) 6725 { 6726 _month = cast(Month)(cast(int) Month.jan + i - 1); 6727 _day = cast(ubyte)(day - lastDay[i - 1]); 6728 return; 6729 } 6730 } 6731 assert(0, "Invalid day of the year."); 6732 } 6733 6734 @safe unittest 6735 { 6736 static void test(Date date, int day, MonthDay expected, size_t line = __LINE__) 6737 { 6738 date.dayOfYear = day; 6739 assert(date.month == expected.month); 6740 assert(date.day == expected.day); 6741 } 6742 6743 foreach (doy; testDaysOfYear) 6744 { 6745 test(Date(1999, 1, 1), doy.day, doy.md); 6746 test(Date(-1, 1, 1), doy.day, doy.md); 6747 } 6748 6749 foreach (doy; testDaysOfLeapYear) 6750 { 6751 test(Date(2000, 1, 1), doy.day, doy.md); 6752 test(Date(-4, 1, 1), doy.day, doy.md); 6753 } 6754 6755 const cdate = Date(1999, 7, 6); 6756 immutable idate = Date(1999, 7, 6); 6757 static assert(!__traits(compiles, cdate.dayOfYear = 187)); 6758 static assert(!__traits(compiles, idate.dayOfYear = 187)); 6759 } 6760 6761 6762 /++ 6763 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6764 +/ 6765 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 6766 { 6767 if (isAD) 6768 { 6769 if (_year == 1) 6770 return dayOfYear; 6771 6772 int years = _year - 1; 6773 auto days = (years / 400) * daysIn400Years; 6774 years %= 400; 6775 6776 days += (years / 100) * daysIn100Years; 6777 years %= 100; 6778 6779 days += (years / 4) * daysIn4Years; 6780 years %= 4; 6781 6782 days += years * daysInYear; 6783 6784 days += dayOfYear; 6785 6786 return days; 6787 } 6788 else if (_year == 0) 6789 return dayOfYear - daysInLeapYear; 6790 else 6791 { 6792 int years = _year; 6793 auto days = (years / 400) * daysIn400Years; 6794 years %= 400; 6795 6796 days += (years / 100) * daysIn100Years; 6797 years %= 100; 6798 6799 days += (years / 4) * daysIn4Years; 6800 years %= 4; 6801 6802 if (years < 0) 6803 { 6804 days -= daysInLeapYear; 6805 ++years; 6806 6807 days += years * daysInYear; 6808 6809 days -= daysInYear - dayOfYear; 6810 } 6811 else 6812 days -= daysInLeapYear - dayOfYear; 6813 6814 return days; 6815 } 6816 } 6817 6818 /// 6819 @safe unittest 6820 { 6821 assert(Date(1, 1, 1).dayOfGregorianCal == 1); 6822 assert(Date(1, 12, 31).dayOfGregorianCal == 365); 6823 assert(Date(2, 1, 1).dayOfGregorianCal == 366); 6824 6825 assert(Date(0, 12, 31).dayOfGregorianCal == 0); 6826 assert(Date(0, 1, 1).dayOfGregorianCal == -365); 6827 assert(Date(-1, 12, 31).dayOfGregorianCal == -366); 6828 6829 assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); 6830 assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); 6831 } 6832 6833 @safe unittest 6834 { 6835 import std.range : chain; 6836 6837 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 6838 assert(gd.date.dayOfGregorianCal == gd.day); 6839 6840 auto date = Date(1999, 7, 6); 6841 const cdate = Date(1999, 7, 6); 6842 immutable idate = Date(1999, 7, 6); 6843 assert(date.dayOfGregorianCal == 729_941); 6844 assert(cdate.dayOfGregorianCal == 729_941); 6845 assert(idate.dayOfGregorianCal == 729_941); 6846 } 6847 6848 /++ 6849 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6850 6851 Params: 6852 day = The day of the Gregorian Calendar to set this $(LREF Date) to. 6853 +/ 6854 @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc 6855 { 6856 this = Date(day); 6857 } 6858 6859 /// 6860 @safe unittest 6861 { 6862 auto date = Date.init; 6863 date.dayOfGregorianCal = 1; 6864 assert(date == Date(1, 1, 1)); 6865 6866 date.dayOfGregorianCal = 365; 6867 assert(date == Date(1, 12, 31)); 6868 6869 date.dayOfGregorianCal = 366; 6870 assert(date == Date(2, 1, 1)); 6871 6872 date.dayOfGregorianCal = 0; 6873 assert(date == Date(0, 12, 31)); 6874 6875 date.dayOfGregorianCal = -365; 6876 assert(date == Date(-0, 1, 1)); 6877 6878 date.dayOfGregorianCal = -366; 6879 assert(date == Date(-1, 12, 31)); 6880 6881 date.dayOfGregorianCal = 730_120; 6882 assert(date == Date(2000, 1, 1)); 6883 6884 date.dayOfGregorianCal = 734_137; 6885 assert(date == Date(2010, 12, 31)); 6886 } 6887 6888 @safe unittest 6889 { 6890 auto date = Date(1999, 7, 6); 6891 const cdate = Date(1999, 7, 6); 6892 immutable idate = Date(1999, 7, 6); 6893 date.dayOfGregorianCal = 187; 6894 assert(date.dayOfGregorianCal == 187); 6895 static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187)); 6896 static assert(!__traits(compiles, idate.dayOfGregorianCal = 187)); 6897 } 6898 6899 6900 /++ 6901 The ISO 8601 week and year of the year that this $(LREF Date) is in. 6902 6903 Returns: 6904 An anonymous struct with the members $(D isoWeekYear) for the 6905 resulting year and $(D isoWeek) for the resulting ISO week. 6906 6907 See_Also: 6908 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 6909 +/ 6910 @property auto isoWeekAndYear() const @safe pure nothrow 6911 { 6912 struct ISOWeekAndYear { short isoWeekYear; ubyte isoWeek; } 6913 6914 immutable weekday = dayOfWeek; 6915 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; 6916 immutable week = (dayOfYear - adjustedWeekday + 10) / 7; 6917 6918 try 6919 { 6920 if (week == 53) 6921 { 6922 switch (Date(_year + 1, 1, 1).dayOfWeek) 6923 { 6924 case DayOfWeek.mon: 6925 case DayOfWeek.tue: 6926 case DayOfWeek.wed: 6927 case DayOfWeek.thu: 6928 return ISOWeekAndYear(cast(short) (_year + 1), 1); 6929 case DayOfWeek.fri: 6930 case DayOfWeek.sat: 6931 case DayOfWeek.sun: 6932 return ISOWeekAndYear(_year, 53); 6933 default: 6934 assert(0, "Invalid ISO Week"); 6935 } 6936 } 6937 else if (week > 0) 6938 return ISOWeekAndYear(_year, cast(ubyte) week); 6939 else 6940 return Date(_year - 1, 12, 31).isoWeekAndYear; 6941 } 6942 catch (Exception e) 6943 assert(0, "Date's constructor threw."); 6944 } 6945 6946 /++ 6947 The ISO 8601 week of the year that this $(LREF Date) is in. 6948 6949 See_Also: 6950 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 6951 +/ 6952 @property ubyte isoWeek() const @safe pure nothrow 6953 { 6954 return isoWeekAndYear().isoWeek; 6955 } 6956 6957 @safe unittest 6958 { 6959 // Test A.D. 6960 assert(Date(2009, 12, 28).isoWeek == 53); 6961 assert(Date(2009, 12, 29).isoWeek == 53); 6962 assert(Date(2009, 12, 30).isoWeek == 53); 6963 assert(Date(2009, 12, 31).isoWeek == 53); 6964 assert(Date(2010, 1, 1).isoWeek == 53); 6965 assert(Date(2010, 1, 2).isoWeek == 53); 6966 assert(Date(2010, 1, 3).isoWeek == 53); 6967 assert(Date(2010, 1, 4).isoWeek == 1); 6968 assert(Date(2010, 1, 5).isoWeek == 1); 6969 assert(Date(2010, 1, 6).isoWeek == 1); 6970 assert(Date(2010, 1, 7).isoWeek == 1); 6971 assert(Date(2010, 1, 8).isoWeek == 1); 6972 assert(Date(2010, 1, 9).isoWeek == 1); 6973 assert(Date(2010, 1, 10).isoWeek == 1); 6974 assert(Date(2010, 1, 11).isoWeek == 2); 6975 assert(Date(2010, 12, 31).isoWeek == 52); 6976 6977 assert(Date(2004, 12, 26).isoWeek == 52); 6978 assert(Date(2004, 12, 27).isoWeek == 53); 6979 assert(Date(2004, 12, 28).isoWeek == 53); 6980 assert(Date(2004, 12, 29).isoWeek == 53); 6981 assert(Date(2004, 12, 30).isoWeek == 53); 6982 assert(Date(2004, 12, 31).isoWeek == 53); 6983 assert(Date(2005, 1, 1).isoWeek == 53); 6984 assert(Date(2005, 1, 2).isoWeek == 53); 6985 6986 assert(Date(2005, 12, 31).isoWeek == 52); 6987 assert(Date(2007, 1, 1).isoWeek == 1); 6988 6989 assert(Date(2007, 12, 30).isoWeek == 52); 6990 assert(Date(2007, 12, 31).isoWeek == 1); 6991 assert(Date(2008, 1, 1).isoWeek == 1); 6992 6993 assert(Date(2008, 12, 28).isoWeek == 52); 6994 assert(Date(2008, 12, 29).isoWeek == 1); 6995 assert(Date(2008, 12, 30).isoWeek == 1); 6996 assert(Date(2008, 12, 31).isoWeek == 1); 6997 assert(Date(2009, 1, 1).isoWeek == 1); 6998 assert(Date(2009, 1, 2).isoWeek == 1); 6999 assert(Date(2009, 1, 3).isoWeek == 1); 7000 assert(Date(2009, 1, 4).isoWeek == 1); 7001 7002 // Test B.C. 7003 // The algorithm should work identically for both A.D. and B.C. since 7004 // it doesn't really take the year into account, so B.C. testing 7005 // probably isn't really needed. 7006 assert(Date(0, 12, 31).isoWeek == 52); 7007 assert(Date(0, 1, 4).isoWeek == 1); 7008 assert(Date(0, 1, 1).isoWeek == 52); 7009 7010 const cdate = Date(1999, 7, 6); 7011 immutable idate = Date(1999, 7, 6); 7012 assert(cdate.isoWeek == 27); 7013 static assert(!__traits(compiles, cdate.isoWeek = 3)); 7014 assert(idate.isoWeek == 27); 7015 static assert(!__traits(compiles, idate.isoWeek = 3)); 7016 } 7017 7018 /++ 7019 The year inside the ISO 8601 week calendar that this $(LREF Date) is in. 7020 7021 May differ from $(LREF year) between 28 December and 4 January. 7022 7023 See_Also: 7024 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 7025 +/ 7026 @property short isoWeekYear() const @safe pure nothrow 7027 { 7028 return isoWeekAndYear().isoWeekYear; 7029 } 7030 7031 @safe unittest 7032 { 7033 // Test A.D. 7034 assert(Date(2009, 12, 28).isoWeekYear == 2009); 7035 assert(Date(2009, 12, 29).isoWeekYear == 2009); 7036 assert(Date(2009, 12, 30).isoWeekYear == 2009); 7037 assert(Date(2009, 12, 31).isoWeekYear == 2009); 7038 assert(Date(2010, 1, 1).isoWeekYear == 2009); 7039 assert(Date(2010, 1, 2).isoWeekYear == 2009); 7040 assert(Date(2010, 1, 3).isoWeekYear == 2009); 7041 assert(Date(2010, 1, 4).isoWeekYear == 2010); 7042 assert(Date(2010, 1, 5).isoWeekYear == 2010); 7043 assert(Date(2010, 1, 6).isoWeekYear == 2010); 7044 assert(Date(2010, 1, 7).isoWeekYear == 2010); 7045 assert(Date(2010, 1, 8).isoWeekYear == 2010); 7046 assert(Date(2010, 1, 9).isoWeekYear == 2010); 7047 assert(Date(2010, 1, 10).isoWeekYear == 2010); 7048 assert(Date(2010, 1, 11).isoWeekYear == 2010); 7049 assert(Date(2010, 12, 31).isoWeekYear == 2010); 7050 7051 assert(Date(2004, 12, 26).isoWeekYear == 2004); 7052 assert(Date(2004, 12, 27).isoWeekYear == 2004); 7053 assert(Date(2004, 12, 28).isoWeekYear == 2004); 7054 assert(Date(2004, 12, 29).isoWeekYear == 2004); 7055 assert(Date(2004, 12, 30).isoWeekYear == 2004); 7056 assert(Date(2004, 12, 31).isoWeekYear == 2004); 7057 assert(Date(2005, 1, 1).isoWeekYear == 2004); 7058 assert(Date(2005, 1, 2).isoWeekYear == 2004); 7059 assert(Date(2005, 1, 3).isoWeekYear == 2005); 7060 7061 assert(Date(2005, 12, 31).isoWeekYear == 2005); 7062 assert(Date(2007, 1, 1).isoWeekYear == 2007); 7063 7064 assert(Date(2007, 12, 30).isoWeekYear == 2007); 7065 assert(Date(2007, 12, 31).isoWeekYear == 2008); 7066 assert(Date(2008, 1, 1).isoWeekYear == 2008); 7067 7068 assert(Date(2008, 12, 28).isoWeekYear == 2008); 7069 assert(Date(2008, 12, 29).isoWeekYear == 2009); 7070 assert(Date(2008, 12, 30).isoWeekYear == 2009); 7071 assert(Date(2008, 12, 31).isoWeekYear == 2009); 7072 assert(Date(2009, 1, 1).isoWeekYear == 2009); 7073 assert(Date(2009, 1, 2).isoWeekYear == 2009); 7074 assert(Date(2009, 1, 3).isoWeekYear == 2009); 7075 assert(Date(2009, 1, 4).isoWeekYear == 2009); 7076 7077 // Test B.C. 7078 assert(Date(0, 12, 31).isoWeekYear == 0); 7079 assert(Date(0, 1, 4).isoWeekYear == 0); 7080 assert(Date(0, 1, 1).isoWeekYear == -1); 7081 7082 const cdate = Date(1999, 7, 6); 7083 immutable idate = Date(1999, 7, 6); 7084 assert(cdate.isoWeekYear == 1999); 7085 assert(idate.isoWeekYear == 1999); 7086 } 7087 7088 static Date fromISOWeek(short isoWeekYear, ubyte isoWeek, DayOfWeek weekday) @safe pure nothrow @nogc 7089 { 7090 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; 7091 immutable dayOffset = (isoWeek - 1) * 7 + adjustedWeekday; 7092 7093 Date date; 7094 date._year = isoWeekYear; 7095 date._month = Month.jan; 7096 date._day = 3; 7097 immutable startOfYear = date.dayOfWeek; 7098 return date._addDays(dayOffset - startOfYear); 7099 } 7100 7101 @safe unittest 7102 { 7103 // Test -30000 days to 30000 days for matching construction <-> deconstruction 7104 Date date = Date(1, 1, 1); 7105 date._addDays(-30_000); 7106 foreach (day; 0 .. 60_000) 7107 { 7108 const year = date.isoWeekYear; 7109 const dow = date.dayOfWeek; 7110 const isoWeek = date.isoWeek; 7111 const reversed = Date.fromISOWeek(year, isoWeek, dow); 7112 assert(reversed == date, date.toISOExtString ~ " != " ~ reversed.toISOExtString); 7113 date = date._addDays(1); 7114 } 7115 } 7116 7117 7118 /++ 7119 $(LREF Date) for the last day in the month that this $(LREF Date) is in. 7120 +/ 7121 @property Date endOfMonth() const @safe pure nothrow 7122 { 7123 try 7124 return Date(_year, _month, maxDay(_year, _month)); 7125 catch (Exception e) 7126 assert(0, "Date's constructor threw."); 7127 } 7128 7129 /// 7130 @safe unittest 7131 { 7132 assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); 7133 assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); 7134 assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); 7135 assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); 7136 } 7137 7138 @safe unittest 7139 { 7140 // Test A.D. 7141 assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31)); 7142 assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28)); 7143 assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29)); 7144 assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31)); 7145 assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30)); 7146 assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31)); 7147 assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30)); 7148 assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31)); 7149 assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31)); 7150 assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30)); 7151 assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31)); 7152 assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30)); 7153 assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31)); 7154 7155 // Test B.C. 7156 assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31)); 7157 assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28)); 7158 assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29)); 7159 assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31)); 7160 assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30)); 7161 assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31)); 7162 assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30)); 7163 assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31)); 7164 assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31)); 7165 assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30)); 7166 assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31)); 7167 assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30)); 7168 assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31)); 7169 7170 const cdate = Date(1999, 7, 6); 7171 immutable idate = Date(1999, 7, 6); 7172 static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30))); 7173 static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30))); 7174 } 7175 7176 7177 /++ 7178 The last day in the month that this $(LREF Date) is in. 7179 +/ 7180 @property ubyte daysInMonth() const @safe pure nothrow @nogc 7181 { 7182 return maxDay(_year, _month); 7183 } 7184 7185 /// 7186 @safe unittest 7187 { 7188 assert(Date(1999, 1, 6).daysInMonth == 31); 7189 assert(Date(1999, 2, 7).daysInMonth == 28); 7190 assert(Date(2000, 2, 7).daysInMonth == 29); 7191 assert(Date(2000, 6, 4).daysInMonth == 30); 7192 } 7193 7194 @safe unittest 7195 { 7196 // Test A.D. 7197 assert(Date(1999, 1, 1).daysInMonth == 31); 7198 assert(Date(1999, 2, 1).daysInMonth == 28); 7199 assert(Date(2000, 2, 1).daysInMonth == 29); 7200 assert(Date(1999, 3, 1).daysInMonth == 31); 7201 assert(Date(1999, 4, 1).daysInMonth == 30); 7202 assert(Date(1999, 5, 1).daysInMonth == 31); 7203 assert(Date(1999, 6, 1).daysInMonth == 30); 7204 assert(Date(1999, 7, 1).daysInMonth == 31); 7205 assert(Date(1999, 8, 1).daysInMonth == 31); 7206 assert(Date(1999, 9, 1).daysInMonth == 30); 7207 assert(Date(1999, 10, 1).daysInMonth == 31); 7208 assert(Date(1999, 11, 1).daysInMonth == 30); 7209 assert(Date(1999, 12, 1).daysInMonth == 31); 7210 7211 // Test B.C. 7212 assert(Date(-1999, 1, 1).daysInMonth == 31); 7213 assert(Date(-1999, 2, 1).daysInMonth == 28); 7214 assert(Date(-2000, 2, 1).daysInMonth == 29); 7215 assert(Date(-1999, 3, 1).daysInMonth == 31); 7216 assert(Date(-1999, 4, 1).daysInMonth == 30); 7217 assert(Date(-1999, 5, 1).daysInMonth == 31); 7218 assert(Date(-1999, 6, 1).daysInMonth == 30); 7219 assert(Date(-1999, 7, 1).daysInMonth == 31); 7220 assert(Date(-1999, 8, 1).daysInMonth == 31); 7221 assert(Date(-1999, 9, 1).daysInMonth == 30); 7222 assert(Date(-1999, 10, 1).daysInMonth == 31); 7223 assert(Date(-1999, 11, 1).daysInMonth == 30); 7224 assert(Date(-1999, 12, 1).daysInMonth == 31); 7225 7226 const cdate = Date(1999, 7, 6); 7227 immutable idate = Date(1999, 7, 6); 7228 static assert(!__traits(compiles, cdate.daysInMonth = 30)); 7229 static assert(!__traits(compiles, idate.daysInMonth = 30)); 7230 } 7231 7232 7233 /++ 7234 Whether the current year is a date in A.D. 7235 +/ 7236 @property bool isAD() const @safe pure nothrow @nogc 7237 { 7238 return _year > 0; 7239 } 7240 7241 /// 7242 @safe unittest 7243 { 7244 assert(Date(1, 1, 1).isAD); 7245 assert(Date(2010, 12, 31).isAD); 7246 assert(!Date(0, 12, 31).isAD); 7247 assert(!Date(-2010, 1, 1).isAD); 7248 } 7249 7250 @safe unittest 7251 { 7252 assert(Date(2010, 7, 4).isAD); 7253 assert(Date(1, 1, 1).isAD); 7254 assert(!Date(0, 1, 1).isAD); 7255 assert(!Date(-1, 1, 1).isAD); 7256 assert(!Date(-2010, 7, 4).isAD); 7257 7258 const cdate = Date(1999, 7, 6); 7259 immutable idate = Date(1999, 7, 6); 7260 assert(cdate.isAD); 7261 assert(idate.isAD); 7262 } 7263 7264 7265 /++ 7266 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 7267 $(LREF Date) at noon (since the Julian day changes at noon). 7268 +/ 7269 @property long julianDay() const @safe pure nothrow @nogc 7270 { 7271 return dayOfGregorianCal + 1_721_425; 7272 } 7273 7274 @safe unittest 7275 { 7276 assert(Date(-4713, 11, 24).julianDay == 0); 7277 assert(Date(0, 12, 31).julianDay == 1_721_425); 7278 assert(Date(1, 1, 1).julianDay == 1_721_426); 7279 assert(Date(1582, 10, 15).julianDay == 2_299_161); 7280 assert(Date(1858, 11, 17).julianDay == 2_400_001); 7281 assert(Date(1982, 1, 4).julianDay == 2_444_974); 7282 assert(Date(1996, 3, 31).julianDay == 2_450_174); 7283 assert(Date(2010, 8, 24).julianDay == 2_455_433); 7284 7285 const cdate = Date(1999, 7, 6); 7286 immutable idate = Date(1999, 7, 6); 7287 assert(cdate.julianDay == 2_451_366); 7288 assert(idate.julianDay == 2_451_366); 7289 } 7290 7291 7292 /++ 7293 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for 7294 any time on this date (since, the modified Julian day changes at 7295 midnight). 7296 +/ 7297 @property long modJulianDay() const @safe pure nothrow @nogc 7298 { 7299 return julianDay - 2_400_001; 7300 } 7301 7302 @safe unittest 7303 { 7304 assert(Date(1858, 11, 17).modJulianDay == 0); 7305 assert(Date(2010, 8, 24).modJulianDay == 55_432); 7306 7307 const cdate = Date(1999, 7, 6); 7308 immutable idate = Date(1999, 7, 6); 7309 assert(cdate.modJulianDay == 51_365); 7310 assert(idate.modJulianDay == 51_365); 7311 } 7312 7313 7314 /++ 7315 Converts this $(LREF Date) to a string with the format `YYYYMMDD`. 7316 If `writer` is set, the resulting string will be written directly 7317 to it. 7318 7319 Params: 7320 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7321 Returns: 7322 A `string` when not using an output range; `void` otherwise. 7323 +/ 7324 string toISOString() const @safe pure nothrow 7325 { 7326 import std.array : appender; 7327 auto w = appender!string(); 7328 w.reserve(8); 7329 try 7330 toISOString(w); 7331 catch (Exception e) 7332 assert(0, "toISOString() threw."); 7333 return w.data; 7334 } 7335 7336 /// 7337 @safe unittest 7338 { 7339 assert(Date(2010, 7, 4).toISOString() == "20100704"); 7340 assert(Date(1998, 12, 25).toISOString() == "19981225"); 7341 assert(Date(0, 1, 5).toISOString() == "00000105"); 7342 assert(Date(-4, 1, 5).toISOString() == "-00040105"); 7343 } 7344 7345 @safe unittest 7346 { 7347 // Test A.D. 7348 assert(Date(9, 12, 4).toISOString() == "00091204"); 7349 assert(Date(99, 12, 4).toISOString() == "00991204"); 7350 assert(Date(999, 12, 4).toISOString() == "09991204"); 7351 assert(Date(9999, 7, 4).toISOString() == "99990704"); 7352 assert(Date(10000, 10, 20).toISOString() == "+100001020"); 7353 7354 // Test B.C. 7355 assert(Date(0, 12, 4).toISOString() == "00001204"); 7356 assert(Date(-9, 12, 4).toISOString() == "-00091204"); 7357 assert(Date(-99, 12, 4).toISOString() == "-00991204"); 7358 assert(Date(-999, 12, 4).toISOString() == "-09991204"); 7359 assert(Date(-9999, 7, 4).toISOString() == "-99990704"); 7360 assert(Date(-10000, 10, 20).toISOString() == "-100001020"); 7361 7362 const cdate = Date(1999, 7, 6); 7363 immutable idate = Date(1999, 7, 6); 7364 assert(cdate.toISOString() == "19990706"); 7365 assert(idate.toISOString() == "19990706"); 7366 } 7367 7368 /// ditto 7369 void toISOString(W)(ref W writer) const 7370 if (isOutputRange!(W, char)) 7371 { 7372 import std.format.write : formattedWrite; 7373 if (_year >= 0) 7374 { 7375 if (_year < 10_000) 7376 formattedWrite(writer, "%04d%02d%02d", _year, _month, _day); 7377 else 7378 formattedWrite(writer, "+%05d%02d%02d", _year, _month, _day); 7379 } 7380 else if (_year > -10_000) 7381 formattedWrite(writer, "%05d%02d%02d", _year, _month, _day); 7382 else 7383 formattedWrite(writer, "%06d%02d%02d", _year, _month, _day); 7384 } 7385 7386 @safe pure unittest 7387 { 7388 import std.array : appender; 7389 7390 auto w = appender!(char[])(); 7391 Date(2010, 7, 4).toISOString(w); 7392 assert(w.data == "20100704"); 7393 w.clear(); 7394 Date(1998, 12, 25).toISOString(w); 7395 assert(w.data == "19981225"); 7396 } 7397 7398 /++ 7399 Converts this $(LREF Date) to a string with the format `YYYY-MM-DD`. 7400 If `writer` is set, the resulting string will be written directly 7401 to it. 7402 7403 Params: 7404 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7405 Returns: 7406 A `string` when not using an output range; `void` otherwise. 7407 +/ 7408 string toISOExtString() const @safe pure nothrow 7409 { 7410 import std.array : appender; 7411 auto w = appender!string(); 7412 w.reserve(10); 7413 try 7414 toISOExtString(w); 7415 catch (Exception e) 7416 assert(0, "toISOExtString() threw."); 7417 return w.data; 7418 } 7419 7420 /// 7421 @safe unittest 7422 { 7423 assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); 7424 assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); 7425 assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); 7426 assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); 7427 } 7428 7429 @safe unittest 7430 { 7431 // Test A.D. 7432 assert(Date(9, 12, 4).toISOExtString() == "0009-12-04"); 7433 assert(Date(99, 12, 4).toISOExtString() == "0099-12-04"); 7434 assert(Date(999, 12, 4).toISOExtString() == "0999-12-04"); 7435 assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04"); 7436 assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20"); 7437 7438 // Test B.C. 7439 assert(Date(0, 12, 4).toISOExtString() == "0000-12-04"); 7440 assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04"); 7441 assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04"); 7442 assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04"); 7443 assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04"); 7444 assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20"); 7445 7446 const cdate = Date(1999, 7, 6); 7447 immutable idate = Date(1999, 7, 6); 7448 assert(cdate.toISOExtString() == "1999-07-06"); 7449 assert(idate.toISOExtString() == "1999-07-06"); 7450 } 7451 7452 /// ditto 7453 void toISOExtString(W)(ref W writer) const 7454 if (isOutputRange!(W, char)) 7455 { 7456 import std.format.write : formattedWrite; 7457 if (_year >= 0) 7458 { 7459 if (_year < 10_000) 7460 formattedWrite(writer, "%04d-%02d-%02d", _year, _month, _day); 7461 else 7462 formattedWrite(writer, "+%05d-%02d-%02d", _year, _month, _day); 7463 } 7464 else if (_year > -10_000) 7465 formattedWrite(writer, "%05d-%02d-%02d", _year, _month, _day); 7466 else 7467 formattedWrite(writer, "%06d-%02d-%02d", _year, _month, _day); 7468 } 7469 7470 @safe pure unittest 7471 { 7472 import std.array : appender; 7473 7474 auto w = appender!(char[])(); 7475 Date(2010, 7, 4).toISOExtString(w); 7476 assert(w.data == "2010-07-04"); 7477 w.clear(); 7478 Date(-4, 1, 5).toISOExtString(w); 7479 assert(w.data == "-0004-01-05"); 7480 } 7481 7482 /++ 7483 Converts this $(LREF Date) to a string with the format `YYYY-Mon-DD`. 7484 If `writer` is set, the resulting string will be written directly 7485 to it. 7486 7487 Params: 7488 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 7489 Returns: 7490 A `string` when not using an output range; `void` otherwise. 7491 +/ 7492 string toSimpleString() const @safe pure nothrow 7493 { 7494 import std.array : appender; 7495 auto w = appender!string(); 7496 w.reserve(11); 7497 try 7498 toSimpleString(w); 7499 catch (Exception e) 7500 assert(0, "toSimpleString() threw."); 7501 return w.data; 7502 } 7503 7504 /// 7505 @safe unittest 7506 { 7507 assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); 7508 assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); 7509 assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); 7510 assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); 7511 } 7512 7513 @safe unittest 7514 { 7515 // Test A.D. 7516 assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04"); 7517 assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04"); 7518 assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04"); 7519 assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04"); 7520 assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20"); 7521 7522 // Test B.C. 7523 assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04"); 7524 assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04"); 7525 assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04"); 7526 assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04"); 7527 assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04"); 7528 assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20"); 7529 7530 const cdate = Date(1999, 7, 6); 7531 immutable idate = Date(1999, 7, 6); 7532 assert(cdate.toSimpleString() == "1999-Jul-06"); 7533 assert(idate.toSimpleString() == "1999-Jul-06"); 7534 } 7535 7536 /// ditto 7537 void toSimpleString(W)(ref W writer) const 7538 if (isOutputRange!(W, char)) 7539 { 7540 import std.format.write : formattedWrite; 7541 if (_year >= 0) 7542 { 7543 if (_year < 10_000) 7544 formattedWrite(writer, "%04d-%s-%02d", _year, monthToString(_month), _day); 7545 else 7546 formattedWrite(writer, "+%05d-%s-%02d", _year, monthToString(_month), _day); 7547 } 7548 else if (_year > -10_000) 7549 formattedWrite(writer, "%05d-%s-%02d", _year, monthToString(_month), _day); 7550 else 7551 formattedWrite(writer, "%06d-%s-%02d", _year, monthToString(_month), _day); 7552 } 7553 7554 @safe pure unittest 7555 { 7556 import std.array : appender; 7557 7558 auto w = appender!(char[])(); 7559 Date(9, 12, 4).toSimpleString(w); 7560 assert(w.data == "0009-Dec-04"); 7561 w.clear(); 7562 Date(-10000, 10, 20).toSimpleString(w); 7563 assert(w.data == "-10000-Oct-20"); 7564 } 7565 7566 /++ 7567 Converts this $(LREF Date) to a string. 7568 7569 This function exists to make it easy to convert a $(LREF Date) to a 7570 string for code that does not care what the exact format is - just that 7571 it presents the information in a clear manner. It also makes it easy to 7572 simply convert a $(LREF Date) to a string when using functions such as 7573 `to!string`, `format`, or `writeln` which use toString to convert 7574 user-defined types. So, it is unlikely that much code will call 7575 toString directly. 7576 7577 The format of the string is purposefully unspecified, and code that 7578 cares about the format of the string should use `toISOString`, 7579 `toISOExtString`, `toSimpleString`, or some other custom formatting 7580 function that explicitly generates the format that the code needs. The 7581 reason is that the code is then clear about what format it's using, 7582 making it less error-prone to maintain the code and interact with other 7583 software that consumes the generated strings. It's for this same reason 7584 $(LREF Date) has no `fromString` function, whereas it does have 7585 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 7586 7587 The format returned by toString may or may not change in the future. 7588 +/ 7589 string toString() const @safe pure nothrow 7590 { 7591 return toSimpleString(); 7592 } 7593 7594 @safe unittest 7595 { 7596 auto date = Date(1999, 7, 6); 7597 const cdate = Date(1999, 7, 6); 7598 immutable idate = Date(1999, 7, 6); 7599 assert(date.toString()); 7600 assert(cdate.toString()); 7601 assert(idate.toString()); 7602 } 7603 7604 /// ditto 7605 void toString(W)(ref W writer) const 7606 if (isOutputRange!(W, char)) 7607 { 7608 toSimpleString(writer); 7609 } 7610 7611 /++ 7612 Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace 7613 is stripped from the given string. 7614 7615 Params: 7616 isoString = A string formatted in the ISO format for dates. 7617 7618 Throws: 7619 $(REF DateTimeException,std,datetime,date) if the given string is 7620 not in the ISO format or if the resulting $(LREF Date) would not be 7621 valid. 7622 +/ 7623 static Date fromISOString(S)(scope const S isoString) @safe pure 7624 if (isSomeString!S) 7625 { 7626 import std.algorithm.searching : startsWith; 7627 import std.conv : to, text, ConvException; 7628 import std.exception : enforce; 7629 import std.string : strip; 7630 7631 auto str = isoString.strip; 7632 7633 enforce!DateTimeException(str.length >= 8, text("Invalid format for Date.fromISOString: ", isoString)); 7634 7635 int day, month, year; 7636 auto yearStr = str[0 .. $ - 4]; 7637 7638 try 7639 { 7640 // using conversion to uint plus cast because it checks for +/- 7641 // for us quickly while throwing ConvException 7642 day = cast(int) to!uint(str[$ - 2 .. $]); 7643 month = cast(int) to!uint(str[$ - 4 .. $ - 2]); 7644 7645 if (yearStr.length > 4) 7646 { 7647 enforce!DateTimeException(yearStr.startsWith('-', '+'), 7648 text("Invalid format for Date.fromISOString: ", isoString)); 7649 year = to!int(yearStr); 7650 } 7651 else 7652 { 7653 year = cast(int) to!uint(yearStr); 7654 } 7655 } 7656 catch (ConvException) 7657 { 7658 throw new DateTimeException(text("Invalid format for Date.fromISOString: ", isoString)); 7659 } 7660 7661 return Date(year, month, day); 7662 } 7663 7664 /// 7665 @safe unittest 7666 { 7667 assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); 7668 assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); 7669 assert(Date.fromISOString("00000105") == Date(0, 1, 5)); 7670 assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); 7671 assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); 7672 } 7673 7674 @safe unittest 7675 { 7676 assertThrown!DateTimeException(Date.fromISOString("")); 7677 assertThrown!DateTimeException(Date.fromISOString("990704")); 7678 assertThrown!DateTimeException(Date.fromISOString("0100704")); 7679 assertThrown!DateTimeException(Date.fromISOString("2010070")); 7680 assertThrown!DateTimeException(Date.fromISOString("2010070 ")); 7681 assertThrown!DateTimeException(Date.fromISOString("120100704")); 7682 assertThrown!DateTimeException(Date.fromISOString("-0100704")); 7683 assertThrown!DateTimeException(Date.fromISOString("+0100704")); 7684 assertThrown!DateTimeException(Date.fromISOString("2010070a")); 7685 assertThrown!DateTimeException(Date.fromISOString("20100a04")); 7686 assertThrown!DateTimeException(Date.fromISOString("2010a704")); 7687 7688 assertThrown!DateTimeException(Date.fromISOString("99-07-04")); 7689 assertThrown!DateTimeException(Date.fromISOString("010-07-04")); 7690 assertThrown!DateTimeException(Date.fromISOString("2010-07-0")); 7691 assertThrown!DateTimeException(Date.fromISOString("2010-07-0 ")); 7692 assertThrown!DateTimeException(Date.fromISOString("12010-07-04")); 7693 assertThrown!DateTimeException(Date.fromISOString("-010-07-04")); 7694 assertThrown!DateTimeException(Date.fromISOString("+010-07-04")); 7695 assertThrown!DateTimeException(Date.fromISOString("2010-07-0a")); 7696 assertThrown!DateTimeException(Date.fromISOString("2010-0a-04")); 7697 assertThrown!DateTimeException(Date.fromISOString("2010-a7-04")); 7698 assertThrown!DateTimeException(Date.fromISOString("2010/07/04")); 7699 assertThrown!DateTimeException(Date.fromISOString("2010/7/04")); 7700 assertThrown!DateTimeException(Date.fromISOString("2010/7/4")); 7701 assertThrown!DateTimeException(Date.fromISOString("2010/07/4")); 7702 assertThrown!DateTimeException(Date.fromISOString("2010-7-04")); 7703 assertThrown!DateTimeException(Date.fromISOString("2010-7-4")); 7704 assertThrown!DateTimeException(Date.fromISOString("2010-07-4")); 7705 7706 assertThrown!DateTimeException(Date.fromISOString("99Jul04")); 7707 assertThrown!DateTimeException(Date.fromISOString("010Jul04")); 7708 assertThrown!DateTimeException(Date.fromISOString("2010Jul0")); 7709 assertThrown!DateTimeException(Date.fromISOString("2010Jul0 ")); 7710 assertThrown!DateTimeException(Date.fromISOString("12010Jul04")); 7711 assertThrown!DateTimeException(Date.fromISOString("-010Jul04")); 7712 assertThrown!DateTimeException(Date.fromISOString("+010Jul04")); 7713 assertThrown!DateTimeException(Date.fromISOString("2010Jul0a")); 7714 assertThrown!DateTimeException(Date.fromISOString("2010Jua04")); 7715 assertThrown!DateTimeException(Date.fromISOString("2010aul04")); 7716 7717 assertThrown!DateTimeException(Date.fromISOString("99-Jul-04")); 7718 assertThrown!DateTimeException(Date.fromISOString("010-Jul-04")); 7719 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0")); 7720 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 ")); 7721 assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04")); 7722 assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04")); 7723 assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04")); 7724 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a")); 7725 assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04")); 7726 assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04")); 7727 assertThrown!DateTimeException(Date.fromISOString("2010-aul-04")); 7728 7729 assertThrown!DateTimeException(Date.fromISOString("2010-07-04")); 7730 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04")); 7731 7732 assert(Date.fromISOString("19990706") == Date(1999, 7, 6)); 7733 assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6)); 7734 assert(Date.fromISOString("+019990706") == Date(1999, 7, 6)); 7735 assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6)); 7736 assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6)); 7737 assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6)); 7738 } 7739 7740 // https://issues.dlang.org/show_bug.cgi?id=17801 7741 @safe unittest 7742 { 7743 import std.conv : to; 7744 import std.meta : AliasSeq; 7745 static foreach (C; AliasSeq!(char, wchar, dchar)) 7746 { 7747 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7748 assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21)); 7749 } 7750 } 7751 7752 7753 /++ 7754 Creates a $(LREF Date) from a string with the format YYYY-MM-DD. 7755 Whitespace is stripped from the given string. 7756 7757 Params: 7758 isoExtString = A string formatted in the ISO Extended format for 7759 dates. 7760 7761 Throws: 7762 $(REF DateTimeException,std,datetime,date) if the given string is 7763 not in the ISO Extended format or if the resulting $(LREF Date) 7764 would not be valid. 7765 +/ 7766 static Date fromISOExtString(S)(scope const S isoExtString) @safe pure 7767 if (isSomeString!(S)) 7768 { 7769 import std.algorithm.searching : startsWith; 7770 import std.conv : to, ConvException; 7771 import std.format : format; 7772 import std.string : strip; 7773 7774 auto str = strip(isoExtString); 7775 short year; 7776 ubyte month, day; 7777 7778 if (str.length < 10 || str[$-3] != '-' || str[$-6] != '-') 7779 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7780 7781 auto yearStr = str[0 .. $-6]; 7782 auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); 7783 if ((yearStr.length > 4) != signAtBegining) 7784 { 7785 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7786 } 7787 7788 try 7789 { 7790 day = to!ubyte(str[$-2 .. $]); 7791 month = to!ubyte(str[$-5 .. $-3]); 7792 year = to!short(yearStr); 7793 } 7794 catch (ConvException) 7795 { 7796 throw new DateTimeException(format("Invalid format for Date.fromISOExtString: %s", isoExtString)); 7797 } 7798 7799 return Date(year, month, day); 7800 } 7801 7802 /// 7803 @safe unittest 7804 { 7805 assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); 7806 assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); 7807 assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); 7808 assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); 7809 assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); 7810 } 7811 7812 @safe unittest 7813 { 7814 assertThrown!DateTimeException(Date.fromISOExtString("")); 7815 assertThrown!DateTimeException(Date.fromISOExtString("990704")); 7816 assertThrown!DateTimeException(Date.fromISOExtString("0100704")); 7817 assertThrown!DateTimeException(Date.fromISOExtString("2010070")); 7818 assertThrown!DateTimeException(Date.fromISOExtString("2010070 ")); 7819 assertThrown!DateTimeException(Date.fromISOExtString("120100704")); 7820 assertThrown!DateTimeException(Date.fromISOExtString("-0100704")); 7821 assertThrown!DateTimeException(Date.fromISOExtString("+0100704")); 7822 assertThrown!DateTimeException(Date.fromISOExtString("2010070a")); 7823 assertThrown!DateTimeException(Date.fromISOExtString("20100a04")); 7824 assertThrown!DateTimeException(Date.fromISOExtString("2010a704")); 7825 7826 assertThrown!DateTimeException(Date.fromISOExtString("99-07-04")); 7827 assertThrown!DateTimeException(Date.fromISOExtString("010-07-04")); 7828 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0")); 7829 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 ")); 7830 assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04")); 7831 assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04")); 7832 assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04")); 7833 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a")); 7834 assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04")); 7835 assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04")); 7836 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04")); 7837 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04")); 7838 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4")); 7839 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4")); 7840 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04")); 7841 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4")); 7842 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4")); 7843 7844 assertThrown!DateTimeException(Date.fromISOExtString("99Jul04")); 7845 assertThrown!DateTimeException(Date.fromISOExtString("010Jul04")); 7846 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0")); 7847 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 ")); 7848 assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04")); 7849 assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04")); 7850 assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04")); 7851 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a")); 7852 assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04")); 7853 assertThrown!DateTimeException(Date.fromISOExtString("2010aul04")); 7854 7855 assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04")); 7856 assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04")); 7857 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0")); 7858 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 ")); 7859 assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04")); 7860 assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04")); 7861 assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04")); 7862 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a")); 7863 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04")); 7864 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04")); 7865 assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04")); 7866 7867 assertThrown!DateTimeException(Date.fromISOExtString("20100704")); 7868 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04")); 7869 7870 assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6)); 7871 assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6)); 7872 assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6)); 7873 assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6)); 7874 assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6)); 7875 assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6)); 7876 } 7877 7878 // https://issues.dlang.org/show_bug.cgi?id=17801 7879 @safe unittest 7880 { 7881 import std.conv : to; 7882 import std.meta : AliasSeq; 7883 static foreach (C; AliasSeq!(char, wchar, dchar)) 7884 { 7885 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7886 assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21)); 7887 } 7888 } 7889 7890 7891 /++ 7892 Creates a $(LREF Date) from a string with the format YYYY-Mon-DD. 7893 Whitespace is stripped from the given string. 7894 7895 Params: 7896 simpleString = A string formatted in the way that toSimpleString 7897 formats dates. 7898 7899 Throws: 7900 $(REF DateTimeException,std,datetime,date) if the given string is 7901 not in the correct format or if the resulting $(LREF Date) would not 7902 be valid. 7903 +/ 7904 static Date fromSimpleString(S)(scope const S simpleString) @safe pure 7905 if (isSomeString!(S)) 7906 { 7907 import std.algorithm.searching : startsWith; 7908 import std.conv : to, ConvException; 7909 import std.format : format; 7910 import std.string : strip; 7911 7912 auto str = strip(simpleString); 7913 7914 if (str.length < 11 || str[$-3] != '-' || str[$-7] != '-') 7915 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7916 7917 int year; 7918 uint day; 7919 auto month = monthFromString(str[$ - 6 .. $ - 3]); 7920 auto yearStr = str[0 .. $ - 7]; 7921 auto signAtBegining = cast(bool) yearStr.startsWith('-', '+'); 7922 if ((yearStr.length > 4) != signAtBegining) 7923 { 7924 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7925 } 7926 7927 try 7928 { 7929 day = to!uint(str[$ - 2 .. $]); 7930 year = to!int(yearStr); 7931 } 7932 catch (ConvException) 7933 { 7934 throw new DateTimeException(format!"Invalid format for Date.fromSimpleString: %s"(simpleString)); 7935 } 7936 7937 return Date(year, month, day); 7938 } 7939 7940 /// 7941 @safe unittest 7942 { 7943 assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); 7944 assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); 7945 assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); 7946 assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); 7947 assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); 7948 } 7949 7950 @safe unittest 7951 { 7952 assertThrown!DateTimeException(Date.fromSimpleString("")); 7953 assertThrown!DateTimeException(Date.fromSimpleString("990704")); 7954 assertThrown!DateTimeException(Date.fromSimpleString("0100704")); 7955 assertThrown!DateTimeException(Date.fromSimpleString("2010070")); 7956 assertThrown!DateTimeException(Date.fromSimpleString("2010070 ")); 7957 assertThrown!DateTimeException(Date.fromSimpleString("120100704")); 7958 assertThrown!DateTimeException(Date.fromSimpleString("-0100704")); 7959 assertThrown!DateTimeException(Date.fromSimpleString("+0100704")); 7960 assertThrown!DateTimeException(Date.fromSimpleString("2010070a")); 7961 assertThrown!DateTimeException(Date.fromSimpleString("20100a04")); 7962 assertThrown!DateTimeException(Date.fromSimpleString("2010a704")); 7963 7964 assertThrown!DateTimeException(Date.fromSimpleString("99-07-04")); 7965 assertThrown!DateTimeException(Date.fromSimpleString("010-07-04")); 7966 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0")); 7967 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 ")); 7968 assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04")); 7969 assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04")); 7970 assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04")); 7971 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a")); 7972 assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04")); 7973 assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04")); 7974 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04")); 7975 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04")); 7976 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4")); 7977 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4")); 7978 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04")); 7979 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4")); 7980 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4")); 7981 7982 assertThrown!DateTimeException(Date.fromSimpleString("99Jul04")); 7983 assertThrown!DateTimeException(Date.fromSimpleString("010Jul04")); 7984 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0")); 7985 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 ")); 7986 assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04")); 7987 assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04")); 7988 assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04")); 7989 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a")); 7990 assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04")); 7991 assertThrown!DateTimeException(Date.fromSimpleString("2010aul04")); 7992 7993 assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04")); 7994 assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04")); 7995 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0")); 7996 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 ")); 7997 assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04")); 7998 assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04")); 7999 assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04")); 8000 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a")); 8001 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04")); 8002 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04")); 8003 assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04")); 8004 8005 assertThrown!DateTimeException(Date.fromSimpleString("20100704")); 8006 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04")); 8007 8008 assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6)); 8009 assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6)); 8010 assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6)); 8011 assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6)); 8012 assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6)); 8013 assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6)); 8014 } 8015 8016 // https://issues.dlang.org/show_bug.cgi?id=17801 8017 @safe unittest 8018 { 8019 import std.conv : to; 8020 import std.meta : AliasSeq; 8021 static foreach (C; AliasSeq!(char, wchar, dchar)) 8022 { 8023 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 8024 assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21)); 8025 } 8026 } 8027 8028 8029 /++ 8030 Returns the $(LREF Date) farthest in the past which is representable by 8031 $(LREF Date). 8032 +/ 8033 @property static Date min() @safe pure nothrow @nogc 8034 { 8035 auto date = Date.init; 8036 date._year = short.min; 8037 date._month = Month.jan; 8038 date._day = 1; 8039 8040 return date; 8041 } 8042 8043 @safe unittest 8044 { 8045 assert(Date.min.year < 0); 8046 assert(Date.min < Date.max); 8047 } 8048 8049 8050 /++ 8051 Returns the $(LREF Date) farthest in the future which is representable 8052 by $(LREF Date). 8053 +/ 8054 @property static Date max() @safe pure nothrow @nogc 8055 { 8056 auto date = Date.init; 8057 date._year = short.max; 8058 date._month = Month.dec; 8059 date._day = 31; 8060 8061 return date; 8062 } 8063 8064 @safe unittest 8065 { 8066 assert(Date.max.year > 0); 8067 assert(Date.max > Date.min); 8068 } 8069 8070 8071 private: 8072 8073 /+ 8074 Whether the given values form a valid date. 8075 8076 Params: 8077 year = The year to test. 8078 month = The month of the Gregorian Calendar to test. 8079 day = The day of the month to test. 8080 +/ 8081 static bool _valid(int year, int month, int day) @safe pure nothrow @nogc 8082 { 8083 if (!valid!"months"(month)) 8084 return false; 8085 return valid!"days"(year, month, day); 8086 } 8087 8088 8089 package: 8090 8091 /+ 8092 Adds the given number of days to this $(LREF Date). A negative number 8093 will subtract. 8094 8095 The month will be adjusted along with the day if the number of days 8096 added (or subtracted) would overflow (or underflow) the current month. 8097 The year will be adjusted along with the month if the increase (or 8098 decrease) to the month would cause it to overflow (or underflow) the 8099 current year. 8100 8101 `_addDays(numDays)` is effectively equivalent to 8102 $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days). 8103 8104 Params: 8105 days = The number of days to add to this Date. 8106 +/ 8107 ref Date _addDays(long days) return @safe pure nothrow @nogc 8108 { 8109 dayOfGregorianCal = cast(int)(dayOfGregorianCal + days); 8110 return this; 8111 } 8112 8113 @safe unittest 8114 { 8115 // Test A.D. 8116 { 8117 auto date = Date(1999, 2, 28); 8118 date._addDays(1); 8119 assert(date == Date(1999, 3, 1)); 8120 date._addDays(-1); 8121 assert(date == Date(1999, 2, 28)); 8122 } 8123 8124 { 8125 auto date = Date(2000, 2, 28); 8126 date._addDays(1); 8127 assert(date == Date(2000, 2, 29)); 8128 date._addDays(1); 8129 assert(date == Date(2000, 3, 1)); 8130 date._addDays(-1); 8131 assert(date == Date(2000, 2, 29)); 8132 } 8133 8134 { 8135 auto date = Date(1999, 6, 30); 8136 date._addDays(1); 8137 assert(date == Date(1999, 7, 1)); 8138 date._addDays(-1); 8139 assert(date == Date(1999, 6, 30)); 8140 } 8141 8142 { 8143 auto date = Date(1999, 7, 31); 8144 date._addDays(1); 8145 assert(date == Date(1999, 8, 1)); 8146 date._addDays(-1); 8147 assert(date == Date(1999, 7, 31)); 8148 } 8149 8150 { 8151 auto date = Date(1999, 1, 1); 8152 date._addDays(-1); 8153 assert(date == Date(1998, 12, 31)); 8154 date._addDays(1); 8155 assert(date == Date(1999, 1, 1)); 8156 } 8157 8158 { 8159 auto date = Date(1999, 7, 6); 8160 date._addDays(9); 8161 assert(date == Date(1999, 7, 15)); 8162 date._addDays(-11); 8163 assert(date == Date(1999, 7, 4)); 8164 date._addDays(30); 8165 assert(date == Date(1999, 8, 3)); 8166 date._addDays(-3); 8167 assert(date == Date(1999, 7, 31)); 8168 } 8169 8170 { 8171 auto date = Date(1999, 7, 6); 8172 date._addDays(365); 8173 assert(date == Date(2000, 7, 5)); 8174 date._addDays(-365); 8175 assert(date == Date(1999, 7, 6)); 8176 date._addDays(366); 8177 assert(date == Date(2000, 7, 6)); 8178 date._addDays(730); 8179 assert(date == Date(2002, 7, 6)); 8180 date._addDays(-1096); 8181 assert(date == Date(1999, 7, 6)); 8182 } 8183 8184 // Test B.C. 8185 { 8186 auto date = Date(-1999, 2, 28); 8187 date._addDays(1); 8188 assert(date == Date(-1999, 3, 1)); 8189 date._addDays(-1); 8190 assert(date == Date(-1999, 2, 28)); 8191 } 8192 8193 { 8194 auto date = Date(-2000, 2, 28); 8195 date._addDays(1); 8196 assert(date == Date(-2000, 2, 29)); 8197 date._addDays(1); 8198 assert(date == Date(-2000, 3, 1)); 8199 date._addDays(-1); 8200 assert(date == Date(-2000, 2, 29)); 8201 } 8202 8203 { 8204 auto date = Date(-1999, 6, 30); 8205 date._addDays(1); 8206 assert(date == Date(-1999, 7, 1)); 8207 date._addDays(-1); 8208 assert(date == Date(-1999, 6, 30)); 8209 } 8210 8211 { 8212 auto date = Date(-1999, 7, 31); 8213 date._addDays(1); 8214 assert(date == Date(-1999, 8, 1)); 8215 date._addDays(-1); 8216 assert(date == Date(-1999, 7, 31)); 8217 } 8218 8219 { 8220 auto date = Date(-1999, 1, 1); 8221 date._addDays(-1); 8222 assert(date == Date(-2000, 12, 31)); 8223 date._addDays(1); 8224 assert(date == Date(-1999, 1, 1)); 8225 } 8226 8227 { 8228 auto date = Date(-1999, 7, 6); 8229 date._addDays(9); 8230 assert(date == Date(-1999, 7, 15)); 8231 date._addDays(-11); 8232 assert(date == Date(-1999, 7, 4)); 8233 date._addDays(30); 8234 assert(date == Date(-1999, 8, 3)); 8235 date._addDays(-3); 8236 } 8237 8238 { 8239 auto date = Date(-1999, 7, 6); 8240 date._addDays(365); 8241 assert(date == Date(-1998, 7, 6)); 8242 date._addDays(-365); 8243 assert(date == Date(-1999, 7, 6)); 8244 date._addDays(366); 8245 assert(date == Date(-1998, 7, 7)); 8246 date._addDays(730); 8247 assert(date == Date(-1996, 7, 6)); 8248 date._addDays(-1096); 8249 assert(date == Date(-1999, 7, 6)); 8250 } 8251 8252 // Test Both 8253 { 8254 auto date = Date(1, 7, 6); 8255 date._addDays(-365); 8256 assert(date == Date(0, 7, 6)); 8257 date._addDays(365); 8258 assert(date == Date(1, 7, 6)); 8259 date._addDays(-731); 8260 assert(date == Date(-1, 7, 6)); 8261 date._addDays(730); 8262 assert(date == Date(1, 7, 5)); 8263 } 8264 8265 const cdate = Date(1999, 7, 6); 8266 immutable idate = Date(1999, 7, 6); 8267 static assert(!__traits(compiles, cdate._addDays(12))); 8268 static assert(!__traits(compiles, idate._addDays(12))); 8269 } 8270 8271 8272 @safe pure invariant() 8273 { 8274 import std.format : format; 8275 assert(valid!"months"(_month), 8276 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 8277 assert(valid!"days"(_year, _month, _day), 8278 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 8279 } 8280 8281 short _year = 1; 8282 Month _month = Month.jan; 8283 ubyte _day = 1; 8284 } 8285 8286 /// 8287 @safe pure unittest 8288 { 8289 import core.time : days; 8290 8291 auto d = Date(2000, 6, 1); 8292 8293 assert(d.dayOfYear == 153); 8294 assert(d.dayOfWeek == DayOfWeek.thu); 8295 8296 d += 10.days; 8297 assert(d == Date(2000, 6, 11)); 8298 8299 assert(d.toISOExtString() == "2000-06-11"); 8300 assert(d.toISOString() == "20000611"); 8301 assert(d.toSimpleString() == "2000-Jun-11"); 8302 8303 assert(Date.fromISOExtString("2018-01-01") == Date(2018, 1, 1)); 8304 assert(Date.fromISOString("20180101") == Date(2018, 1, 1)); 8305 assert(Date.fromSimpleString("2018-Jan-01") == Date(2018, 1, 1)); 8306 } 8307 8308 8309 /++ 8310 Represents a time of day with hours, minutes, and seconds. It uses 24 hour 8311 time. 8312 +/ 8313 struct TimeOfDay 8314 { 8315 public: 8316 8317 /++ 8318 Params: 8319 hour = Hour of the day [0 - 24$(RPAREN). 8320 minute = Minute of the hour [0 - 60$(RPAREN). 8321 second = Second of the minute [0 - 60$(RPAREN). 8322 8323 Throws: 8324 $(REF DateTimeException,std,datetime,date) if the resulting 8325 $(LREF TimeOfDay) would be not be valid. 8326 +/ 8327 this(int hour, int minute, int second = 0) @safe pure 8328 { 8329 enforceValid!"hours"(hour); 8330 enforceValid!"minutes"(minute); 8331 enforceValid!"seconds"(second); 8332 8333 _hour = cast(ubyte) hour; 8334 _minute = cast(ubyte) minute; 8335 _second = cast(ubyte) second; 8336 } 8337 8338 @safe unittest 8339 { 8340 assert(TimeOfDay(0, 0) == TimeOfDay.init); 8341 8342 { 8343 auto tod = TimeOfDay(0, 0); 8344 assert(tod._hour == 0); 8345 assert(tod._minute == 0); 8346 assert(tod._second == 0); 8347 } 8348 8349 { 8350 auto tod = TimeOfDay(12, 30, 33); 8351 assert(tod._hour == 12); 8352 assert(tod._minute == 30); 8353 assert(tod._second == 33); 8354 } 8355 8356 { 8357 auto tod = TimeOfDay(23, 59, 59); 8358 assert(tod._hour == 23); 8359 assert(tod._minute == 59); 8360 assert(tod._second == 59); 8361 } 8362 8363 assertThrown!DateTimeException(TimeOfDay(24, 0, 0)); 8364 assertThrown!DateTimeException(TimeOfDay(0, 60, 0)); 8365 assertThrown!DateTimeException(TimeOfDay(0, 0, 60)); 8366 } 8367 8368 8369 /++ 8370 Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay). 8371 8372 Returns: 8373 $(BOOKTABLE, 8374 $(TR $(TD this < rhs) $(TD < 0)) 8375 $(TR $(TD this == rhs) $(TD 0)) 8376 $(TR $(TD this > rhs) $(TD > 0)) 8377 ) 8378 +/ 8379 int opCmp(TimeOfDay rhs) const @safe pure nothrow @nogc 8380 { 8381 if (_hour < rhs._hour) 8382 return -1; 8383 if (_hour > rhs._hour) 8384 return 1; 8385 8386 if (_minute < rhs._minute) 8387 return -1; 8388 if (_minute > rhs._minute) 8389 return 1; 8390 8391 if (_second < rhs._second) 8392 return -1; 8393 if (_second > rhs._second) 8394 return 1; 8395 8396 return 0; 8397 } 8398 8399 @safe unittest 8400 { 8401 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0); 8402 8403 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0); 8404 assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0); 8405 assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0); 8406 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8407 8408 assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0); 8409 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0); 8410 8411 assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0); 8412 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8413 8414 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8415 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8416 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0); 8417 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8418 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0); 8419 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0); 8420 8421 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8422 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0); 8423 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0); 8424 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8425 8426 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8427 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0); 8428 8429 const ctod = TimeOfDay(12, 30, 33); 8430 immutable itod = TimeOfDay(12, 30, 33); 8431 assert(ctod.opCmp(itod) == 0); 8432 assert(itod.opCmp(ctod) == 0); 8433 } 8434 8435 8436 /++ 8437 Hours past midnight. 8438 +/ 8439 @property ubyte hour() const @safe pure nothrow @nogc 8440 { 8441 return _hour; 8442 } 8443 8444 @safe unittest 8445 { 8446 assert(TimeOfDay.init.hour == 0); 8447 assert(TimeOfDay(12, 0, 0).hour == 12); 8448 8449 const ctod = TimeOfDay(12, 0, 0); 8450 immutable itod = TimeOfDay(12, 0, 0); 8451 assert(ctod.hour == 12); 8452 assert(itod.hour == 12); 8453 } 8454 8455 8456 /++ 8457 Hours past midnight. 8458 8459 Params: 8460 hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to. 8461 8462 Throws: 8463 $(REF DateTimeException,std,datetime,date) if the given hour would 8464 result in an invalid $(LREF TimeOfDay). 8465 +/ 8466 @property void hour(int hour) @safe pure 8467 { 8468 enforceValid!"hours"(hour); 8469 _hour = cast(ubyte) hour; 8470 } 8471 8472 @safe unittest 8473 { 8474 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}()); 8475 8476 auto tod = TimeOfDay(0, 0, 0); 8477 tod.hour = 12; 8478 assert(tod == TimeOfDay(12, 0, 0)); 8479 8480 const ctod = TimeOfDay(0, 0, 0); 8481 immutable itod = TimeOfDay(0, 0, 0); 8482 static assert(!__traits(compiles, ctod.hour = 12)); 8483 static assert(!__traits(compiles, itod.hour = 12)); 8484 } 8485 8486 8487 /++ 8488 Minutes past the hour. 8489 +/ 8490 @property ubyte minute() const @safe pure nothrow @nogc 8491 { 8492 return _minute; 8493 } 8494 8495 @safe unittest 8496 { 8497 assert(TimeOfDay.init.minute == 0); 8498 assert(TimeOfDay(0, 30, 0).minute == 30); 8499 8500 const ctod = TimeOfDay(0, 30, 0); 8501 immutable itod = TimeOfDay(0, 30, 0); 8502 assert(ctod.minute == 30); 8503 assert(itod.minute == 30); 8504 } 8505 8506 8507 /++ 8508 Minutes past the hour. 8509 8510 Params: 8511 minute = The minute to set this $(LREF TimeOfDay)'s minute to. 8512 8513 Throws: 8514 $(REF DateTimeException,std,datetime,date) if the given minute 8515 would result in an invalid $(LREF TimeOfDay). 8516 +/ 8517 @property void minute(int minute) @safe pure 8518 { 8519 enforceValid!"minutes"(minute); 8520 _minute = cast(ubyte) minute; 8521 } 8522 8523 @safe unittest 8524 { 8525 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}()); 8526 8527 auto tod = TimeOfDay(0, 0, 0); 8528 tod.minute = 30; 8529 assert(tod == TimeOfDay(0, 30, 0)); 8530 8531 const ctod = TimeOfDay(0, 0, 0); 8532 immutable itod = TimeOfDay(0, 0, 0); 8533 static assert(!__traits(compiles, ctod.minute = 30)); 8534 static assert(!__traits(compiles, itod.minute = 30)); 8535 } 8536 8537 8538 /++ 8539 Seconds past the minute. 8540 +/ 8541 @property ubyte second() const @safe pure nothrow @nogc 8542 { 8543 return _second; 8544 } 8545 8546 @safe unittest 8547 { 8548 assert(TimeOfDay.init.second == 0); 8549 assert(TimeOfDay(0, 0, 33).second == 33); 8550 8551 const ctod = TimeOfDay(0, 0, 33); 8552 immutable itod = TimeOfDay(0, 0, 33); 8553 assert(ctod.second == 33); 8554 assert(itod.second == 33); 8555 } 8556 8557 8558 /++ 8559 Seconds past the minute. 8560 8561 Params: 8562 second = The second to set this $(LREF TimeOfDay)'s second to. 8563 8564 Throws: 8565 $(REF DateTimeException,std,datetime,date) if the given second 8566 would result in an invalid $(LREF TimeOfDay). 8567 +/ 8568 @property void second(int second) @safe pure 8569 { 8570 enforceValid!"seconds"(second); 8571 _second = cast(ubyte) second; 8572 } 8573 8574 @safe unittest 8575 { 8576 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}()); 8577 8578 auto tod = TimeOfDay(0, 0, 0); 8579 tod.second = 33; 8580 assert(tod == TimeOfDay(0, 0, 33)); 8581 8582 const ctod = TimeOfDay(0, 0, 0); 8583 immutable itod = TimeOfDay(0, 0, 0); 8584 static assert(!__traits(compiles, ctod.second = 33)); 8585 static assert(!__traits(compiles, itod.second = 33)); 8586 } 8587 8588 8589 /++ 8590 Adds the given number of units to this $(LREF TimeOfDay), mutating it. A 8591 negative number will subtract. 8592 8593 The difference between rolling and adding is that rolling does not 8594 affect larger units. For instance, rolling a $(LREF TimeOfDay) 8595 one hours's worth of minutes gets the exact same 8596 $(LREF TimeOfDay). 8597 8598 Accepted units are `"hours"`, `"minutes"`, and `"seconds"`. 8599 8600 Params: 8601 units = The units to add. 8602 value = The number of $(D_PARAM units) to add to this 8603 $(LREF TimeOfDay). 8604 8605 Returns: 8606 A reference to the `TimeOfDay` (`this`). 8607 +/ 8608 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8609 if (units == "hours") 8610 { 8611 import core.time : dur; 8612 return this += dur!"hours"(value); 8613 } 8614 8615 /// 8616 @safe unittest 8617 { 8618 auto tod1 = TimeOfDay(7, 12, 0); 8619 tod1.roll!"hours"(1); 8620 assert(tod1 == TimeOfDay(8, 12, 0)); 8621 8622 auto tod2 = TimeOfDay(7, 12, 0); 8623 tod2.roll!"hours"(-1); 8624 assert(tod2 == TimeOfDay(6, 12, 0)); 8625 8626 auto tod3 = TimeOfDay(23, 59, 0); 8627 tod3.roll!"minutes"(1); 8628 assert(tod3 == TimeOfDay(23, 0, 0)); 8629 8630 auto tod4 = TimeOfDay(0, 0, 0); 8631 tod4.roll!"minutes"(-1); 8632 assert(tod4 == TimeOfDay(0, 59, 0)); 8633 8634 auto tod5 = TimeOfDay(23, 59, 59); 8635 tod5.roll!"seconds"(1); 8636 assert(tod5 == TimeOfDay(23, 59, 0)); 8637 8638 auto tod6 = TimeOfDay(0, 0, 0); 8639 tod6.roll!"seconds"(-1); 8640 assert(tod6 == TimeOfDay(0, 0, 59)); 8641 } 8642 8643 @safe unittest 8644 { 8645 auto tod = TimeOfDay(12, 27, 2); 8646 tod.roll!"hours"(22).roll!"hours"(-7); 8647 assert(tod == TimeOfDay(3, 27, 2)); 8648 8649 const ctod = TimeOfDay(0, 0, 0); 8650 immutable itod = TimeOfDay(0, 0, 0); 8651 static assert(!__traits(compiles, ctod.roll!"hours"(53))); 8652 static assert(!__traits(compiles, itod.roll!"hours"(53))); 8653 } 8654 8655 8656 /// ditto 8657 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8658 if (units == "minutes" || units == "seconds") 8659 { 8660 import std.format : format; 8661 8662 enum memberVarStr = units[0 .. $ - 1]; 8663 value %= 60; 8664 mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr)); 8665 8666 if (value < 0) 8667 { 8668 if (newVal < 0) 8669 newVal += 60; 8670 } 8671 else if (newVal >= 60) 8672 newVal -= 60; 8673 8674 mixin(format("_%s = cast(ubyte) newVal;", memberVarStr)); 8675 return this; 8676 } 8677 8678 // Test roll!"minutes"(). 8679 @safe unittest 8680 { 8681 static void testTOD(TimeOfDay orig, int minutes, TimeOfDay expected, size_t line = __LINE__) 8682 { 8683 orig.roll!"minutes"(minutes); 8684 assert(orig == expected); 8685 } 8686 8687 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8688 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33)); 8689 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33)); 8690 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33)); 8691 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33)); 8692 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33)); 8693 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33)); 8694 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33)); 8695 testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33)); 8696 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33)); 8697 testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33)); 8698 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8699 testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33)); 8700 testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33)); 8701 testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33)); 8702 8703 testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33)); 8704 testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33)); 8705 testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33)); 8706 testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33)); 8707 testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33)); 8708 testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33)); 8709 testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33)); 8710 testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33)); 8711 8712 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33)); 8713 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33)); 8714 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33)); 8715 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33)); 8716 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33)); 8717 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33)); 8718 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33)); 8719 testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33)); 8720 testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33)); 8721 testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33)); 8722 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8723 testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33)); 8724 testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33)); 8725 testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33)); 8726 8727 testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33)); 8728 testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33)); 8729 testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33)); 8730 testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33)); 8731 testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33)); 8732 testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33)); 8733 testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33)); 8734 testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33)); 8735 8736 testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33)); 8737 testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33)); 8738 testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33)); 8739 8740 testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33)); 8741 testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33)); 8742 testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33)); 8743 8744 testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33)); 8745 testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33)); 8746 testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33)); 8747 8748 testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33)); 8749 testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33)); 8750 testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33)); 8751 8752 auto tod = TimeOfDay(12, 27, 2); 8753 tod.roll!"minutes"(97).roll!"minutes"(-102); 8754 assert(tod == TimeOfDay(12, 22, 2)); 8755 8756 const ctod = TimeOfDay(0, 0, 0); 8757 immutable itod = TimeOfDay(0, 0, 0); 8758 static assert(!__traits(compiles, ctod.roll!"minutes"(7))); 8759 static assert(!__traits(compiles, itod.roll!"minutes"(7))); 8760 } 8761 8762 // Test roll!"seconds"(). 8763 @safe unittest 8764 { 8765 static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) 8766 { 8767 orig.roll!"seconds"(seconds); 8768 assert(orig == expected); 8769 } 8770 8771 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8772 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 8773 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 8774 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 8775 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 8776 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 8777 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 8778 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 8779 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 8780 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0)); 8781 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3)); 8782 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32)); 8783 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8784 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34)); 8785 8786 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59)); 8787 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0)); 8788 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1)); 8789 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0)); 8790 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32)); 8791 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33)); 8792 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34)); 8793 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33)); 8794 8795 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 8796 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 8797 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 8798 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 8799 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 8800 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 8801 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 8802 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 8803 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59)); 8804 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58)); 8805 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34)); 8806 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8807 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32)); 8808 8809 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 8810 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 8811 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59)); 8812 8813 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 8814 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 8815 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59)); 8816 8817 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 8818 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 8819 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59)); 8820 8821 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0)); 8822 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 8823 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 8824 8825 auto tod = TimeOfDay(12, 27, 2); 8826 tod.roll!"seconds"(105).roll!"seconds"(-77); 8827 assert(tod == TimeOfDay(12, 27, 30)); 8828 8829 const ctod = TimeOfDay(0, 0, 0); 8830 immutable itod = TimeOfDay(0, 0, 0); 8831 static assert(!__traits(compiles, ctod.roll!"seconds"(7))); 8832 static assert(!__traits(compiles, itod.roll!"seconds"(7))); 8833 } 8834 8835 8836 import core.time : Duration; 8837 /++ 8838 Gives the result of adding or subtracting a $(REF Duration, core,time) 8839 from this $(LREF TimeOfDay). 8840 8841 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8842 are 8843 8844 $(BOOKTABLE, 8845 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8846 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8847 ) 8848 8849 Params: 8850 duration = The $(REF Duration, core,time) to add to or subtract from 8851 this $(LREF TimeOfDay). 8852 +/ 8853 TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 8854 if (op == "+" || op == "-") 8855 { 8856 TimeOfDay retval = this; 8857 immutable seconds = duration.total!"seconds"; 8858 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 8859 } 8860 8861 /// 8862 @safe unittest 8863 { 8864 import core.time : hours, minutes, seconds; 8865 8866 assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); 8867 assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); 8868 assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); 8869 assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); 8870 8871 assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); 8872 assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); 8873 assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); 8874 assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); 8875 } 8876 8877 @safe unittest 8878 { 8879 auto tod = TimeOfDay(12, 30, 33); 8880 8881 import core.time : dur; 8882 assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8883 assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8884 assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8885 assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8886 assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8887 assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8888 8889 assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8890 assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8891 assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8892 assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8893 assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8894 assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8895 8896 assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 8897 assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 8898 assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 8899 assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 8900 assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 8901 assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 8902 8903 assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 8904 assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 8905 assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 8906 assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 8907 assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 8908 assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 8909 8910 auto duration = dur!"hours"(11); 8911 const ctod = TimeOfDay(12, 30, 33); 8912 immutable itod = TimeOfDay(12, 30, 33); 8913 assert(tod + duration == TimeOfDay(23, 30, 33)); 8914 assert(ctod + duration == TimeOfDay(23, 30, 33)); 8915 assert(itod + duration == TimeOfDay(23, 30, 33)); 8916 8917 assert(tod - duration == TimeOfDay(1, 30, 33)); 8918 assert(ctod - duration == TimeOfDay(1, 30, 33)); 8919 assert(itod - duration == TimeOfDay(1, 30, 33)); 8920 } 8921 8922 8923 /++ 8924 Gives the result of adding or subtracting a $(REF Duration, core,time) 8925 from this $(LREF TimeOfDay), as well as assigning the result to this 8926 $(LREF TimeOfDay). 8927 8928 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8929 are 8930 8931 $(BOOKTABLE, 8932 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8933 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8934 ) 8935 8936 Params: 8937 duration = The $(REF Duration, core,time) to add to or subtract from 8938 this $(LREF TimeOfDay). 8939 +/ 8940 ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 8941 if (op == "+" || op == "-") 8942 { 8943 immutable seconds = duration.total!"seconds"; 8944 mixin("return _addSeconds(" ~ op ~ "seconds);"); 8945 } 8946 8947 @safe unittest 8948 { 8949 import core.time : dur; 8950 auto duration = dur!"hours"(12); 8951 8952 assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8953 assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8954 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8955 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8956 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8957 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8958 8959 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8960 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8961 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8962 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8963 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8964 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8965 8966 assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 8967 assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 8968 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 8969 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 8970 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 8971 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 8972 8973 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 8974 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 8975 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 8976 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 8977 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 8978 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 8979 8980 auto tod = TimeOfDay(19, 17, 22); 8981 (tod += dur!"seconds"(9)) += dur!"seconds"(-7292); 8982 assert(tod == TimeOfDay(17, 15, 59)); 8983 8984 const ctod = TimeOfDay(12, 33, 30); 8985 immutable itod = TimeOfDay(12, 33, 30); 8986 static assert(!__traits(compiles, ctod += duration)); 8987 static assert(!__traits(compiles, itod += duration)); 8988 static assert(!__traits(compiles, ctod -= duration)); 8989 static assert(!__traits(compiles, itod -= duration)); 8990 } 8991 8992 8993 /++ 8994 Gives the difference between two $(LREF TimeOfDay)s. 8995 8996 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8997 are 8998 8999 $(BOOKTABLE, 9000 $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration)) 9001 ) 9002 9003 Params: 9004 rhs = The $(LREF TimeOfDay) to subtract from this one. 9005 +/ 9006 Duration opBinary(string op)(TimeOfDay rhs) const @safe pure nothrow @nogc 9007 if (op == "-") 9008 { 9009 immutable lhsSec = _hour * 3600 + _minute * 60 + _second; 9010 immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second; 9011 9012 import core.time : dur; 9013 return dur!"seconds"(lhsSec - rhsSec); 9014 } 9015 9016 @safe unittest 9017 { 9018 auto tod = TimeOfDay(12, 30, 33); 9019 9020 import core.time : dur; 9021 assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061)); 9022 assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061)); 9023 assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200)); 9024 assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200)); 9025 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240)); 9026 assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240)); 9027 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1)); 9028 assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1)); 9029 9030 const ctod = TimeOfDay(12, 30, 33); 9031 immutable itod = TimeOfDay(12, 30, 33); 9032 assert(tod - tod == Duration.zero); 9033 assert(ctod - tod == Duration.zero); 9034 assert(itod - tod == Duration.zero); 9035 9036 assert(tod - ctod == Duration.zero); 9037 assert(ctod - ctod == Duration.zero); 9038 assert(itod - ctod == Duration.zero); 9039 9040 assert(tod - itod == Duration.zero); 9041 assert(ctod - itod == Duration.zero); 9042 assert(itod - itod == Duration.zero); 9043 } 9044 9045 9046 /++ 9047 Converts this $(LREF TimeOfDay) to a string with the format `HHMMSS`. 9048 If `writer` is set, the resulting string will be written directly to it. 9049 9050 Params: 9051 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9052 Returns: 9053 A `string` when not using an output range; `void` otherwise. 9054 +/ 9055 string toISOString() const @safe pure nothrow 9056 { 9057 import std.array : appender; 9058 auto w = appender!string(); 9059 w.reserve(6); 9060 try 9061 toISOString(w); 9062 catch (Exception e) 9063 assert(0, "toISOString() threw."); 9064 return w.data; 9065 } 9066 9067 /// ditto 9068 void toISOString(W)(ref W writer) const 9069 if (isOutputRange!(W, char)) 9070 { 9071 import std.format.write : formattedWrite; 9072 formattedWrite(writer, "%02d%02d%02d", _hour, _minute, _second); 9073 } 9074 9075 /// 9076 @safe unittest 9077 { 9078 assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); 9079 assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); 9080 } 9081 9082 @safe unittest 9083 { 9084 auto tod = TimeOfDay(12, 30, 33); 9085 const ctod = TimeOfDay(12, 30, 33); 9086 immutable itod = TimeOfDay(12, 30, 33); 9087 assert(tod.toISOString() == "123033"); 9088 assert(ctod.toISOString() == "123033"); 9089 assert(itod.toISOString() == "123033"); 9090 } 9091 9092 9093 /++ 9094 Converts this $(LREF TimeOfDay) to a string with the format `HH:MM:SS`. 9095 If `writer` is set, the resulting string will be written directly to it. 9096 9097 Params: 9098 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9099 Returns: 9100 A `string` when not using an output range; `void` otherwise. 9101 +/ 9102 string toISOExtString() const @safe pure nothrow 9103 { 9104 import std.array : appender; 9105 auto w = appender!string(); 9106 w.reserve(8); 9107 try 9108 toISOExtString(w); 9109 catch (Exception e) 9110 assert(0, "toISOExtString() threw."); 9111 return w.data; 9112 } 9113 9114 /// ditto 9115 void toISOExtString(W)(ref W writer) const 9116 if (isOutputRange!(W, char)) 9117 { 9118 import std.format.write : formattedWrite; 9119 formattedWrite(writer, "%02d:%02d:%02d", _hour, _minute, _second); 9120 } 9121 9122 /// 9123 @safe unittest 9124 { 9125 assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); 9126 assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); 9127 } 9128 9129 @safe unittest 9130 { 9131 auto tod = TimeOfDay(12, 30, 33); 9132 const ctod = TimeOfDay(12, 30, 33); 9133 immutable itod = TimeOfDay(12, 30, 33); 9134 assert(tod.toISOExtString() == "12:30:33"); 9135 assert(ctod.toISOExtString() == "12:30:33"); 9136 assert(itod.toISOExtString() == "12:30:33"); 9137 } 9138 9139 9140 /++ 9141 Converts this TimeOfDay to a string. 9142 9143 This function exists to make it easy to convert a $(LREF TimeOfDay) to a 9144 string for code that does not care what the exact format is - just that 9145 it presents the information in a clear manner. It also makes it easy to 9146 simply convert a $(LREF TimeOfDay) to a string when using functions such 9147 as `to!string`, `format`, or `writeln` which use toString to convert 9148 user-defined types. So, it is unlikely that much code will call 9149 toString directly. 9150 9151 The format of the string is purposefully unspecified, and code that 9152 cares about the format of the string should use `toISOString`, 9153 `toISOExtString`, or some other custom formatting function that 9154 explicitly generates the format that the code needs. The reason is that 9155 the code is then clear about what format it's using, making it less 9156 error-prone to maintain the code and interact with other software that 9157 consumes the generated strings. It's for this same reason that 9158 $(LREF TimeOfDay) has no `fromString` function, whereas it does have 9159 `fromISOString` and `fromISOExtString`. 9160 9161 The format returned by toString may or may not change in the future. 9162 9163 Params: 9164 writer = A `char` accepting $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 9165 Returns: 9166 A `string` when not using an output range; `void` otherwise. 9167 +/ 9168 string toString() const @safe pure nothrow 9169 { 9170 return toISOExtString(); 9171 } 9172 9173 /// ditto 9174 void toString(W)(ref W writer) const 9175 if (isOutputRange!(W, char)) 9176 { 9177 toISOExtString(writer); 9178 } 9179 9180 @safe unittest 9181 { 9182 auto tod = TimeOfDay(12, 30, 33); 9183 const ctod = TimeOfDay(12, 30, 33); 9184 immutable itod = TimeOfDay(12, 30, 33); 9185 assert(tod.toString()); 9186 assert(ctod.toString()); 9187 assert(itod.toString()); 9188 } 9189 9190 9191 /++ 9192 Creates a $(LREF TimeOfDay) from a string with the format HHMMSS. 9193 Whitespace is stripped from the given string. 9194 9195 Params: 9196 isoString = A string formatted in the ISO format for times. 9197 9198 Throws: 9199 $(REF DateTimeException,std,datetime,date) if the given string is 9200 not in the ISO format or if the resulting $(LREF TimeOfDay) would 9201 not be valid. 9202 +/ 9203 static TimeOfDay fromISOString(S)(scope const S isoString) @safe pure 9204 if (isSomeString!S) 9205 { 9206 import std.conv : to, text, ConvException; 9207 import std.exception : enforce; 9208 import std.string : strip; 9209 9210 int hours, minutes, seconds; 9211 auto str = strip(isoString); 9212 9213 enforce!DateTimeException(str.length == 6, text("Invalid format for TimeOfDay.fromISOString: ", isoString)); 9214 9215 try 9216 { 9217 // cast to int from uint is used because it checks for 9218 // non digits without extra loops 9219 hours = cast(int) to!uint(str[0 .. 2]); 9220 minutes = cast(int) to!uint(str[2 .. 4]); 9221 seconds = cast(int) to!uint(str[4 .. $]); 9222 } 9223 catch (ConvException) 9224 { 9225 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOString: ", isoString)); 9226 } 9227 9228 return TimeOfDay(hours, minutes, seconds); 9229 } 9230 9231 /// 9232 @safe unittest 9233 { 9234 assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); 9235 assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); 9236 assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); 9237 } 9238 9239 @safe unittest 9240 { 9241 assertThrown!DateTimeException(TimeOfDay.fromISOString("")); 9242 assertThrown!DateTimeException(TimeOfDay.fromISOString("0")); 9243 assertThrown!DateTimeException(TimeOfDay.fromISOString("00")); 9244 assertThrown!DateTimeException(TimeOfDay.fromISOString("000")); 9245 assertThrown!DateTimeException(TimeOfDay.fromISOString("0000")); 9246 assertThrown!DateTimeException(TimeOfDay.fromISOString("00000")); 9247 assertThrown!DateTimeException(TimeOfDay.fromISOString("13033")); 9248 assertThrown!DateTimeException(TimeOfDay.fromISOString("1277")); 9249 assertThrown!DateTimeException(TimeOfDay.fromISOString("12707")); 9250 assertThrown!DateTimeException(TimeOfDay.fromISOString("12070")); 9251 assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a")); 9252 assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3")); 9253 assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33")); 9254 assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033")); 9255 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033")); 9256 assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033")); 9257 assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330")); 9258 assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033")); 9259 assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033")); 9260 assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033")); 9261 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am")); 9262 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm")); 9263 9264 assertThrown!DateTimeException(TimeOfDay.fromISOString("0::")); 9265 assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:")); 9266 assertThrown!DateTimeException(TimeOfDay.fromISOString("::0")); 9267 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0")); 9268 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00")); 9269 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0")); 9270 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0")); 9271 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0")); 9272 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00")); 9273 assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33")); 9274 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7")); 9275 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07")); 9276 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0")); 9277 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a")); 9278 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3")); 9279 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33")); 9280 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33")); 9281 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33")); 9282 assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33")); 9283 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30")); 9284 assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30")); 9285 assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33")); 9286 assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33")); 9287 assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33")); 9288 assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33")); 9289 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am")); 9290 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm")); 9291 9292 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33")); 9293 9294 assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17)); 9295 assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12)); 9296 assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7)); 9297 assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17)); 9298 assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17)); 9299 assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17)); 9300 } 9301 9302 // https://issues.dlang.org/show_bug.cgi?id=17801 9303 @safe unittest 9304 { 9305 import std.conv : to; 9306 import std.meta : AliasSeq; 9307 static foreach (C; AliasSeq!(char, wchar, dchar)) 9308 { 9309 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 9310 assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16)); 9311 } 9312 } 9313 9314 9315 /++ 9316 Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS. 9317 Whitespace is stripped from the given string. 9318 9319 Params: 9320 isoExtString = A string formatted in the ISO Extended format for 9321 times. 9322 9323 Throws: 9324 $(REF DateTimeException,std,datetime,date) if the given string is 9325 not in the ISO Extended format or if the resulting $(LREF TimeOfDay) 9326 would not be valid. 9327 +/ 9328 static TimeOfDay fromISOExtString(S)(scope const S isoExtString) @safe pure 9329 if (isSomeString!S) 9330 { 9331 import std.conv : ConvException, text, to; 9332 import std.string : strip; 9333 9334 auto str = strip(isoExtString); 9335 int hours, minutes, seconds; 9336 9337 if (str.length != 8 || str[2] != ':' || str[5] != ':') 9338 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString)); 9339 9340 try 9341 { 9342 // cast to int from uint is used because it checks for 9343 // non digits without extra loops 9344 hours = cast(int) to!uint(str[0 .. 2]); 9345 minutes = cast(int) to!uint(str[3 .. 5]); 9346 seconds = cast(int) to!uint(str[6 .. $]); 9347 } 9348 catch (ConvException) 9349 { 9350 throw new DateTimeException(text("Invalid format for TimeOfDay.fromISOExtString: ", isoExtString)); 9351 } 9352 9353 return TimeOfDay(hours, minutes, seconds); 9354 } 9355 9356 /// 9357 @safe unittest 9358 { 9359 assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); 9360 assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); 9361 assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); 9362 } 9363 9364 @safe unittest 9365 { 9366 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("")); 9367 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0")); 9368 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00")); 9369 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000")); 9370 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000")); 9371 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000")); 9372 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033")); 9373 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277")); 9374 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707")); 9375 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070")); 9376 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a")); 9377 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3")); 9378 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33")); 9379 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033")); 9380 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033")); 9381 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033")); 9382 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330")); 9383 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033")); 9384 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033")); 9385 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033")); 9386 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am")); 9387 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm")); 9388 9389 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::")); 9390 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:")); 9391 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0")); 9392 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0")); 9393 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00")); 9394 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0")); 9395 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0")); 9396 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0")); 9397 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00")); 9398 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33")); 9399 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7")); 9400 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07")); 9401 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0")); 9402 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a")); 9403 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3")); 9404 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33")); 9405 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33")); 9406 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33")); 9407 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33")); 9408 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30")); 9409 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30")); 9410 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33")); 9411 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33")); 9412 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33")); 9413 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33")); 9414 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am")); 9415 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm")); 9416 9417 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033")); 9418 9419 assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17)); 9420 assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12)); 9421 assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7)); 9422 assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17)); 9423 assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17)); 9424 assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17)); 9425 } 9426 9427 // https://issues.dlang.org/show_bug.cgi?id=17801 9428 @safe unittest 9429 { 9430 import std.conv : to; 9431 import std.meta : AliasSeq; 9432 static foreach (C; AliasSeq!(char, wchar, dchar)) 9433 { 9434 static foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 9435 assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16)); 9436 } 9437 } 9438 9439 9440 /++ 9441 Returns midnight. 9442 +/ 9443 @property static TimeOfDay min() @safe pure nothrow @nogc 9444 { 9445 return TimeOfDay.init; 9446 } 9447 9448 @safe unittest 9449 { 9450 assert(TimeOfDay.min.hour == 0); 9451 assert(TimeOfDay.min.minute == 0); 9452 assert(TimeOfDay.min.second == 0); 9453 assert(TimeOfDay.min < TimeOfDay.max); 9454 } 9455 9456 9457 /++ 9458 Returns one second short of midnight. 9459 +/ 9460 @property static TimeOfDay max() @safe pure nothrow @nogc 9461 { 9462 auto tod = TimeOfDay.init; 9463 tod._hour = maxHour; 9464 tod._minute = maxMinute; 9465 tod._second = maxSecond; 9466 9467 return tod; 9468 } 9469 9470 @safe unittest 9471 { 9472 assert(TimeOfDay.max.hour == 23); 9473 assert(TimeOfDay.max.minute == 59); 9474 assert(TimeOfDay.max.second == 59); 9475 assert(TimeOfDay.max > TimeOfDay.min); 9476 } 9477 9478 9479 private: 9480 9481 /+ 9482 Add seconds to the time of day. Negative values will subtract. If the 9483 number of seconds overflows (or underflows), then the seconds will wrap, 9484 increasing (or decreasing) the number of minutes accordingly. If the 9485 number of minutes overflows (or underflows), then the minutes will wrap. 9486 If the number of minutes overflows(or underflows), then the hour will 9487 wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30). 9488 9489 Params: 9490 seconds = The number of seconds to add to this TimeOfDay. 9491 +/ 9492 ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc 9493 { 9494 import core.time : convert; 9495 long hnsecs = convert!("seconds", "hnsecs")(seconds); 9496 hnsecs += convert!("hours", "hnsecs")(_hour); 9497 hnsecs += convert!("minutes", "hnsecs")(_minute); 9498 hnsecs += convert!("seconds", "hnsecs")(_second); 9499 9500 hnsecs %= convert!("days", "hnsecs")(1); 9501 9502 if (hnsecs < 0) 9503 hnsecs += convert!("days", "hnsecs")(1); 9504 9505 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 9506 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 9507 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 9508 9509 _hour = cast(ubyte) newHours; 9510 _minute = cast(ubyte) newMinutes; 9511 _second = cast(ubyte) newSeconds; 9512 9513 return this; 9514 } 9515 9516 @safe unittest 9517 { 9518 static void testTOD(TimeOfDay orig, int seconds, TimeOfDay expected, size_t line = __LINE__) 9519 { 9520 orig._addSeconds(seconds); 9521 assert(orig == expected); 9522 } 9523 9524 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 9525 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 9526 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 9527 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 9528 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 9529 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 9530 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 9531 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 9532 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 9533 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0)); 9534 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3)); 9535 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32)); 9536 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33)); 9537 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34)); 9538 9539 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59)); 9540 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0)); 9541 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1)); 9542 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0)); 9543 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32)); 9544 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33)); 9545 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34)); 9546 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33)); 9547 9548 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 9549 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 9550 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 9551 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 9552 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 9553 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 9554 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 9555 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 9556 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59)); 9557 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58)); 9558 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34)); 9559 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33)); 9560 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32)); 9561 9562 testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0)); 9563 testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59)); 9564 testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33)); 9565 testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32)); 9566 testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59)); 9567 testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33)); 9568 9569 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 9570 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 9571 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59)); 9572 9573 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 9574 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 9575 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59)); 9576 9577 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 9578 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 9579 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59)); 9580 9581 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0)); 9582 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 9583 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 9584 9585 const ctod = TimeOfDay(0, 0, 0); 9586 immutable itod = TimeOfDay(0, 0, 0); 9587 static assert(!__traits(compiles, ctod._addSeconds(7))); 9588 static assert(!__traits(compiles, itod._addSeconds(7))); 9589 } 9590 9591 9592 /+ 9593 Whether the given values form a valid $(LREF TimeOfDay). 9594 +/ 9595 static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc 9596 { 9597 return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second); 9598 } 9599 9600 9601 @safe pure invariant() 9602 { 9603 import std.format : format; 9604 assert(_valid(_hour, _minute, _second), 9605 format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second)); 9606 } 9607 9608 9609 package: 9610 9611 ubyte _hour; 9612 ubyte _minute; 9613 ubyte _second; 9614 9615 enum ubyte maxHour = 24 - 1; 9616 enum ubyte maxMinute = 60 - 1; 9617 enum ubyte maxSecond = 60 - 1; 9618 } 9619 9620 /// 9621 @safe pure unittest 9622 { 9623 import core.time : minutes, seconds; 9624 9625 auto t = TimeOfDay(12, 30, 0); 9626 9627 t += 10.minutes + 100.seconds; 9628 assert(t == TimeOfDay(12, 41, 40)); 9629 9630 assert(t.toISOExtString() == "12:41:40"); 9631 assert(t.toISOString() == "124140"); 9632 9633 assert(TimeOfDay.fromISOExtString("15:00:00") == TimeOfDay(15, 0, 0)); 9634 assert(TimeOfDay.fromISOString("015000") == TimeOfDay(1, 50, 0)); 9635 } 9636 9637 /++ 9638 Returns whether the given value is valid for the given unit type when in a 9639 time point. Naturally, a duration is not held to a particular range, but 9640 the values in a time point are (e.g. a month must be in the range of 9641 1 - 12 inclusive). 9642 9643 Params: 9644 units = The units of time to validate. 9645 value = The number to validate. 9646 +/ 9647 bool valid(string units)(int value) @safe pure nothrow @nogc 9648 if (units == "months" || 9649 units == "hours" || 9650 units == "minutes" || 9651 units == "seconds") 9652 { 9653 static if (units == "months") 9654 return value >= Month.jan && value <= Month.dec; 9655 else static if (units == "hours") 9656 return value >= 0 && value <= 23; 9657 else static if (units == "minutes") 9658 return value >= 0 && value <= 59; 9659 else static if (units == "seconds") 9660 return value >= 0 && value <= 59; 9661 } 9662 9663 /// 9664 @safe unittest 9665 { 9666 assert(valid!"hours"(12)); 9667 assert(!valid!"hours"(32)); 9668 assert(valid!"months"(12)); 9669 assert(!valid!"months"(13)); 9670 } 9671 9672 /++ 9673 Returns whether the given day is valid for the given year and month. 9674 9675 Params: 9676 units = The units of time to validate. 9677 year = The year of the day to validate. 9678 month = The month of the day to validate (January is 1). 9679 day = The day to validate. 9680 +/ 9681 bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc 9682 if (units == "days") 9683 { 9684 return day > 0 && day <= maxDay(year, month); 9685 } 9686 9687 /// 9688 @safe pure nothrow @nogc unittest 9689 { 9690 assert(valid!"days"(2016, 2, 29)); 9691 assert(!valid!"days"(2016, 2, 30)); 9692 assert(valid!"days"(2017, 2, 20)); 9693 assert(!valid!"days"(2017, 2, 29)); 9694 } 9695 9696 private short castToYear(int year, string file = __FILE__, size_t line = __LINE__) @safe pure 9697 { 9698 import std.conv : to, ConvOverflowException; 9699 import std.format : format; 9700 9701 try 9702 return year.to!short; 9703 catch (ConvOverflowException) 9704 throw new DateTimeException(format("year %s doesn't fit to Date.", year), file, line); 9705 } 9706 9707 /++ 9708 Params: 9709 units = The units of time to validate. 9710 value = The number to validate. 9711 file = The file that the $(LREF DateTimeException) will list if thrown. 9712 line = The line number that the $(LREF DateTimeException) will list if 9713 thrown. 9714 9715 Throws: 9716 $(LREF DateTimeException) if `valid!units(value)` is false. 9717 +/ 9718 void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure 9719 if (units == "months" || 9720 units == "hours" || 9721 units == "minutes" || 9722 units == "seconds") 9723 { 9724 import std.format : format; 9725 9726 static if (units == "months") 9727 { 9728 if (!valid!units(value)) 9729 throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line); 9730 } 9731 else static if (units == "hours") 9732 { 9733 if (!valid!units(value)) 9734 throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line); 9735 } 9736 else static if (units == "minutes") 9737 { 9738 if (!valid!units(value)) 9739 throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line); 9740 } 9741 else static if (units == "seconds") 9742 { 9743 if (!valid!units(value)) 9744 throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line); 9745 } 9746 } 9747 9748 /// 9749 @safe pure unittest 9750 { 9751 import std.exception : assertThrown, assertNotThrown; 9752 9753 assertNotThrown(enforceValid!"months"(10)); 9754 assertNotThrown(enforceValid!"seconds"(40)); 9755 9756 assertThrown!DateTimeException(enforceValid!"months"(0)); 9757 assertThrown!DateTimeException(enforceValid!"hours"(24)); 9758 assertThrown!DateTimeException(enforceValid!"minutes"(60)); 9759 assertThrown!DateTimeException(enforceValid!"seconds"(60)); 9760 } 9761 9762 9763 /++ 9764 Because the validity of the day number depends on both on the year 9765 and month of which the day is occurring, take all three variables 9766 to validate the day. 9767 9768 Params: 9769 units = The units of time to validate. 9770 year = The year of the day to validate. 9771 month = The month of the day to validate. 9772 day = The day to validate. 9773 file = The file that the $(LREF DateTimeException) will list if thrown. 9774 line = The line number that the $(LREF DateTimeException) will list if 9775 thrown. 9776 9777 Throws: 9778 $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false. 9779 +/ 9780 void enforceValid(string units) 9781 (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure 9782 if (units == "days") 9783 { 9784 import std.format : format; 9785 if (!valid!"days"(year, month, day)) 9786 throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line); 9787 } 9788 9789 /// 9790 @safe pure unittest 9791 { 9792 import std.exception : assertThrown, assertNotThrown; 9793 9794 assertNotThrown(enforceValid!"days"(2000, Month.jan, 1)); 9795 // leap year 9796 assertNotThrown(enforceValid!"days"(2000, Month.feb, 29)); 9797 9798 assertThrown!DateTimeException(enforceValid!"days"(2001, Month.feb, 29)); 9799 assertThrown!DateTimeException(enforceValid!"days"(2000, Month.jan, 32)); 9800 assertThrown!DateTimeException(enforceValid!"days"(2000, Month.apr, 31)); 9801 } 9802 9803 9804 /++ 9805 Returns the number of days from the current day of the week to the given 9806 day of the week. If they are the same, then the result is 0. 9807 9808 Params: 9809 currDoW = The current day of the week. 9810 dow = The day of the week to get the number of days to. 9811 +/ 9812 int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc 9813 { 9814 if (currDoW == dow) 9815 return 0; 9816 if (currDoW < dow) 9817 return dow - currDoW; 9818 return DayOfWeek.sat - currDoW + dow + 1; 9819 } 9820 9821 /// 9822 @safe pure nothrow @nogc unittest 9823 { 9824 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9825 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9826 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9827 } 9828 9829 @safe unittest 9830 { 9831 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0); 9832 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1); 9833 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2); 9834 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3); 9835 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4); 9836 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5); 9837 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6); 9838 9839 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9840 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9841 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1); 9842 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9843 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3); 9844 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4); 9845 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5); 9846 9847 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5); 9848 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6); 9849 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0); 9850 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1); 9851 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2); 9852 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3); 9853 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4); 9854 9855 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4); 9856 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5); 9857 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6); 9858 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0); 9859 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1); 9860 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2); 9861 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3); 9862 9863 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3); 9864 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4); 9865 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5); 9866 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6); 9867 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0); 9868 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1); 9869 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2); 9870 9871 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2); 9872 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3); 9873 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4); 9874 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5); 9875 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6); 9876 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0); 9877 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1); 9878 9879 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1); 9880 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2); 9881 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3); 9882 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4); 9883 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5); 9884 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6); 9885 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0); 9886 } 9887 9888 9889 /++ 9890 Returns the number of months from the current months of the year to the 9891 given month of the year. If they are the same, then the result is 0. 9892 9893 Params: 9894 currMonth = The current month of the year. 9895 month = The month of the year to get the number of months to. 9896 +/ 9897 int monthsToMonth(int currMonth, int month) @safe pure 9898 { 9899 enforceValid!"months"(currMonth); 9900 enforceValid!"months"(month); 9901 9902 if (currMonth == month) 9903 return 0; 9904 if (currMonth < month) 9905 return month - currMonth; 9906 return Month.dec - currMonth + month; 9907 } 9908 9909 /// 9910 @safe pure unittest 9911 { 9912 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9913 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9914 assert(monthsToMonth(Month.jul, Month.oct) == 3); 9915 } 9916 9917 @safe unittest 9918 { 9919 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9920 assert(monthsToMonth(Month.jan, Month.feb) == 1); 9921 assert(monthsToMonth(Month.jan, Month.mar) == 2); 9922 assert(monthsToMonth(Month.jan, Month.apr) == 3); 9923 assert(monthsToMonth(Month.jan, Month.may) == 4); 9924 assert(monthsToMonth(Month.jan, Month.jun) == 5); 9925 assert(monthsToMonth(Month.jan, Month.jul) == 6); 9926 assert(monthsToMonth(Month.jan, Month.aug) == 7); 9927 assert(monthsToMonth(Month.jan, Month.sep) == 8); 9928 assert(monthsToMonth(Month.jan, Month.oct) == 9); 9929 assert(monthsToMonth(Month.jan, Month.nov) == 10); 9930 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9931 9932 assert(monthsToMonth(Month.may, Month.jan) == 8); 9933 assert(monthsToMonth(Month.may, Month.feb) == 9); 9934 assert(monthsToMonth(Month.may, Month.mar) == 10); 9935 assert(monthsToMonth(Month.may, Month.apr) == 11); 9936 assert(monthsToMonth(Month.may, Month.may) == 0); 9937 assert(monthsToMonth(Month.may, Month.jun) == 1); 9938 assert(monthsToMonth(Month.may, Month.jul) == 2); 9939 assert(monthsToMonth(Month.may, Month.aug) == 3); 9940 assert(monthsToMonth(Month.may, Month.sep) == 4); 9941 assert(monthsToMonth(Month.may, Month.oct) == 5); 9942 assert(monthsToMonth(Month.may, Month.nov) == 6); 9943 assert(monthsToMonth(Month.may, Month.dec) == 7); 9944 9945 assert(monthsToMonth(Month.oct, Month.jan) == 3); 9946 assert(monthsToMonth(Month.oct, Month.feb) == 4); 9947 assert(monthsToMonth(Month.oct, Month.mar) == 5); 9948 assert(monthsToMonth(Month.oct, Month.apr) == 6); 9949 assert(monthsToMonth(Month.oct, Month.may) == 7); 9950 assert(monthsToMonth(Month.oct, Month.jun) == 8); 9951 assert(monthsToMonth(Month.oct, Month.jul) == 9); 9952 assert(monthsToMonth(Month.oct, Month.aug) == 10); 9953 assert(monthsToMonth(Month.oct, Month.sep) == 11); 9954 assert(monthsToMonth(Month.oct, Month.oct) == 0); 9955 assert(monthsToMonth(Month.oct, Month.nov) == 1); 9956 assert(monthsToMonth(Month.oct, Month.dec) == 2); 9957 9958 assert(monthsToMonth(Month.dec, Month.jan) == 1); 9959 assert(monthsToMonth(Month.dec, Month.feb) == 2); 9960 assert(monthsToMonth(Month.dec, Month.mar) == 3); 9961 assert(monthsToMonth(Month.dec, Month.apr) == 4); 9962 assert(monthsToMonth(Month.dec, Month.may) == 5); 9963 assert(monthsToMonth(Month.dec, Month.jun) == 6); 9964 assert(monthsToMonth(Month.dec, Month.jul) == 7); 9965 assert(monthsToMonth(Month.dec, Month.aug) == 8); 9966 assert(monthsToMonth(Month.dec, Month.sep) == 9); 9967 assert(monthsToMonth(Month.dec, Month.oct) == 10); 9968 assert(monthsToMonth(Month.dec, Month.nov) == 11); 9969 assert(monthsToMonth(Month.dec, Month.dec) == 0); 9970 } 9971 9972 9973 /++ 9974 Whether the given Gregorian Year is a leap year. 9975 9976 Params: 9977 year = The year to to be tested. 9978 +/ 9979 bool yearIsLeapYear(int year) @safe pure nothrow @nogc 9980 { 9981 if (year % 400 == 0) 9982 return true; 9983 if (year % 100 == 0) 9984 return false; 9985 return year % 4 == 0; 9986 } 9987 9988 /// 9989 @safe unittest 9990 { 9991 foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) 9992 { 9993 assert(!yearIsLeapYear(year)); 9994 assert(!yearIsLeapYear(-year)); 9995 } 9996 9997 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 9998 { 9999 assert(yearIsLeapYear(year)); 10000 assert(yearIsLeapYear(-year)); 10001 } 10002 } 10003 10004 @safe unittest 10005 { 10006 import std.format : format; 10007 foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999, 10008 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011]) 10009 { 10010 assert(!yearIsLeapYear(year), format("year: %s.", year)); 10011 assert(!yearIsLeapYear(-year), format("year: %s.", year)); 10012 } 10013 10014 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 10015 { 10016 assert(yearIsLeapYear(year), format("year: %s.", year)); 10017 assert(yearIsLeapYear(-year), format("year: %s.", year)); 10018 } 10019 } 10020 10021 10022 /++ 10023 Whether the given type defines all of the necessary functions for it to 10024 function as a time point. 10025 10026 1. `T` must define a static property named `min` which is the smallest 10027 value of `T` as `Unqual!T`. 10028 10029 2. `T` must define a static property named `max` which is the largest 10030 value of `T` as `Unqual!T`. 10031 10032 3. `T` must define an `opBinary` for addition and subtraction that 10033 accepts $(REF Duration, core,time) and returns `Unqual!T`. 10034 10035 4. `T` must define an `opOpAssign` for addition and subtraction that 10036 accepts $(REF Duration, core,time) and returns $(D ref Unqual!T). 10037 10038 5. `T` must define a `opBinary` for subtraction which accepts `T` 10039 and returns $(REF Duration, core,time). 10040 +/ 10041 template isTimePoint(T) 10042 { 10043 import core.time : Duration; 10044 import std.traits : FunctionAttribute, functionAttributes, Unqual; 10045 10046 enum isTimePoint = hasMin && 10047 hasMax && 10048 hasOverloadedOpBinaryWithDuration && 10049 hasOverloadedOpAssignWithDuration && 10050 hasOverloadedOpBinaryWithSelf && 10051 !is(U == Duration); 10052 10053 private: 10054 10055 alias U = Unqual!T; 10056 10057 enum hasMin = __traits(hasMember, T, "min") && 10058 is(typeof(T.min) == U) && 10059 is(typeof({static assert(__traits(isStaticFunction, T.min));})); 10060 10061 enum hasMax = __traits(hasMember, T, "max") && 10062 is(typeof(T.max) == U) && 10063 is(typeof({static assert(__traits(isStaticFunction, T.max));})); 10064 10065 enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) && 10066 is(typeof(T.init - Duration.init) == U); 10067 10068 enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) && 10069 is(typeof(U.init -= Duration.init) == U) && 10070 is(typeof( 10071 { 10072 alias add = U.opOpAssign!"+"; 10073 alias sub = U.opOpAssign!"-"; 10074 alias FA = FunctionAttribute; 10075 static assert((functionAttributes!add & FA.ref_) != 0); 10076 static assert((functionAttributes!sub & FA.ref_) != 0); 10077 })); 10078 10079 enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration); 10080 } 10081 10082 /// 10083 @safe unittest 10084 { 10085 import core.time : Duration; 10086 import std.datetime.interval : Interval; 10087 import std.datetime.systime : SysTime; 10088 10089 static assert(isTimePoint!Date); 10090 static assert(isTimePoint!DateTime); 10091 static assert(isTimePoint!SysTime); 10092 static assert(isTimePoint!TimeOfDay); 10093 10094 static assert(!isTimePoint!int); 10095 static assert(!isTimePoint!Duration); 10096 static assert(!isTimePoint!(Interval!SysTime)); 10097 } 10098 10099 @safe unittest 10100 { 10101 import core.time; 10102 import std.datetime.interval; 10103 import std.datetime.systime; 10104 import std.meta : AliasSeq; 10105 10106 static foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay)) 10107 { 10108 static assert(isTimePoint!(const TP), TP.stringof); 10109 static assert(isTimePoint!(immutable TP), TP.stringof); 10110 } 10111 10112 static foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date)) 10113 static assert(!isTimePoint!T, T.stringof); 10114 } 10115 10116 10117 /++ 10118 Whether all of the given strings are valid units of time. 10119 10120 `"nsecs"` is not considered a valid unit of time. Nothing in std.datetime 10121 can handle precision greater than hnsecs, and the few functions in core.time 10122 which deal with "nsecs" deal with it explicitly. 10123 +/ 10124 bool validTimeUnits(string[] units...) @safe pure nothrow @nogc 10125 { 10126 import std.algorithm.searching : canFind; 10127 foreach (str; units) 10128 { 10129 if (!canFind(timeStrings[], str)) 10130 return false; 10131 } 10132 return true; 10133 } 10134 10135 /// 10136 @safe @nogc nothrow unittest 10137 { 10138 assert(validTimeUnits("msecs", "seconds", "minutes")); 10139 assert(validTimeUnits("days", "weeks", "months")); 10140 assert(!validTimeUnits("ms", "seconds", "minutes")); 10141 } 10142 10143 10144 /++ 10145 Compares two time unit strings. `"years"` are the largest units and 10146 `"hnsecs"` are the smallest. 10147 10148 Returns: 10149 $(BOOKTABLE, 10150 $(TR $(TD this < rhs) $(TD < 0)) 10151 $(TR $(TD this == rhs) $(TD 0)) 10152 $(TR $(TD this > rhs) $(TD > 0)) 10153 ) 10154 10155 Throws: 10156 $(LREF DateTimeException) if either of the given strings is not a valid 10157 time unit string. 10158 +/ 10159 int cmpTimeUnits(string lhs, string rhs) @safe pure 10160 { 10161 import std.algorithm.searching : countUntil; 10162 import std.exception : enforce; 10163 import std.format : format; 10164 10165 immutable indexOfLHS = countUntil(timeStrings, lhs); 10166 immutable indexOfRHS = countUntil(timeStrings, rhs); 10167 10168 enforce!DateTimeException(indexOfLHS != -1, format("%s is not a valid TimeString", lhs)); 10169 enforce!DateTimeException(indexOfRHS != -1, format("%s is not a valid TimeString", rhs)); 10170 10171 if (indexOfLHS < indexOfRHS) 10172 return -1; 10173 if (indexOfLHS > indexOfRHS) 10174 return 1; 10175 10176 return 0; 10177 } 10178 10179 /// 10180 @safe pure unittest 10181 { 10182 import std.exception : assertThrown; 10183 10184 assert(cmpTimeUnits("hours", "hours") == 0); 10185 assert(cmpTimeUnits("hours", "weeks") < 0); 10186 assert(cmpTimeUnits("months", "seconds") > 0); 10187 10188 assertThrown!DateTimeException(cmpTimeUnits("month", "second")); 10189 } 10190 10191 @safe unittest 10192 { 10193 foreach (i, outerUnits; timeStrings) 10194 { 10195 assert(cmpTimeUnits(outerUnits, outerUnits) == 0); 10196 10197 // For some reason, $ won't compile. 10198 foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length]) 10199 assert(cmpTimeUnits(outerUnits, innerUnits) == -1); 10200 } 10201 10202 foreach (i, outerUnits; timeStrings) 10203 { 10204 foreach (innerUnits; timeStrings[0 .. i]) 10205 assert(cmpTimeUnits(outerUnits, innerUnits) == 1); 10206 } 10207 } 10208 10209 10210 /++ 10211 Compares two time unit strings at compile time. `"years"` are the largest 10212 units and `"hnsecs"` are the smallest. 10213 10214 This template is used instead of `cmpTimeUnits` because exceptions 10215 can't be thrown at compile time and `cmpTimeUnits` must enforce that 10216 the strings it's given are valid time unit strings. This template uses a 10217 template constraint instead. 10218 10219 Returns: 10220 $(BOOKTABLE, 10221 $(TR $(TD this < rhs) $(TD < 0)) 10222 $(TR $(TD this == rhs) $(TD 0)) 10223 $(TR $(TD this > rhs) $(TD > 0)) 10224 ) 10225 +/ 10226 template CmpTimeUnits(string lhs, string rhs) 10227 if (validTimeUnits(lhs, rhs)) 10228 { 10229 enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs); 10230 } 10231 10232 /// 10233 @safe pure unittest 10234 { 10235 static assert(CmpTimeUnits!("years", "weeks") > 0); 10236 static assert(CmpTimeUnits!("days", "days") == 0); 10237 static assert(CmpTimeUnits!("seconds", "hours") < 0); 10238 } 10239 10240 // Helper function for CmpTimeUnits. 10241 private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc 10242 { 10243 import std.algorithm.searching : countUntil; 10244 auto tstrings = timeStrings; 10245 immutable indexOfLHS = countUntil(tstrings, lhs); 10246 immutable indexOfRHS = countUntil(tstrings, rhs); 10247 10248 if (indexOfLHS < indexOfRHS) 10249 return -1; 10250 if (indexOfLHS > indexOfRHS) 10251 return 1; 10252 10253 return 0; 10254 } 10255 10256 @safe unittest 10257 { 10258 static foreach (i; 0 .. timeStrings.length) 10259 { 10260 static assert(CmpTimeUnits!(timeStrings[i], timeStrings[i]) == 0); 10261 10262 static foreach (next; timeStrings[i + 1 .. $]) 10263 static assert(CmpTimeUnits!(timeStrings[i], next) == -1); 10264 10265 static foreach (prev; timeStrings[0 .. i]) 10266 static assert(CmpTimeUnits!(timeStrings[i], prev) == 1); 10267 } 10268 } 10269 10270 10271 package: 10272 10273 10274 /+ 10275 Array of the short (three letter) names of each month. 10276 +/ 10277 immutable string[12] _monthNames = ["Jan", 10278 "Feb", 10279 "Mar", 10280 "Apr", 10281 "May", 10282 "Jun", 10283 "Jul", 10284 "Aug", 10285 "Sep", 10286 "Oct", 10287 "Nov", 10288 "Dec"]; 10289 10290 /+ 10291 The maximum valid Day in the given month in the given year. 10292 10293 Params: 10294 year = The year to get the day for. 10295 month = The month of the Gregorian Calendar to get the day for. 10296 +/ 10297 ubyte maxDay(int year, int month) @safe pure nothrow @nogc 10298 in 10299 { 10300 assert(valid!"months"(month)); 10301 } 10302 do 10303 { 10304 switch (month) 10305 { 10306 case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec: 10307 return 31; 10308 case Month.feb: 10309 return yearIsLeapYear(year) ? 29 : 28; 10310 case Month.apr, Month.jun, Month.sep, Month.nov: 10311 return 30; 10312 default: 10313 assert(0, "Invalid month."); 10314 } 10315 } 10316 10317 @safe unittest 10318 { 10319 // Test A.D. 10320 assert(maxDay(1999, 1) == 31); 10321 assert(maxDay(1999, 2) == 28); 10322 assert(maxDay(1999, 3) == 31); 10323 assert(maxDay(1999, 4) == 30); 10324 assert(maxDay(1999, 5) == 31); 10325 assert(maxDay(1999, 6) == 30); 10326 assert(maxDay(1999, 7) == 31); 10327 assert(maxDay(1999, 8) == 31); 10328 assert(maxDay(1999, 9) == 30); 10329 assert(maxDay(1999, 10) == 31); 10330 assert(maxDay(1999, 11) == 30); 10331 assert(maxDay(1999, 12) == 31); 10332 10333 assert(maxDay(2000, 1) == 31); 10334 assert(maxDay(2000, 2) == 29); 10335 assert(maxDay(2000, 3) == 31); 10336 assert(maxDay(2000, 4) == 30); 10337 assert(maxDay(2000, 5) == 31); 10338 assert(maxDay(2000, 6) == 30); 10339 assert(maxDay(2000, 7) == 31); 10340 assert(maxDay(2000, 8) == 31); 10341 assert(maxDay(2000, 9) == 30); 10342 assert(maxDay(2000, 10) == 31); 10343 assert(maxDay(2000, 11) == 30); 10344 assert(maxDay(2000, 12) == 31); 10345 10346 // Test B.C. 10347 assert(maxDay(-1999, 1) == 31); 10348 assert(maxDay(-1999, 2) == 28); 10349 assert(maxDay(-1999, 3) == 31); 10350 assert(maxDay(-1999, 4) == 30); 10351 assert(maxDay(-1999, 5) == 31); 10352 assert(maxDay(-1999, 6) == 30); 10353 assert(maxDay(-1999, 7) == 31); 10354 assert(maxDay(-1999, 8) == 31); 10355 assert(maxDay(-1999, 9) == 30); 10356 assert(maxDay(-1999, 10) == 31); 10357 assert(maxDay(-1999, 11) == 30); 10358 assert(maxDay(-1999, 12) == 31); 10359 10360 assert(maxDay(-2000, 1) == 31); 10361 assert(maxDay(-2000, 2) == 29); 10362 assert(maxDay(-2000, 3) == 31); 10363 assert(maxDay(-2000, 4) == 30); 10364 assert(maxDay(-2000, 5) == 31); 10365 assert(maxDay(-2000, 6) == 30); 10366 assert(maxDay(-2000, 7) == 31); 10367 assert(maxDay(-2000, 8) == 31); 10368 assert(maxDay(-2000, 9) == 30); 10369 assert(maxDay(-2000, 10) == 31); 10370 assert(maxDay(-2000, 11) == 30); 10371 assert(maxDay(-2000, 12) == 31); 10372 } 10373 10374 /+ 10375 Splits out a particular unit from hnsecs and gives the value for that 10376 unit and the remaining hnsecs. It really shouldn't be used unless unless 10377 all units larger than the given units have already been split out. 10378 10379 Params: 10380 units = The units to split out. 10381 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left 10382 after splitting out the given units. 10383 10384 Returns: 10385 The number of the given units from converting hnsecs to those units. 10386 +/ 10387 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc 10388 if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) 10389 { 10390 import core.time : convert; 10391 immutable value = convert!("hnsecs", units)(hnsecs); 10392 hnsecs -= convert!(units, "hnsecs")(value); 10393 return value; 10394 } 10395 10396 @safe unittest 10397 { 10398 auto hnsecs = 2595000000007L; 10399 immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 10400 assert(days == 3); 10401 assert(hnsecs == 3000000007); 10402 10403 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 10404 assert(minutes == 5); 10405 assert(hnsecs == 7); 10406 } 10407 10408 10409 /+ 10410 Returns the day of the week for the given day of the Gregorian Calendar. 10411 10412 Params: 10413 day = The day of the Gregorian Calendar for which to get the day of 10414 the week. 10415 +/ 10416 DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc 10417 { 10418 // January 1st, 1 A.D. was a Monday 10419 if (day >= 0) 10420 return cast(DayOfWeek)(day % 7); 10421 else 10422 { 10423 immutable dow = cast(DayOfWeek)((day % 7) + 7); 10424 10425 if (dow == 7) 10426 return DayOfWeek.sun; 10427 else 10428 return dow; 10429 } 10430 } 10431 10432 @safe unittest 10433 { 10434 import std.datetime.systime : SysTime; 10435 10436 // Test A.D. 10437 assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon); 10438 assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue); 10439 assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed); 10440 assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu); 10441 assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri); 10442 assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat); 10443 assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun); 10444 assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon); 10445 assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue); 10446 assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue); 10447 assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed); 10448 assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu); 10449 assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 10450 assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 10451 assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun); 10452 assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon); 10453 assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue); 10454 assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed); 10455 assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu); 10456 assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri); 10457 assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat); 10458 assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun); 10459 10460 // Test B.C. 10461 assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun); 10462 assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat); 10463 assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri); 10464 assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu); 10465 assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed); 10466 assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue); 10467 assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon); 10468 assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun); 10469 assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat); 10470 } 10471 10472 10473 private: 10474 10475 enum daysInYear = 365; // The number of days in a non-leap year. 10476 enum daysInLeapYear = 366; // The numbef or days in a leap year. 10477 enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years. 10478 enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years. 10479 enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years. 10480 10481 /+ 10482 Array of integers representing the last days of each month in a year. 10483 +/ 10484 immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; 10485 10486 /+ 10487 Array of integers representing the last days of each month in a leap year. 10488 +/ 10489 immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; 10490 10491 10492 /+ 10493 Returns the string representation of the given month. 10494 +/ 10495 string monthToString(Month month) @safe pure 10496 { 10497 import std.format : format; 10498 assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month)); 10499 return _monthNames[month - Month.jan]; 10500 } 10501 10502 @safe unittest 10503 { 10504 assert(monthToString(Month.jan) == "Jan"); 10505 assert(monthToString(Month.feb) == "Feb"); 10506 assert(monthToString(Month.mar) == "Mar"); 10507 assert(monthToString(Month.apr) == "Apr"); 10508 assert(monthToString(Month.may) == "May"); 10509 assert(monthToString(Month.jun) == "Jun"); 10510 assert(monthToString(Month.jul) == "Jul"); 10511 assert(monthToString(Month.aug) == "Aug"); 10512 assert(monthToString(Month.sep) == "Sep"); 10513 assert(monthToString(Month.oct) == "Oct"); 10514 assert(monthToString(Month.nov) == "Nov"); 10515 assert(monthToString(Month.dec) == "Dec"); 10516 } 10517 10518 10519 /+ 10520 Returns the Month corresponding to the given string. 10521 10522 Params: 10523 monthStr = The string representation of the month to get the Month for. 10524 10525 Throws: 10526 $(REF DateTimeException,std,datetime,date) if the given month is not a 10527 valid month string. 10528 +/ 10529 Month monthFromString(T)(T monthStr) @safe pure 10530 if (isSomeString!T) 10531 { 10532 import std.format : format; 10533 switch (monthStr) 10534 { 10535 case "Jan": 10536 return Month.jan; 10537 case "Feb": 10538 return Month.feb; 10539 case "Mar": 10540 return Month.mar; 10541 case "Apr": 10542 return Month.apr; 10543 case "May": 10544 return Month.may; 10545 case "Jun": 10546 return Month.jun; 10547 case "Jul": 10548 return Month.jul; 10549 case "Aug": 10550 return Month.aug; 10551 case "Sep": 10552 return Month.sep; 10553 case "Oct": 10554 return Month.oct; 10555 case "Nov": 10556 return Month.nov; 10557 case "Dec": 10558 return Month.dec; 10559 default: 10560 throw new DateTimeException(format!"Invalid month %s"(monthStr)); 10561 } 10562 } 10563 10564 @safe unittest 10565 { 10566 import std.conv : to; 10567 import std.traits : EnumMembers; 10568 foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY", 10569 "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"]) 10570 { 10571 assertThrown!DateTimeException(monthFromString(badStr), badStr); 10572 } 10573 10574 foreach (month; EnumMembers!Month) 10575 { 10576 assert(monthFromString(monthToString(month)) == month, month.to!string); 10577 } 10578 } 10579 10580 10581 // NOTE: all the non-simple array literals are wrapped in functions, because 10582 // otherwise importing causes re-evaluation of the static initializers using 10583 // CTFE with unittests enabled 10584 version (StdUnittest) 10585 { 10586 private @safe: 10587 // All of these helper arrays are sorted in ascending order. 10588 auto testYearsBC = [-1999, -1200, -600, -4, -1, 0]; 10589 auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012]; 10590 10591 // I'd use a Tuple, but I get forward reference errors if I try. 10592 struct MonthDay 10593 { 10594 Month month; 10595 short day; 10596 10597 this(int m, short d) 10598 { 10599 month = cast(Month) m; 10600 day = d; 10601 } 10602 } 10603 10604 MonthDay[] testMonthDays() 10605 { 10606 static MonthDay[] result = [MonthDay(1, 1), 10607 MonthDay(1, 2), 10608 MonthDay(3, 17), 10609 MonthDay(7, 4), 10610 MonthDay(10, 27), 10611 MonthDay(12, 30), 10612 MonthDay(12, 31)]; 10613 return result; 10614 } 10615 10616 auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31]; 10617 10618 TimeOfDay[] testTODs() 10619 { 10620 static result = [TimeOfDay(0, 0, 0), 10621 TimeOfDay(0, 0, 1), 10622 TimeOfDay(0, 1, 0), 10623 TimeOfDay(1, 0, 0), 10624 TimeOfDay(13, 13, 13), 10625 TimeOfDay(23, 59, 59)]; 10626 return result; 10627 } 10628 10629 auto testHours = [0, 1, 12, 22, 23]; 10630 auto testMinSecs = [0, 1, 30, 58, 59]; 10631 10632 // Throwing exceptions is incredibly expensive, so we want to use a smaller 10633 // set of values for tests using assertThrown. 10634 TimeOfDay[] testTODsThrown() 10635 { 10636 static result = [TimeOfDay(0, 0, 0), 10637 TimeOfDay(13, 13, 13), 10638 TimeOfDay(23, 59, 59)]; 10639 return result; 10640 } 10641 10642 Date[] testDatesBC; 10643 Date[] testDatesAD; 10644 10645 DateTime[] testDateTimesBC; 10646 DateTime[] testDateTimesAD; 10647 10648 // I'd use a Tuple, but I get forward reference errors if I try. 10649 struct GregDay { int day; Date date; } 10650 GregDay[] testGregDaysBC() 10651 { 10652 static result = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar 10653 GregDay(-735_233, Date(-2012, 1, 1)), 10654 GregDay(-735_202, Date(-2012, 2, 1)), 10655 GregDay(-735_175, Date(-2012, 2, 28)), 10656 GregDay(-735_174, Date(-2012, 2, 29)), 10657 GregDay(-735_173, Date(-2012, 3, 1)), 10658 GregDay(-734_502, Date(-2010, 1, 1)), 10659 GregDay(-734_472, Date(-2010, 1, 31)), 10660 GregDay(-734_471, Date(-2010, 2, 1)), 10661 GregDay(-734_444, Date(-2010, 2, 28)), 10662 GregDay(-734_443, Date(-2010, 3, 1)), 10663 GregDay(-734_413, Date(-2010, 3, 31)), 10664 GregDay(-734_412, Date(-2010, 4, 1)), 10665 GregDay(-734_383, Date(-2010, 4, 30)), 10666 GregDay(-734_382, Date(-2010, 5, 1)), 10667 GregDay(-734_352, Date(-2010, 5, 31)), 10668 GregDay(-734_351, Date(-2010, 6, 1)), 10669 GregDay(-734_322, Date(-2010, 6, 30)), 10670 GregDay(-734_321, Date(-2010, 7, 1)), 10671 GregDay(-734_291, Date(-2010, 7, 31)), 10672 GregDay(-734_290, Date(-2010, 8, 1)), 10673 GregDay(-734_260, Date(-2010, 8, 31)), 10674 GregDay(-734_259, Date(-2010, 9, 1)), 10675 GregDay(-734_230, Date(-2010, 9, 30)), 10676 GregDay(-734_229, Date(-2010, 10, 1)), 10677 GregDay(-734_199, Date(-2010, 10, 31)), 10678 GregDay(-734_198, Date(-2010, 11, 1)), 10679 GregDay(-734_169, Date(-2010, 11, 30)), 10680 GregDay(-734_168, Date(-2010, 12, 1)), 10681 GregDay(-734_139, Date(-2010, 12, 30)), 10682 GregDay(-734_138, Date(-2010, 12, 31)), 10683 GregDay(-731_215, Date(-2001, 1, 1)), 10684 GregDay(-730_850, Date(-2000, 1, 1)), 10685 GregDay(-730_849, Date(-2000, 1, 2)), 10686 GregDay(-730_486, Date(-2000, 12, 30)), 10687 GregDay(-730_485, Date(-2000, 12, 31)), 10688 GregDay(-730_484, Date(-1999, 1, 1)), 10689 GregDay(-694_690, Date(-1901, 1, 1)), 10690 GregDay(-694_325, Date(-1900, 1, 1)), 10691 GregDay(-585_118, Date(-1601, 1, 1)), 10692 GregDay(-584_753, Date(-1600, 1, 1)), 10693 GregDay(-584_388, Date(-1600, 12, 31)), 10694 GregDay(-584_387, Date(-1599, 1, 1)), 10695 GregDay(-365_972, Date(-1001, 1, 1)), 10696 GregDay(-365_607, Date(-1000, 1, 1)), 10697 GregDay(-183_351, Date(-501, 1, 1)), 10698 GregDay(-182_986, Date(-500, 1, 1)), 10699 GregDay(-182_621, Date(-499, 1, 1)), 10700 GregDay(-146_827, Date(-401, 1, 1)), 10701 GregDay(-146_462, Date(-400, 1, 1)), 10702 GregDay(-146_097, Date(-400, 12, 31)), 10703 GregDay(-110_302, Date(-301, 1, 1)), 10704 GregDay(-109_937, Date(-300, 1, 1)), 10705 GregDay(-73_778, Date(-201, 1, 1)), 10706 GregDay(-73_413, Date(-200, 1, 1)), 10707 GregDay(-38_715, Date(-105, 1, 1)), 10708 GregDay(-37_254, Date(-101, 1, 1)), 10709 GregDay(-36_889, Date(-100, 1, 1)), 10710 GregDay(-36_524, Date(-99, 1, 1)), 10711 GregDay(-36_160, Date(-99, 12, 31)), 10712 GregDay(-35_794, Date(-97, 1, 1)), 10713 GregDay(-18_627, Date(-50, 1, 1)), 10714 GregDay(-18_262, Date(-49, 1, 1)), 10715 GregDay(-3652, Date(-9, 1, 1)), 10716 GregDay(-2191, Date(-5, 1, 1)), 10717 GregDay(-1827, Date(-5, 12, 31)), 10718 GregDay(-1826, Date(-4, 1, 1)), 10719 GregDay(-1825, Date(-4, 1, 2)), 10720 GregDay(-1462, Date(-4, 12, 30)), 10721 GregDay(-1461, Date(-4, 12, 31)), 10722 GregDay(-1460, Date(-3, 1, 1)), 10723 GregDay(-1096, Date(-3, 12, 31)), 10724 GregDay(-1095, Date(-2, 1, 1)), 10725 GregDay(-731, Date(-2, 12, 31)), 10726 GregDay(-730, Date(-1, 1, 1)), 10727 GregDay(-367, Date(-1, 12, 30)), 10728 GregDay(-366, Date(-1, 12, 31)), 10729 GregDay(-365, Date(0, 1, 1)), 10730 GregDay(-31, Date(0, 11, 30)), 10731 GregDay(-30, Date(0, 12, 1)), 10732 GregDay(-1, Date(0, 12, 30)), 10733 GregDay(0, Date(0, 12, 31))]; 10734 return result; 10735 } 10736 10737 GregDay[] testGregDaysAD() 10738 { 10739 static result = [GregDay(1, Date(1, 1, 1)), 10740 GregDay(2, Date(1, 1, 2)), 10741 GregDay(32, Date(1, 2, 1)), 10742 GregDay(365, Date(1, 12, 31)), 10743 GregDay(366, Date(2, 1, 1)), 10744 GregDay(731, Date(3, 1, 1)), 10745 GregDay(1096, Date(4, 1, 1)), 10746 GregDay(1097, Date(4, 1, 2)), 10747 GregDay(1460, Date(4, 12, 30)), 10748 GregDay(1461, Date(4, 12, 31)), 10749 GregDay(1462, Date(5, 1, 1)), 10750 GregDay(17_898, Date(50, 1, 1)), 10751 GregDay(35_065, Date(97, 1, 1)), 10752 GregDay(36_160, Date(100, 1, 1)), 10753 GregDay(36_525, Date(101, 1, 1)), 10754 GregDay(37_986, Date(105, 1, 1)), 10755 GregDay(72_684, Date(200, 1, 1)), 10756 GregDay(73_049, Date(201, 1, 1)), 10757 GregDay(109_208, Date(300, 1, 1)), 10758 GregDay(109_573, Date(301, 1, 1)), 10759 GregDay(145_732, Date(400, 1, 1)), 10760 GregDay(146_098, Date(401, 1, 1)), 10761 GregDay(182_257, Date(500, 1, 1)), 10762 GregDay(182_622, Date(501, 1, 1)), 10763 GregDay(364_878, Date(1000, 1, 1)), 10764 GregDay(365_243, Date(1001, 1, 1)), 10765 GregDay(584_023, Date(1600, 1, 1)), 10766 GregDay(584_389, Date(1601, 1, 1)), 10767 GregDay(693_596, Date(1900, 1, 1)), 10768 GregDay(693_961, Date(1901, 1, 1)), 10769 GregDay(729_755, Date(1999, 1, 1)), 10770 GregDay(730_120, Date(2000, 1, 1)), 10771 GregDay(730_121, Date(2000, 1, 2)), 10772 GregDay(730_484, Date(2000, 12, 30)), 10773 GregDay(730_485, Date(2000, 12, 31)), 10774 GregDay(730_486, Date(2001, 1, 1)), 10775 GregDay(733_773, Date(2010, 1, 1)), 10776 GregDay(733_774, Date(2010, 1, 2)), 10777 GregDay(733_803, Date(2010, 1, 31)), 10778 GregDay(733_804, Date(2010, 2, 1)), 10779 GregDay(733_831, Date(2010, 2, 28)), 10780 GregDay(733_832, Date(2010, 3, 1)), 10781 GregDay(733_862, Date(2010, 3, 31)), 10782 GregDay(733_863, Date(2010, 4, 1)), 10783 GregDay(733_892, Date(2010, 4, 30)), 10784 GregDay(733_893, Date(2010, 5, 1)), 10785 GregDay(733_923, Date(2010, 5, 31)), 10786 GregDay(733_924, Date(2010, 6, 1)), 10787 GregDay(733_953, Date(2010, 6, 30)), 10788 GregDay(733_954, Date(2010, 7, 1)), 10789 GregDay(733_984, Date(2010, 7, 31)), 10790 GregDay(733_985, Date(2010, 8, 1)), 10791 GregDay(734_015, Date(2010, 8, 31)), 10792 GregDay(734_016, Date(2010, 9, 1)), 10793 GregDay(734_045, Date(2010, 9, 30)), 10794 GregDay(734_046, Date(2010, 10, 1)), 10795 GregDay(734_076, Date(2010, 10, 31)), 10796 GregDay(734_077, Date(2010, 11, 1)), 10797 GregDay(734_106, Date(2010, 11, 30)), 10798 GregDay(734_107, Date(2010, 12, 1)), 10799 GregDay(734_136, Date(2010, 12, 30)), 10800 GregDay(734_137, Date(2010, 12, 31)), 10801 GregDay(734_503, Date(2012, 1, 1)), 10802 GregDay(734_534, Date(2012, 2, 1)), 10803 GregDay(734_561, Date(2012, 2, 28)), 10804 GregDay(734_562, Date(2012, 2, 29)), 10805 GregDay(734_563, Date(2012, 3, 1)), 10806 GregDay(734_858, Date(2012, 12, 21))]; 10807 return result; 10808 } 10809 10810 // I'd use a Tuple, but I get forward reference errors if I try. 10811 struct DayOfYear { int day; MonthDay md; } 10812 DayOfYear[] testDaysOfYear() 10813 { 10814 static result = [DayOfYear(1, MonthDay(1, 1)), 10815 DayOfYear(2, MonthDay(1, 2)), 10816 DayOfYear(3, MonthDay(1, 3)), 10817 DayOfYear(31, MonthDay(1, 31)), 10818 DayOfYear(32, MonthDay(2, 1)), 10819 DayOfYear(59, MonthDay(2, 28)), 10820 DayOfYear(60, MonthDay(3, 1)), 10821 DayOfYear(90, MonthDay(3, 31)), 10822 DayOfYear(91, MonthDay(4, 1)), 10823 DayOfYear(120, MonthDay(4, 30)), 10824 DayOfYear(121, MonthDay(5, 1)), 10825 DayOfYear(151, MonthDay(5, 31)), 10826 DayOfYear(152, MonthDay(6, 1)), 10827 DayOfYear(181, MonthDay(6, 30)), 10828 DayOfYear(182, MonthDay(7, 1)), 10829 DayOfYear(212, MonthDay(7, 31)), 10830 DayOfYear(213, MonthDay(8, 1)), 10831 DayOfYear(243, MonthDay(8, 31)), 10832 DayOfYear(244, MonthDay(9, 1)), 10833 DayOfYear(273, MonthDay(9, 30)), 10834 DayOfYear(274, MonthDay(10, 1)), 10835 DayOfYear(304, MonthDay(10, 31)), 10836 DayOfYear(305, MonthDay(11, 1)), 10837 DayOfYear(334, MonthDay(11, 30)), 10838 DayOfYear(335, MonthDay(12, 1)), 10839 DayOfYear(363, MonthDay(12, 29)), 10840 DayOfYear(364, MonthDay(12, 30)), 10841 DayOfYear(365, MonthDay(12, 31))]; 10842 return result; 10843 } 10844 10845 DayOfYear[] testDaysOfLeapYear() 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(2, 29)), 10854 DayOfYear(61, MonthDay(3, 1)), 10855 DayOfYear(91, MonthDay(3, 31)), 10856 DayOfYear(92, MonthDay(4, 1)), 10857 DayOfYear(121, MonthDay(4, 30)), 10858 DayOfYear(122, MonthDay(5, 1)), 10859 DayOfYear(152, MonthDay(5, 31)), 10860 DayOfYear(153, MonthDay(6, 1)), 10861 DayOfYear(182, MonthDay(6, 30)), 10862 DayOfYear(183, MonthDay(7, 1)), 10863 DayOfYear(213, MonthDay(7, 31)), 10864 DayOfYear(214, MonthDay(8, 1)), 10865 DayOfYear(244, MonthDay(8, 31)), 10866 DayOfYear(245, MonthDay(9, 1)), 10867 DayOfYear(274, MonthDay(9, 30)), 10868 DayOfYear(275, MonthDay(10, 1)), 10869 DayOfYear(305, MonthDay(10, 31)), 10870 DayOfYear(306, MonthDay(11, 1)), 10871 DayOfYear(335, MonthDay(11, 30)), 10872 DayOfYear(336, MonthDay(12, 1)), 10873 DayOfYear(364, MonthDay(12, 29)), 10874 DayOfYear(365, MonthDay(12, 30)), 10875 DayOfYear(366, MonthDay(12, 31))]; 10876 return result; 10877 } 10878 10879 void initializeTests() 10880 { 10881 foreach (year; testYearsBC) 10882 { 10883 foreach (md; testMonthDays) 10884 testDatesBC ~= Date(year, md.month, md.day); 10885 } 10886 10887 foreach (year; testYearsAD) 10888 { 10889 foreach (md; testMonthDays) 10890 testDatesAD ~= Date(year, md.month, md.day); 10891 } 10892 10893 foreach (dt; testDatesBC) 10894 { 10895 foreach (tod; testTODs) 10896 testDateTimesBC ~= DateTime(dt, tod); 10897 } 10898 10899 foreach (dt; testDatesAD) 10900 { 10901 foreach (tod; testTODs) 10902 testDateTimesAD ~= DateTime(dt, tod); 10903 } 10904 } 10905 }