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