1 // Written in the D programming language 2 3 /++ 4 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 5 Authors: Jonathan M Davis 6 Source: $(PHOBOSSRC std/datetime/_date.d) 7 +/ 8 module std.datetime.date; 9 10 import core.time; 11 import std.traits : isSomeString, Unqual; 12 import std.typecons : Flag; 13 14 version (unittest) import std.exception : assertThrown; 15 16 17 @safe unittest 18 { 19 initializeTests(); 20 } 21 22 23 /++ 24 Exception type used by std.datetime. It's an alias to 25 $(REF TimeException,core,time). Either can be caught without concern about 26 which module it came from. 27 +/ 28 alias DateTimeException = TimeException; 29 30 31 /++ 32 Represents the 12 months of the Gregorian year (January is 1). 33 +/ 34 enum Month : ubyte 35 { 36 jan = 1, /// 37 feb, /// 38 mar, /// 39 apr, /// 40 may, /// 41 jun, /// 42 jul, /// 43 aug, /// 44 sep, /// 45 oct, /// 46 nov, /// 47 dec /// 48 } 49 50 51 /++ 52 Represents the 7 days of the Gregorian week (Sunday is 0). 53 +/ 54 enum DayOfWeek : ubyte 55 { 56 sun = 0, /// 57 mon, /// 58 tue, /// 59 wed, /// 60 thu, /// 61 fri, /// 62 sat /// 63 } 64 65 66 /++ 67 In some date calculations, adding months or years can cause the date to fall 68 on a day of the month which is not valid (e.g. February 29th 2001 or 69 June 31st 2000). If overflow is allowed (as is the default), then the month 70 will be incremented accordingly (so, February 29th 2001 would become 71 March 1st 2001, and June 31st 2000 would become July 1st 2000). If overflow 72 is not allowed, then the day will be adjusted to the last valid day in that 73 month (so, February 29th 2001 would become February 28th 2001 and 74 June 31st 2000 would become June 30th 2000). 75 76 AllowDayOverflow only applies to calculations involving months or years. 77 78 If set to $(D AllowDayOverflow.no), then day overflow is not allowed. 79 80 Otherwise, if set to $(D AllowDayOverflow.yes), then day overflow is 81 allowed. 82 +/ 83 alias AllowDayOverflow = Flag!"allowDayOverflow"; 84 85 86 /++ 87 Array of the strings representing time units, starting with the smallest 88 unit and going to the largest. It does not include $(D "nsecs"). 89 90 Includes $(D "hnsecs") (hecto-nanoseconds (100 ns)), 91 $(D "usecs") (microseconds), $(D "msecs") (milliseconds), $(D "seconds"), 92 $(D "minutes"), $(D "hours"), $(D "days"), $(D "weeks"), $(D "months"), and 93 $(D "years") 94 +/ 95 immutable string[] timeStrings = ["hnsecs", "usecs", "msecs", "seconds", "minutes", 96 "hours", "days", "weeks", "months", "years"]; 97 98 99 /++ 100 Combines the $(REF Date,std,datetime,date) and 101 $(REF TimeOfDay,std,datetime,date) structs to give an object which holds 102 both the date and the time. It is optimized for calendar-based operations and 103 has no concept of time zone. For an object which is optimized for time 104 operations based on the system time, use $(REF SysTime,std,datetime,systime). 105 $(REF SysTime,std,datetime,systime) has a concept of time zone and has much 106 higher precision (hnsecs). $(D DateTime) is intended primarily for 107 calendar-based uses rather than precise time operations. 108 +/ 109 struct DateTime 110 { 111 public: 112 113 /++ 114 Params: 115 date = The date portion of $(LREF DateTime). 116 tod = The time portion of $(LREF DateTime). 117 +/ 118 this(in Date date, in TimeOfDay tod = TimeOfDay.init) @safe pure nothrow @nogc 119 { 120 _date = date; 121 _tod = tod; 122 } 123 124 @safe unittest 125 { 126 { 127 auto dt = DateTime.init; 128 assert(dt._date == Date.init); 129 assert(dt._tod == TimeOfDay.init); 130 } 131 132 { 133 auto dt = DateTime(Date(1999, 7 ,6)); 134 assert(dt._date == Date(1999, 7, 6)); 135 assert(dt._tod == TimeOfDay.init); 136 } 137 138 { 139 auto dt = DateTime(Date(1999, 7 ,6), TimeOfDay(12, 30, 33)); 140 assert(dt._date == Date(1999, 7, 6)); 141 assert(dt._tod == TimeOfDay(12, 30, 33)); 142 } 143 } 144 145 146 /++ 147 Params: 148 year = The year portion of the date. 149 month = The month portion of the date (January is 1). 150 day = The day portion of the date. 151 hour = The hour portion of the time; 152 minute = The minute portion of the time; 153 second = The second portion of the time; 154 +/ 155 this(int year, int month, int day, int hour = 0, int minute = 0, int second = 0) @safe pure 156 { 157 _date = Date(year, month, day); 158 _tod = TimeOfDay(hour, minute, second); 159 } 160 161 @safe unittest 162 { 163 { 164 auto dt = DateTime(1999, 7 ,6); 165 assert(dt._date == Date(1999, 7, 6)); 166 assert(dt._tod == TimeOfDay.init); 167 } 168 169 { 170 auto dt = DateTime(1999, 7 ,6, 12, 30, 33); 171 assert(dt._date == Date(1999, 7, 6)); 172 assert(dt._tod == TimeOfDay(12, 30, 33)); 173 } 174 } 175 176 177 /++ 178 Compares this $(LREF DateTime) with the given $(D DateTime.). 179 180 Returns: 181 $(BOOKTABLE, 182 $(TR $(TD this < rhs) $(TD < 0)) 183 $(TR $(TD this == rhs) $(TD 0)) 184 $(TR $(TD this > rhs) $(TD > 0)) 185 ) 186 +/ 187 int opCmp(in DateTime rhs) const @safe pure nothrow @nogc 188 { 189 immutable dateResult = _date.opCmp(rhs._date); 190 191 if (dateResult != 0) 192 return dateResult; 193 194 return _tod.opCmp(rhs._tod); 195 } 196 197 @safe unittest 198 { 199 // Test A.D. 200 assert(DateTime(Date.init, TimeOfDay.init).opCmp(DateTime.init) == 0); 201 202 assert(DateTime(Date(1999, 1, 1)).opCmp(DateTime(Date(1999, 1, 1))) == 0); 203 assert(DateTime(Date(1, 7, 1)).opCmp(DateTime(Date(1, 7, 1))) == 0); 204 assert(DateTime(Date(1, 1, 6)).opCmp(DateTime(Date(1, 1, 6))) == 0); 205 206 assert(DateTime(Date(1999, 7, 1)).opCmp(DateTime(Date(1999, 7, 1))) == 0); 207 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) == 0); 208 209 assert(DateTime(Date(1, 7, 6)).opCmp(DateTime(Date(1, 7, 6))) == 0); 210 211 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(2000, 7, 6))) < 0); 212 assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); 213 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 8, 6))) < 0); 214 assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 6))) > 0); 215 assert(DateTime(Date(1999, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) < 0); 216 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 7, 6))) > 0); 217 218 assert(DateTime(Date(1999, 8, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); 219 assert(DateTime(Date(2000, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); 220 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(2000, 7, 6))) < 0); 221 assert(DateTime(Date(2000, 7, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); 222 assert(DateTime(Date(1999, 7, 7)).opCmp(DateTime(Date(1999, 8, 6))) < 0); 223 assert(DateTime(Date(1999, 8, 6)).opCmp(DateTime(Date(1999, 7, 7))) > 0); 224 225 226 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).opCmp( 227 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))) == 0); 228 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)).opCmp( 229 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))) == 0); 230 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0)).opCmp( 231 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 0))) == 0); 232 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( 233 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); 234 235 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)).opCmp( 236 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))) == 0); 237 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 238 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); 239 240 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)).opCmp( 241 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))) == 0); 242 assert(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)).opCmp( 243 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))) == 0); 244 245 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 246 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); 247 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 248 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 249 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 250 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); 251 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 252 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 253 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 254 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) < 0); 255 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 256 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 257 258 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 259 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); 260 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 261 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); 262 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 263 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); 264 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 265 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) < 0); 266 267 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 268 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); 269 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 270 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) < 0); 271 272 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 273 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); 274 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 275 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); 276 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 277 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); 278 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 279 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); 280 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 281 DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33))) < 0); 282 assert(DateTime(Date(2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 283 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); 284 285 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 286 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); 287 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 288 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); 289 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 290 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); 291 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 292 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))) > 0); 293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 294 DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); 295 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 296 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); 297 298 assert(DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33)).opCmp( 299 DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); 300 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 301 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))) > 0); 302 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)).opCmp( 303 DateTime(Date(1999, 7, 7), TimeOfDay(12, 31, 33))) < 0); 304 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 305 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 306 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)).opCmp( 307 DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); 308 assert(DateTime(Date(1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 309 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))) > 0); 310 311 // Test B.C. 312 assert(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)).opCmp( 313 DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33))) == 0); 314 assert(DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33)).opCmp( 315 DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))) == 0); 316 assert(DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33)).opCmp( 317 DateTime(Date(-1, 1, 6), TimeOfDay(12, 30, 33))) == 0); 318 319 assert(DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33)).opCmp( 320 DateTime(Date(-1999, 7, 1), TimeOfDay(12, 30, 33))) == 0); 321 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 322 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) == 0); 323 324 assert(DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 325 DateTime(Date(-1, 7, 6), TimeOfDay(12, 30, 33))) == 0); 326 327 assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 328 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); 329 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 330 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); 331 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 332 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); 333 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 334 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 335 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 336 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); 337 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 338 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 339 340 assert(DateTime(Date(-2000, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 341 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); 342 assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( 343 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); 344 assert(DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 345 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) < 0); 346 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 347 DateTime(Date(-2000, 7, 6), TimeOfDay(12, 30, 33))) > 0); 348 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 349 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) < 0); 350 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 351 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); 352 353 // Test Both 354 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 355 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); 356 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 357 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 358 359 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 360 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); 361 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 362 DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33))) > 0); 363 364 assert(DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33)).opCmp( 365 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); 366 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 367 DateTime(Date(-1999, 7, 7), TimeOfDay(12, 30, 33))) > 0); 368 369 assert(DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33)).opCmp( 370 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))) < 0); 371 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).opCmp( 372 DateTime(Date(-1999, 8, 7), TimeOfDay(12, 30, 33))) > 0); 373 374 assert(DateTime(Date(-1999, 8, 6), TimeOfDay(12, 30, 33)).opCmp( 375 DateTime(Date(1999, 6, 6), TimeOfDay(12, 30, 33))) < 0); 376 assert(DateTime(Date(1999, 6, 8), TimeOfDay(12, 30, 33)).opCmp( 377 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))) > 0); 378 379 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); 380 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); 381 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 30)); 382 assert(dt.opCmp(dt) == 0); 383 assert(dt.opCmp(cdt) == 0); 384 assert(dt.opCmp(idt) == 0); 385 assert(cdt.opCmp(dt) == 0); 386 assert(cdt.opCmp(cdt) == 0); 387 assert(cdt.opCmp(idt) == 0); 388 assert(idt.opCmp(dt) == 0); 389 assert(idt.opCmp(cdt) == 0); 390 assert(idt.opCmp(idt) == 0); 391 } 392 393 394 /++ 395 The date portion of $(LREF DateTime). 396 +/ 397 @property Date date() const @safe pure nothrow @nogc 398 { 399 return _date; 400 } 401 402 @safe unittest 403 { 404 { 405 auto dt = DateTime.init; 406 assert(dt.date == Date.init); 407 } 408 409 { 410 auto dt = DateTime(Date(1999, 7, 6)); 411 assert(dt.date == Date(1999, 7, 6)); 412 } 413 414 const cdt = DateTime(1999, 7, 6); 415 immutable idt = DateTime(1999, 7, 6); 416 assert(cdt.date == Date(1999, 7, 6)); 417 assert(idt.date == Date(1999, 7, 6)); 418 } 419 420 421 /++ 422 The date portion of $(LREF DateTime). 423 424 Params: 425 date = The Date to set this $(LREF DateTime)'s date portion to. 426 +/ 427 @property void date(in Date date) @safe pure nothrow @nogc 428 { 429 _date = date; 430 } 431 432 @safe unittest 433 { 434 auto dt = DateTime.init; 435 dt.date = Date(1999, 7, 6); 436 assert(dt._date == Date(1999, 7, 6)); 437 assert(dt._tod == TimeOfDay.init); 438 439 const cdt = DateTime(1999, 7, 6); 440 immutable idt = DateTime(1999, 7, 6); 441 static assert(!__traits(compiles, cdt.date = Date(2010, 1, 1))); 442 static assert(!__traits(compiles, idt.date = Date(2010, 1, 1))); 443 } 444 445 446 /++ 447 The time portion of $(LREF DateTime). 448 +/ 449 @property TimeOfDay timeOfDay() const @safe pure nothrow @nogc 450 { 451 return _tod; 452 } 453 454 @safe unittest 455 { 456 { 457 auto dt = DateTime.init; 458 assert(dt.timeOfDay == TimeOfDay.init); 459 } 460 461 { 462 auto dt = DateTime(Date.init, TimeOfDay(12, 30, 33)); 463 assert(dt.timeOfDay == TimeOfDay(12, 30, 33)); 464 } 465 466 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 467 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 468 assert(cdt.timeOfDay == TimeOfDay(12, 30, 33)); 469 assert(idt.timeOfDay == TimeOfDay(12, 30, 33)); 470 } 471 472 473 /++ 474 The time portion of $(LREF DateTime). 475 476 Params: 477 tod = The $(REF TimeOfDay,std,datetime,date) to set this 478 $(LREF DateTime)'s time portion to. 479 +/ 480 @property void timeOfDay(in TimeOfDay tod) @safe pure nothrow @nogc 481 { 482 _tod = tod; 483 } 484 485 @safe unittest 486 { 487 auto dt = DateTime.init; 488 dt.timeOfDay = TimeOfDay(12, 30, 33); 489 assert(dt._date == Date.init); 490 assert(dt._tod == TimeOfDay(12, 30, 33)); 491 492 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 493 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 494 static assert(!__traits(compiles, cdt.timeOfDay = TimeOfDay(12, 30, 33))); 495 static assert(!__traits(compiles, idt.timeOfDay = TimeOfDay(12, 30, 33))); 496 } 497 498 499 /++ 500 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 501 are B.C. 502 +/ 503 @property short year() const @safe pure nothrow @nogc 504 { 505 return _date.year; 506 } 507 508 @safe unittest 509 { 510 assert(Date.init.year == 1); 511 assert(Date(1999, 7, 6).year == 1999); 512 assert(Date(-1999, 7, 6).year == -1999); 513 514 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 515 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 516 assert(idt.year == 1999); 517 assert(idt.year == 1999); 518 } 519 520 521 /++ 522 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 523 are B.C. 524 525 Params: 526 year = The year to set this $(LREF DateTime)'s year to. 527 528 Throws: 529 $(REF DateTimeException,std,datetime,date) if the new year is not 530 a leap year and if the resulting date would be on February 29th. 531 +/ 532 @property void year(int year) @safe pure 533 { 534 _date.year = year; 535 } 536 537 /// 538 @safe unittest 539 { 540 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).year == 1999); 541 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).year == 2010); 542 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).year == -7); 543 } 544 545 @safe unittest 546 { 547 static void testDT(DateTime dt, int year, in DateTime expected, size_t line = __LINE__) 548 { 549 dt.year = year; 550 assert(dt == expected); 551 } 552 553 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 554 1999, 555 DateTime(Date(1999, 1, 1), TimeOfDay(12, 30, 33))); 556 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 557 0, 558 DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33))); 559 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 560 -1999, 561 DateTime(Date(-1999, 1, 1), TimeOfDay(12, 30, 33))); 562 563 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 564 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 565 static assert(!__traits(compiles, cdt.year = 7)); 566 static assert(!__traits(compiles, idt.year = 7)); 567 } 568 569 570 /++ 571 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 572 573 Throws: 574 $(REF DateTimeException,std,datetime,date) if $(D isAD) is true. 575 +/ 576 @property short yearBC() const @safe pure 577 { 578 return _date.yearBC; 579 } 580 581 /// 582 @safe unittest 583 { 584 assert(DateTime(Date(0, 1, 1), TimeOfDay(12, 30, 33)).yearBC == 1); 585 assert(DateTime(Date(-1, 1, 1), TimeOfDay(10, 7, 2)).yearBC == 2); 586 assert(DateTime(Date(-100, 1, 1), TimeOfDay(4, 59, 0)).yearBC == 101); 587 } 588 589 @safe unittest 590 { 591 assertThrown!DateTimeException((in DateTime dt){dt.yearBC;}(DateTime(Date(1, 1, 1)))); 592 593 auto dt = DateTime(1999, 7, 6, 12, 30, 33); 594 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 595 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 596 dt.yearBC = 12; 597 assert(dt.yearBC == 12); 598 static assert(!__traits(compiles, cdt.yearBC = 12)); 599 static assert(!__traits(compiles, idt.yearBC = 12)); 600 } 601 602 603 /++ 604 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 605 606 Params: 607 year = The year B.C. to set this $(LREF DateTime)'s year to. 608 609 Throws: 610 $(REF DateTimeException,std,datetime,date) if a non-positive value 611 is given. 612 +/ 613 @property void yearBC(int year) @safe pure 614 { 615 _date.yearBC = year; 616 } 617 618 /// 619 @safe unittest 620 { 621 auto dt = DateTime(Date(2010, 1, 1), TimeOfDay(7, 30, 0)); 622 dt.yearBC = 1; 623 assert(dt == DateTime(Date(0, 1, 1), TimeOfDay(7, 30, 0))); 624 625 dt.yearBC = 10; 626 assert(dt == DateTime(Date(-9, 1, 1), TimeOfDay(7, 30, 0))); 627 } 628 629 @safe unittest 630 { 631 assertThrown!DateTimeException((DateTime dt){dt.yearBC = -1;}(DateTime(Date(1, 1, 1)))); 632 633 auto dt = DateTime(1999, 7, 6, 12, 30, 33); 634 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 635 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 636 dt.yearBC = 12; 637 assert(dt.yearBC == 12); 638 static assert(!__traits(compiles, cdt.yearBC = 12)); 639 static assert(!__traits(compiles, idt.yearBC = 12)); 640 } 641 642 643 /++ 644 Month of a Gregorian Year. 645 +/ 646 @property Month month() const @safe pure nothrow @nogc 647 { 648 return _date.month; 649 } 650 651 /// 652 @safe unittest 653 { 654 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).month == 7); 655 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).month == 10); 656 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).month == 4); 657 } 658 659 @safe unittest 660 { 661 assert(DateTime.init.month == 1); 662 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); 663 assert(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)).month == 7); 664 665 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 666 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 667 assert(cdt.month == 7); 668 assert(idt.month == 7); 669 } 670 671 672 /++ 673 Month of a Gregorian Year. 674 675 Params: 676 month = The month to set this $(LREF DateTime)'s month to. 677 678 Throws: 679 $(REF DateTimeException,std,datetime,date) if the given month is 680 not a valid month. 681 +/ 682 @property void month(Month month) @safe pure 683 { 684 _date.month = month; 685 } 686 687 @safe unittest 688 { 689 static void testDT(DateTime dt, Month month, in DateTime expected = DateTime.init, size_t line = __LINE__) 690 { 691 dt.month = month; 692 assert(expected != DateTime.init); 693 assert(dt == expected); 694 } 695 696 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 0)); 697 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), cast(Month) 13)); 698 699 testDT(DateTime(Date(1, 1, 1), TimeOfDay(12, 30, 33)), 700 cast(Month) 7, 701 DateTime(Date(1, 7, 1), TimeOfDay(12, 30, 33))); 702 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(12, 30, 33)), 703 cast(Month) 7, 704 DateTime(Date(-1, 7, 1), TimeOfDay(12, 30, 33))); 705 706 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 707 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 708 static assert(!__traits(compiles, cdt.month = 12)); 709 static assert(!__traits(compiles, idt.month = 12)); 710 } 711 712 713 /++ 714 Day of a Gregorian Month. 715 +/ 716 @property ubyte day() const @safe pure nothrow @nogc 717 { 718 return _date.day; 719 } 720 721 /// 722 @safe unittest 723 { 724 assert(DateTime(Date(1999, 7, 6), TimeOfDay(9, 7, 5)).day == 6); 725 assert(DateTime(Date(2010, 10, 4), TimeOfDay(0, 0, 30)).day == 4); 726 assert(DateTime(Date(-7, 4, 5), TimeOfDay(7, 45, 2)).day == 5); 727 } 728 729 @safe unittest 730 { 731 import std.format : format; 732 import std.range : chain; 733 734 static void test(DateTime dateTime, int expected) 735 { 736 assert(dateTime.day == expected, format("Value given: %s", dateTime)); 737 } 738 739 foreach (year; chain(testYearsBC, testYearsAD)) 740 { 741 foreach (md; testMonthDays) 742 { 743 foreach (tod; testTODs) 744 test(DateTime(Date(year, md.month, md.day), tod), md.day); 745 } 746 } 747 748 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 749 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 750 assert(cdt.day == 6); 751 assert(idt.day == 6); 752 } 753 754 755 /++ 756 Day of a Gregorian Month. 757 758 Params: 759 day = The day of the month to set this $(LREF DateTime)'s day to. 760 761 Throws: 762 $(REF DateTimeException,std,datetime,date) if the given day is not 763 a valid day of the current month. 764 +/ 765 @property void day(int day) @safe pure 766 { 767 _date.day = day; 768 } 769 770 @safe unittest 771 { 772 import std.exception : assertNotThrown; 773 774 static void testDT(DateTime dt, int day) 775 { 776 dt.day = day; 777 } 778 779 // Test A.D. 780 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 0)); 781 assertThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 32)); 782 assertThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 29)); 783 assertThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 30)); 784 assertThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 32)); 785 assertThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 31)); 786 assertThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 32)); 787 assertThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 31)); 788 assertThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 32)); 789 assertThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 32)); 790 assertThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 31)); 791 assertThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 32)); 792 assertThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 31)); 793 assertThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 32)); 794 795 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 1, 1)), 31)); 796 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 2, 1)), 28)); 797 assertNotThrown!DateTimeException(testDT(DateTime(Date(4, 2, 1)), 29)); 798 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 3, 1)), 31)); 799 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 4, 1)), 30)); 800 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 5, 1)), 31)); 801 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 6, 1)), 30)); 802 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 7, 1)), 31)); 803 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 8, 1)), 31)); 804 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 9, 1)), 30)); 805 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 10, 1)), 31)); 806 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 11, 1)), 30)); 807 assertNotThrown!DateTimeException(testDT(DateTime(Date(1, 12, 1)), 31)); 808 809 { 810 auto dt = DateTime(Date(1, 1, 1), TimeOfDay(7, 12, 22)); 811 dt.day = 6; 812 assert(dt == DateTime(Date(1, 1, 6), TimeOfDay(7, 12, 22))); 813 } 814 815 // Test B.C. 816 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 0)); 817 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 32)); 818 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 29)); 819 assertThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 30)); 820 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 32)); 821 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 31)); 822 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 32)); 823 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 31)); 824 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 32)); 825 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 32)); 826 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 31)); 827 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 32)); 828 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 31)); 829 assertThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 32)); 830 831 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 1, 1)), 31)); 832 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 2, 1)), 28)); 833 assertNotThrown!DateTimeException(testDT(DateTime(Date(0, 2, 1)), 29)); 834 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 3, 1)), 31)); 835 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 4, 1)), 30)); 836 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 5, 1)), 31)); 837 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 6, 1)), 30)); 838 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 7, 1)), 31)); 839 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 8, 1)), 31)); 840 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 9, 1)), 30)); 841 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 10, 1)), 31)); 842 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 11, 1)), 30)); 843 assertNotThrown!DateTimeException(testDT(DateTime(Date(-1, 12, 1)), 31)); 844 845 auto dt = DateTime(Date(-1, 1, 1), TimeOfDay(7, 12, 22)); 846 dt.day = 6; 847 assert(dt == DateTime(Date(-1, 1, 6), TimeOfDay(7, 12, 22))); 848 849 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 850 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 851 static assert(!__traits(compiles, cdt.day = 27)); 852 static assert(!__traits(compiles, idt.day = 27)); 853 } 854 855 856 /++ 857 Hours past midnight. 858 +/ 859 @property ubyte hour() const @safe pure nothrow @nogc 860 { 861 return _tod.hour; 862 } 863 864 @safe unittest 865 { 866 assert(DateTime.init.hour == 0); 867 assert(DateTime(Date.init, TimeOfDay(12, 0, 0)).hour == 12); 868 869 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 870 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 871 assert(cdt.hour == 12); 872 assert(idt.hour == 12); 873 } 874 875 876 /++ 877 Hours past midnight. 878 879 Params: 880 hour = The hour of the day to set this $(LREF DateTime)'s hour to. 881 882 Throws: 883 $(REF DateTimeException,std,datetime,date) if the given hour would 884 result in an invalid $(LREF DateTime). 885 +/ 886 @property void hour(int hour) @safe pure 887 { 888 _tod.hour = hour; 889 } 890 891 @safe unittest 892 { 893 assertThrown!DateTimeException((){DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)).hour = 24;}()); 894 895 auto dt = DateTime.init; 896 dt.hour = 12; 897 assert(dt == DateTime(1, 1, 1, 12, 0, 0)); 898 899 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 900 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 901 static assert(!__traits(compiles, cdt.hour = 27)); 902 static assert(!__traits(compiles, idt.hour = 27)); 903 } 904 905 906 /++ 907 Minutes past the hour. 908 +/ 909 @property ubyte minute() const @safe pure nothrow @nogc 910 { 911 return _tod.minute; 912 } 913 914 @safe unittest 915 { 916 assert(DateTime.init.minute == 0); 917 assert(DateTime(1, 1, 1, 0, 30, 0).minute == 30); 918 919 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 920 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 921 assert(cdt.minute == 30); 922 assert(idt.minute == 30); 923 } 924 925 926 /++ 927 Minutes past the hour. 928 929 Params: 930 minute = The minute to set this $(LREF DateTime)'s minute to. 931 932 Throws: 933 $(REF DateTimeException,std,datetime,date) if the given minute 934 would result in an invalid $(LREF DateTime). 935 +/ 936 @property void minute(int minute) @safe pure 937 { 938 _tod.minute = minute; 939 } 940 941 @safe unittest 942 { 943 assertThrown!DateTimeException((){DateTime.init.minute = 60;}()); 944 945 auto dt = DateTime.init; 946 dt.minute = 30; 947 assert(dt == DateTime(1, 1, 1, 0, 30, 0)); 948 949 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 950 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 951 static assert(!__traits(compiles, cdt.minute = 27)); 952 static assert(!__traits(compiles, idt.minute = 27)); 953 } 954 955 956 /++ 957 Seconds past the minute. 958 +/ 959 @property ubyte second() const @safe pure nothrow @nogc 960 { 961 return _tod.second; 962 } 963 964 @safe unittest 965 { 966 assert(DateTime.init.second == 0); 967 assert(DateTime(1, 1, 1, 0, 0, 33).second == 33); 968 969 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 970 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 971 assert(cdt.second == 33); 972 assert(idt.second == 33); 973 } 974 975 976 /++ 977 Seconds past the minute. 978 979 Params: 980 second = The second to set this $(LREF DateTime)'s second to. 981 982 Throws: 983 $(REF DateTimeException,std,datetime,date) if the given seconds 984 would result in an invalid $(LREF DateTime). 985 +/ 986 @property void second(int second) @safe pure 987 { 988 _tod.second = second; 989 } 990 991 @safe unittest 992 { 993 assertThrown!DateTimeException((){DateTime.init.second = 60;}()); 994 995 auto dt = DateTime.init; 996 dt.second = 33; 997 assert(dt == DateTime(1, 1, 1, 0, 0, 33)); 998 999 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1000 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1001 static assert(!__traits(compiles, cdt.second = 27)); 1002 static assert(!__traits(compiles, idt.second = 27)); 1003 } 1004 1005 1006 /++ 1007 Adds the given number of years or months to this $(LREF DateTime). A 1008 negative number will subtract. 1009 1010 Note that if day overflow is allowed, and the date with the adjusted 1011 year/month overflows the number of days in the new month, then the month 1012 will be incremented by one, and the day set to the number of days 1013 overflowed. (e.g. if the day were 31 and the new month were June, then 1014 the month would be incremented to July, and the new day would be 1). If 1015 day overflow is not allowed, then the day will be set to the last valid 1016 day in the month (e.g. June 31st would become June 30th). 1017 1018 Params: 1019 units = The type of units to add ("years" or "months"). 1020 value = The number of months or years to add to this 1021 $(LREF DateTime). 1022 allowOverflow = Whether the days should be allowed to overflow, 1023 causing the month to increment. 1024 +/ 1025 ref DateTime add(string units) 1026 (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc 1027 if (units == "years" || units == "months") 1028 { 1029 _date.add!units(value, allowOverflow); 1030 return this; 1031 } 1032 1033 /// 1034 @safe unittest 1035 { 1036 auto dt1 = DateTime(2010, 1, 1, 12, 30, 33); 1037 dt1.add!"months"(11); 1038 assert(dt1 == DateTime(2010, 12, 1, 12, 30, 33)); 1039 1040 auto dt2 = DateTime(2010, 1, 1, 12, 30, 33); 1041 dt2.add!"months"(-11); 1042 assert(dt2 == DateTime(2009, 2, 1, 12, 30, 33)); 1043 1044 auto dt3 = DateTime(2000, 2, 29, 12, 30, 33); 1045 dt3.add!"years"(1); 1046 assert(dt3 == DateTime(2001, 3, 1, 12, 30, 33)); 1047 1048 auto dt4 = DateTime(2000, 2, 29, 12, 30, 33); 1049 dt4.add!"years"(1, AllowDayOverflow.no); 1050 assert(dt4 == DateTime(2001, 2, 28, 12, 30, 33)); 1051 } 1052 1053 @safe unittest 1054 { 1055 auto dt = DateTime(2000, 1, 31); 1056 dt.add!"years"(7).add!"months"(-4); 1057 assert(dt == DateTime(2006, 10, 1)); 1058 1059 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1060 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1061 static assert(!__traits(compiles, cdt.add!"years"(4))); 1062 static assert(!__traits(compiles, idt.add!"years"(4))); 1063 static assert(!__traits(compiles, cdt.add!"months"(4))); 1064 static assert(!__traits(compiles, idt.add!"months"(4))); 1065 } 1066 1067 1068 /++ 1069 Adds the given number of years or months to this $(LREF DateTime). A 1070 negative number will subtract. 1071 1072 The difference between rolling and adding is that rolling does not 1073 affect larger units. Rolling a $(LREF DateTime) 12 months 1074 gets the exact same $(LREF DateTime). However, the days can still be 1075 affected due to the differing number of days in each month. 1076 1077 Because there are no units larger than years, there is no difference 1078 between adding and rolling years. 1079 1080 Params: 1081 units = The type of units to add ("years" or "months"). 1082 value = The number of months or years to add to this 1083 $(LREF DateTime). 1084 allowOverflow = Whether the days should be allowed to overflow, 1085 causing the month to increment. 1086 +/ 1087 ref DateTime roll(string units) 1088 (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc 1089 if (units == "years" || units == "months") 1090 { 1091 _date.roll!units(value, allowOverflow); 1092 return this; 1093 } 1094 1095 /// 1096 @safe unittest 1097 { 1098 auto dt1 = DateTime(2010, 1, 1, 12, 33, 33); 1099 dt1.roll!"months"(1); 1100 assert(dt1 == DateTime(2010, 2, 1, 12, 33, 33)); 1101 1102 auto dt2 = DateTime(2010, 1, 1, 12, 33, 33); 1103 dt2.roll!"months"(-1); 1104 assert(dt2 == DateTime(2010, 12, 1, 12, 33, 33)); 1105 1106 auto dt3 = DateTime(1999, 1, 29, 12, 33, 33); 1107 dt3.roll!"months"(1); 1108 assert(dt3 == DateTime(1999, 3, 1, 12, 33, 33)); 1109 1110 auto dt4 = DateTime(1999, 1, 29, 12, 33, 33); 1111 dt4.roll!"months"(1, AllowDayOverflow.no); 1112 assert(dt4 == DateTime(1999, 2, 28, 12, 33, 33)); 1113 1114 auto dt5 = DateTime(2000, 2, 29, 12, 30, 33); 1115 dt5.roll!"years"(1); 1116 assert(dt5 == DateTime(2001, 3, 1, 12, 30, 33)); 1117 1118 auto dt6 = DateTime(2000, 2, 29, 12, 30, 33); 1119 dt6.roll!"years"(1, AllowDayOverflow.no); 1120 assert(dt6 == DateTime(2001, 2, 28, 12, 30, 33)); 1121 } 1122 1123 @safe unittest 1124 { 1125 auto dt = DateTime(2000, 1, 31); 1126 dt.roll!"years"(7).roll!"months"(-4); 1127 assert(dt == DateTime(2007, 10, 1)); 1128 1129 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1130 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1131 static assert(!__traits(compiles, cdt.roll!"years"(4))); 1132 static assert(!__traits(compiles, idt.roll!"years"(4))); 1133 static assert(!__traits(compiles, cdt.roll!"months"(4))); 1134 static assert(!__traits(compiles, idt.roll!"months"(4))); 1135 } 1136 1137 1138 /++ 1139 Adds the given number of units to this $(LREF DateTime). A negative 1140 number will subtract. 1141 1142 The difference between rolling and adding is that rolling does not 1143 affect larger units. For instance, rolling a $(LREF DateTime) one 1144 year's worth of days gets the exact same $(LREF DateTime). 1145 1146 Accepted units are $(D "days"), $(D "minutes"), $(D "hours"), 1147 $(D "minutes"), and $(D "seconds"). 1148 1149 Params: 1150 units = The units to add. 1151 value = The number of $(D_PARAM units) to add to this 1152 $(LREF DateTime). 1153 +/ 1154 ref DateTime roll(string units)(long value) @safe pure nothrow @nogc 1155 if (units == "days") 1156 { 1157 _date.roll!"days"(value); 1158 return this; 1159 } 1160 1161 /// 1162 @safe unittest 1163 { 1164 auto dt1 = DateTime(2010, 1, 1, 11, 23, 12); 1165 dt1.roll!"days"(1); 1166 assert(dt1 == DateTime(2010, 1, 2, 11, 23, 12)); 1167 dt1.roll!"days"(365); 1168 assert(dt1 == DateTime(2010, 1, 26, 11, 23, 12)); 1169 dt1.roll!"days"(-32); 1170 assert(dt1 == DateTime(2010, 1, 25, 11, 23, 12)); 1171 1172 auto dt2 = DateTime(2010, 7, 4, 12, 0, 0); 1173 dt2.roll!"hours"(1); 1174 assert(dt2 == DateTime(2010, 7, 4, 13, 0, 0)); 1175 1176 auto dt3 = DateTime(2010, 1, 1, 0, 0, 0); 1177 dt3.roll!"seconds"(-1); 1178 assert(dt3 == DateTime(2010, 1, 1, 0, 0, 59)); 1179 } 1180 1181 @safe unittest 1182 { 1183 auto dt = DateTime(2000, 1, 31); 1184 dt.roll!"days"(7).roll!"days"(-4); 1185 assert(dt == DateTime(2000, 1, 3)); 1186 1187 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1188 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1189 static assert(!__traits(compiles, cdt.roll!"days"(4))); 1190 static assert(!__traits(compiles, idt.roll!"days"(4))); 1191 } 1192 1193 1194 // Shares documentation with "days" version. 1195 ref DateTime roll(string units)(long value) @safe pure nothrow @nogc 1196 if (units == "hours" || 1197 units == "minutes" || 1198 units == "seconds") 1199 { 1200 _tod.roll!units(value); 1201 return this; 1202 } 1203 1204 // Test roll!"hours"(). 1205 @safe unittest 1206 { 1207 static void testDT(DateTime orig, int hours, in DateTime expected, size_t line = __LINE__) 1208 { 1209 orig.roll!"hours"(hours); 1210 assert(orig == expected); 1211 } 1212 1213 // Test A.D. 1214 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1215 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1216 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1217 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); 1218 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1219 DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); 1220 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1221 DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); 1222 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1223 DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); 1224 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1225 DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); 1226 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 6, 1227 DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); 1228 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7, 1229 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 1230 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 8, 1231 DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); 1232 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 9, 1233 DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); 1234 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1235 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); 1236 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 11, 1237 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); 1238 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 12, 1239 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); 1240 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 13, 1241 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); 1242 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 14, 1243 DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); 1244 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1245 DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); 1246 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 16, 1247 DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); 1248 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 17, 1249 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 1250 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 18, 1251 DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); 1252 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 19, 1253 DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); 1254 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 20, 1255 DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); 1256 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 21, 1257 DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); 1258 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 22, 1259 DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); 1260 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 23, 1261 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); 1262 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 24, 1263 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1264 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 25, 1265 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); 1266 1267 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1268 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); 1269 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1270 DateTime(Date(1999, 7, 6), TimeOfDay(10, 30, 33))); 1271 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1272 DateTime(Date(1999, 7, 6), TimeOfDay(9, 30, 33))); 1273 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1274 DateTime(Date(1999, 7, 6), TimeOfDay(8, 30, 33))); 1275 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1276 DateTime(Date(1999, 7, 6), TimeOfDay(7, 30, 33))); 1277 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -6, 1278 DateTime(Date(1999, 7, 6), TimeOfDay(6, 30, 33))); 1279 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -7, 1280 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 1281 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -8, 1282 DateTime(Date(1999, 7, 6), TimeOfDay(4, 30, 33))); 1283 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -9, 1284 DateTime(Date(1999, 7, 6), TimeOfDay(3, 30, 33))); 1285 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1286 DateTime(Date(1999, 7, 6), TimeOfDay(2, 30, 33))); 1287 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -11, 1288 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); 1289 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -12, 1290 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); 1291 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -13, 1292 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); 1293 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -14, 1294 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); 1295 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1296 DateTime(Date(1999, 7, 6), TimeOfDay(21, 30, 33))); 1297 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -16, 1298 DateTime(Date(1999, 7, 6), TimeOfDay(20, 30, 33))); 1299 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -17, 1300 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 1301 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -18, 1302 DateTime(Date(1999, 7, 6), TimeOfDay(18, 30, 33))); 1303 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -19, 1304 DateTime(Date(1999, 7, 6), TimeOfDay(17, 30, 33))); 1305 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -20, 1306 DateTime(Date(1999, 7, 6), TimeOfDay(16, 30, 33))); 1307 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -21, 1308 DateTime(Date(1999, 7, 6), TimeOfDay(15, 30, 33))); 1309 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -22, 1310 DateTime(Date(1999, 7, 6), TimeOfDay(14, 30, 33))); 1311 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -23, 1312 DateTime(Date(1999, 7, 6), TimeOfDay(13, 30, 33))); 1313 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -24, 1314 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1315 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -25, 1316 DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33))); 1317 1318 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 1, 1319 DateTime(Date(1999, 7, 6), TimeOfDay(1, 30, 33))); 1320 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), 0, 1321 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); 1322 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33)), -1, 1323 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); 1324 1325 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 1, 1326 DateTime(Date(1999, 7, 6), TimeOfDay(0, 30, 33))); 1327 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), 0, 1328 DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33))); 1329 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(23, 30, 33)), -1, 1330 DateTime(Date(1999, 7, 6), TimeOfDay(22, 30, 33))); 1331 1332 testDT(DateTime(Date(1999, 7, 31), TimeOfDay(23, 30, 33)), 1, 1333 DateTime(Date(1999, 7, 31), TimeOfDay(0, 30, 33))); 1334 testDT(DateTime(Date(1999, 8, 1), TimeOfDay(0, 30, 33)), -1, 1335 DateTime(Date(1999, 8, 1), TimeOfDay(23, 30, 33))); 1336 1337 testDT(DateTime(Date(1999, 12, 31), TimeOfDay(23, 30, 33)), 1, 1338 DateTime(Date(1999, 12, 31), TimeOfDay(0, 30, 33))); 1339 testDT(DateTime(Date(2000, 1, 1), TimeOfDay(0, 30, 33)), -1, 1340 DateTime(Date(2000, 1, 1), TimeOfDay(23, 30, 33))); 1341 1342 testDT(DateTime(Date(1999, 2, 28), TimeOfDay(23, 30, 33)), 25, 1343 DateTime(Date(1999, 2, 28), TimeOfDay(0, 30, 33))); 1344 testDT(DateTime(Date(1999, 3, 2), TimeOfDay(0, 30, 33)), -25, 1345 DateTime(Date(1999, 3, 2), TimeOfDay(23, 30, 33))); 1346 1347 testDT(DateTime(Date(2000, 2, 28), TimeOfDay(23, 30, 33)), 25, 1348 DateTime(Date(2000, 2, 28), TimeOfDay(0, 30, 33))); 1349 testDT(DateTime(Date(2000, 3, 1), TimeOfDay(0, 30, 33)), -25, 1350 DateTime(Date(2000, 3, 1), TimeOfDay(23, 30, 33))); 1351 1352 // Test B.C. 1353 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1354 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1355 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1356 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); 1357 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1358 DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); 1359 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1360 DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); 1361 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1362 DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); 1363 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1364 DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); 1365 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 6, 1366 DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); 1367 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7, 1368 DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); 1369 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 8, 1370 DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); 1371 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 9, 1372 DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); 1373 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1374 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); 1375 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 11, 1376 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); 1377 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 12, 1378 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); 1379 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 13, 1380 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); 1381 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 14, 1382 DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); 1383 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1384 DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); 1385 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 16, 1386 DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); 1387 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 17, 1388 DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); 1389 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 18, 1390 DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); 1391 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 19, 1392 DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); 1393 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 20, 1394 DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); 1395 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 21, 1396 DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); 1397 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 22, 1398 DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); 1399 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 23, 1400 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); 1401 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 24, 1402 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1403 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 25, 1404 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); 1405 1406 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1407 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); 1408 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1409 DateTime(Date(-1999, 7, 6), TimeOfDay(10, 30, 33))); 1410 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1411 DateTime(Date(-1999, 7, 6), TimeOfDay(9, 30, 33))); 1412 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1413 DateTime(Date(-1999, 7, 6), TimeOfDay(8, 30, 33))); 1414 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1415 DateTime(Date(-1999, 7, 6), TimeOfDay(7, 30, 33))); 1416 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -6, 1417 DateTime(Date(-1999, 7, 6), TimeOfDay(6, 30, 33))); 1418 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -7, 1419 DateTime(Date(-1999, 7, 6), TimeOfDay(5, 30, 33))); 1420 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -8, 1421 DateTime(Date(-1999, 7, 6), TimeOfDay(4, 30, 33))); 1422 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -9, 1423 DateTime(Date(-1999, 7, 6), TimeOfDay(3, 30, 33))); 1424 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1425 DateTime(Date(-1999, 7, 6), TimeOfDay(2, 30, 33))); 1426 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -11, 1427 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); 1428 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -12, 1429 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); 1430 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -13, 1431 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); 1432 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -14, 1433 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); 1434 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1435 DateTime(Date(-1999, 7, 6), TimeOfDay(21, 30, 33))); 1436 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -16, 1437 DateTime(Date(-1999, 7, 6), TimeOfDay(20, 30, 33))); 1438 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -17, 1439 DateTime(Date(-1999, 7, 6), TimeOfDay(19, 30, 33))); 1440 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -18, 1441 DateTime(Date(-1999, 7, 6), TimeOfDay(18, 30, 33))); 1442 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -19, 1443 DateTime(Date(-1999, 7, 6), TimeOfDay(17, 30, 33))); 1444 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -20, 1445 DateTime(Date(-1999, 7, 6), TimeOfDay(16, 30, 33))); 1446 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -21, 1447 DateTime(Date(-1999, 7, 6), TimeOfDay(15, 30, 33))); 1448 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -22, 1449 DateTime(Date(-1999, 7, 6), TimeOfDay(14, 30, 33))); 1450 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -23, 1451 DateTime(Date(-1999, 7, 6), TimeOfDay(13, 30, 33))); 1452 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -24, 1453 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1454 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -25, 1455 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 30, 33))); 1456 1457 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 1, 1458 DateTime(Date(-1999, 7, 6), TimeOfDay(1, 30, 33))); 1459 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), 0, 1460 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); 1461 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33)), -1, 1462 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); 1463 1464 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 1, 1465 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 30, 33))); 1466 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), 0, 1467 DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33))); 1468 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(23, 30, 33)), -1, 1469 DateTime(Date(-1999, 7, 6), TimeOfDay(22, 30, 33))); 1470 1471 testDT(DateTime(Date(-1999, 7, 31), TimeOfDay(23, 30, 33)), 1, 1472 DateTime(Date(-1999, 7, 31), TimeOfDay(0, 30, 33))); 1473 testDT(DateTime(Date(-1999, 8, 1), TimeOfDay(0, 30, 33)), -1, 1474 DateTime(Date(-1999, 8, 1), TimeOfDay(23, 30, 33))); 1475 1476 testDT(DateTime(Date(-2001, 12, 31), TimeOfDay(23, 30, 33)), 1, 1477 DateTime(Date(-2001, 12, 31), TimeOfDay(0, 30, 33))); 1478 testDT(DateTime(Date(-2000, 1, 1), TimeOfDay(0, 30, 33)), -1, 1479 DateTime(Date(-2000, 1, 1), TimeOfDay(23, 30, 33))); 1480 1481 testDT(DateTime(Date(-2001, 2, 28), TimeOfDay(23, 30, 33)), 25, 1482 DateTime(Date(-2001, 2, 28), TimeOfDay(0, 30, 33))); 1483 testDT(DateTime(Date(-2001, 3, 2), TimeOfDay(0, 30, 33)), -25, 1484 DateTime(Date(-2001, 3, 2), TimeOfDay(23, 30, 33))); 1485 1486 testDT(DateTime(Date(-2000, 2, 28), TimeOfDay(23, 30, 33)), 25, 1487 DateTime(Date(-2000, 2, 28), TimeOfDay(0, 30, 33))); 1488 testDT(DateTime(Date(-2000, 3, 1), TimeOfDay(0, 30, 33)), -25, 1489 DateTime(Date(-2000, 3, 1), TimeOfDay(23, 30, 33))); 1490 1491 // Test Both 1492 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 17_546, 1493 DateTime(Date(-1, 1, 1), TimeOfDay(13, 30, 33))); 1494 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -17_546, 1495 DateTime(Date(1, 1, 1), TimeOfDay(11, 30, 33))); 1496 1497 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 1498 dt.roll!"hours"(27).roll!"hours"(-9); 1499 assert(dt == DateTime(2000, 1, 31, 3, 7, 6)); 1500 1501 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1502 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1503 static assert(!__traits(compiles, cdt.roll!"hours"(4))); 1504 static assert(!__traits(compiles, idt.roll!"hours"(4))); 1505 } 1506 1507 // Test roll!"minutes"(). 1508 @safe unittest 1509 { 1510 static void testDT(DateTime orig, int minutes, in DateTime expected, size_t line = __LINE__) 1511 { 1512 orig.roll!"minutes"(minutes); 1513 assert(orig == expected); 1514 } 1515 1516 // Test A.D. 1517 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1518 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1519 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1520 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); 1521 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1522 DateTime(Date(1999, 7, 6), TimeOfDay(12, 32, 33))); 1523 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1524 DateTime(Date(1999, 7, 6), TimeOfDay(12, 33, 33))); 1525 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1526 DateTime(Date(1999, 7, 6), TimeOfDay(12, 34, 33))); 1527 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1528 DateTime(Date(1999, 7, 6), TimeOfDay(12, 35, 33))); 1529 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1530 DateTime(Date(1999, 7, 6), TimeOfDay(12, 40, 33))); 1531 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1532 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); 1533 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 29, 1534 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); 1535 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, 1536 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1537 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 45, 1538 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); 1539 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, 1540 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1541 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 75, 1542 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); 1543 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 90, 1544 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1545 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 100, 1546 DateTime(Date(1999, 7, 6), TimeOfDay(12, 10, 33))); 1547 1548 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 689, 1549 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); 1550 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 690, 1551 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1552 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 691, 1553 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); 1554 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 960, 1555 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1556 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, 1557 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); 1558 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, 1559 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1560 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, 1561 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); 1562 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, 1563 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1564 1565 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1566 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); 1567 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1568 DateTime(Date(1999, 7, 6), TimeOfDay(12, 28, 33))); 1569 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1570 DateTime(Date(1999, 7, 6), TimeOfDay(12, 27, 33))); 1571 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1572 DateTime(Date(1999, 7, 6), TimeOfDay(12, 26, 33))); 1573 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1574 DateTime(Date(1999, 7, 6), TimeOfDay(12, 25, 33))); 1575 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1576 DateTime(Date(1999, 7, 6), TimeOfDay(12, 20, 33))); 1577 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1578 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); 1579 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -29, 1580 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); 1581 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -30, 1582 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1583 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -45, 1584 DateTime(Date(1999, 7, 6), TimeOfDay(12, 45, 33))); 1585 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, 1586 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1587 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -75, 1588 DateTime(Date(1999, 7, 6), TimeOfDay(12, 15, 33))); 1589 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -90, 1590 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1591 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -100, 1592 DateTime(Date(1999, 7, 6), TimeOfDay(12, 50, 33))); 1593 1594 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -749, 1595 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); 1596 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -750, 1597 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1598 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -751, 1599 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); 1600 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -960, 1601 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1602 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, 1603 DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33))); 1604 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, 1605 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1606 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, 1607 DateTime(Date(1999, 7, 6), TimeOfDay(12, 29, 33))); 1608 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, 1609 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1610 1611 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 1, 1612 DateTime(Date(1999, 7, 6), TimeOfDay(12, 1, 33))); 1613 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), 0, 1614 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33))); 1615 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 33)), -1, 1616 DateTime(Date(1999, 7, 6), TimeOfDay(12, 59, 33))); 1617 1618 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 1, 1619 DateTime(Date(1999, 7, 6), TimeOfDay(11, 0, 33))); 1620 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), 0, 1621 DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33))); 1622 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(11, 59, 33)), -1, 1623 DateTime(Date(1999, 7, 6), TimeOfDay(11, 58, 33))); 1624 1625 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 1, 1626 DateTime(Date(1999, 7, 6), TimeOfDay(0, 1, 33))); 1627 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), 0, 1628 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33))); 1629 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 33)), -1, 1630 DateTime(Date(1999, 7, 6), TimeOfDay(0, 59, 33))); 1631 1632 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 1, 1633 DateTime(Date(1999, 7, 5), TimeOfDay(23, 0, 33))); 1634 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), 0, 1635 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33))); 1636 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 33)), -1, 1637 DateTime(Date(1999, 7, 5), TimeOfDay(23, 58, 33))); 1638 1639 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 1, 1640 DateTime(Date(1998, 12, 31), TimeOfDay(23, 0, 33))); 1641 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), 0, 1642 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33))); 1643 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 33)), -1, 1644 DateTime(Date(1998, 12, 31), TimeOfDay(23, 58, 33))); 1645 1646 // Test B.C. 1647 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1648 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1649 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1650 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); 1651 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1652 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 32, 33))); 1653 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1654 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 33, 33))); 1655 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1656 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 34, 33))); 1657 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1658 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 35, 33))); 1659 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1660 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 40, 33))); 1661 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1662 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); 1663 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 29, 1664 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); 1665 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, 1666 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1667 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 45, 1668 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); 1669 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, 1670 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1671 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 75, 1672 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); 1673 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 90, 1674 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1675 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 100, 1676 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 10, 33))); 1677 1678 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 689, 1679 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); 1680 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 690, 1681 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1682 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 691, 1683 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); 1684 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 960, 1685 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1686 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1439, 1687 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); 1688 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1440, 1689 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1690 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1441, 1691 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); 1692 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2880, 1693 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1694 1695 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1696 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); 1697 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1698 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 28, 33))); 1699 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1700 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 27, 33))); 1701 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1702 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 26, 33))); 1703 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1704 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 25, 33))); 1705 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1706 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 20, 33))); 1707 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1708 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); 1709 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -29, 1710 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); 1711 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -30, 1712 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1713 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -45, 1714 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 45, 33))); 1715 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, 1716 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1717 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -75, 1718 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 15, 33))); 1719 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -90, 1720 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1721 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -100, 1722 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 50, 33))); 1723 1724 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -749, 1725 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); 1726 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -750, 1727 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1728 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -751, 1729 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); 1730 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -960, 1731 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1732 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1439, 1733 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 31, 33))); 1734 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1440, 1735 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1736 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1441, 1737 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 29, 33))); 1738 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2880, 1739 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1740 1741 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 1, 1742 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 1, 33))); 1743 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), 0, 1744 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33))); 1745 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 33)), -1, 1746 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 59, 33))); 1747 1748 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 1, 1749 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 0, 33))); 1750 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), 0, 1751 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33))); 1752 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(11, 59, 33)), -1, 1753 DateTime(Date(-1999, 7, 6), TimeOfDay(11, 58, 33))); 1754 1755 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 1, 1756 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 1, 33))); 1757 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), 0, 1758 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33))); 1759 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 33)), -1, 1760 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 59, 33))); 1761 1762 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 1, 1763 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 0, 33))); 1764 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), 0, 1765 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33))); 1766 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 33)), -1, 1767 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 58, 33))); 1768 1769 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 1, 1770 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 0, 33))); 1771 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), 0, 1772 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33))); 1773 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 33)), -1, 1774 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 58, 33))); 1775 1776 // Test Both 1777 testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, 1778 DateTime(Date(1, 1, 1), TimeOfDay(0, 59, 0))); 1779 testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0)), 1, 1780 DateTime(Date(0, 12, 31), TimeOfDay(23, 0, 0))); 1781 1782 testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, 1783 DateTime(Date(0, 1, 1), TimeOfDay(0, 59, 0))); 1784 testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0)), 1, 1785 DateTime(Date(-1, 12, 31), TimeOfDay(23, 0, 0))); 1786 1787 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_760, 1788 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); 1789 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -1_052_760, 1790 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); 1791 1792 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 1_052_782, 1793 DateTime(Date(-1, 1, 1), TimeOfDay(11, 52, 33))); 1794 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 52, 33)), -1_052_782, 1795 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); 1796 1797 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 1798 dt.roll!"minutes"(92).roll!"minutes"(-292); 1799 assert(dt == DateTime(2000, 1, 31, 9, 47, 6)); 1800 1801 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 1802 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 1803 static assert(!__traits(compiles, cdt.roll!"minutes"(4))); 1804 static assert(!__traits(compiles, idt.roll!"minutes"(4))); 1805 } 1806 1807 // Test roll!"seconds"(). 1808 @safe unittest 1809 { 1810 static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__) 1811 { 1812 orig.roll!"seconds"(seconds); 1813 assert(orig == expected); 1814 } 1815 1816 // Test A.D. 1817 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1818 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1819 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1820 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); 1821 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1822 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 35))); 1823 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1824 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 36))); 1825 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1826 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 37))); 1827 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1828 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 38))); 1829 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1830 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 43))); 1831 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1832 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 48))); 1833 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 26, 1834 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); 1835 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 27, 1836 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); 1837 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 30, 1838 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 3))); 1839 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 59, 1840 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); 1841 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 60, 1842 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1843 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 61, 1844 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); 1845 1846 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, 1847 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); 1848 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, 1849 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); 1850 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, 1851 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); 1852 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, 1853 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); 1854 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, 1855 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); 1856 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, 1857 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1858 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, 1859 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); 1860 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, 1861 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1862 1863 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1864 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); 1865 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1866 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 31))); 1867 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1868 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 30))); 1869 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1870 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 29))); 1871 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1872 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 28))); 1873 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1874 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 23))); 1875 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1876 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 18))); 1877 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -33, 1878 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); 1879 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -34, 1880 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); 1881 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -35, 1882 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 58))); 1883 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -59, 1884 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34))); 1885 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -60, 1886 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 1887 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)), -61, 1888 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 32))); 1889 1890 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 1, 1891 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 1))); 1892 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), 0, 1893 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0))); 1894 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 0)), -1, 1895 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 59))); 1896 1897 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 1, 1898 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 1))); 1899 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), 0, 1900 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0))); 1901 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 0)), -1, 1902 DateTime(Date(1999, 7, 6), TimeOfDay(12, 0, 59))); 1903 1904 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 1, 1905 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 1))); 1906 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), 0, 1907 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0))); 1908 testDT(DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 0)), -1, 1909 DateTime(Date(1999, 7, 6), TimeOfDay(0, 0, 59))); 1910 1911 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 1, 1912 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 0))); 1913 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), 0, 1914 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59))); 1915 testDT(DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 59)), -1, 1916 DateTime(Date(1999, 7, 5), TimeOfDay(23, 59, 58))); 1917 1918 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 1, 1919 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 0))); 1920 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), 0, 1921 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59))); 1922 testDT(DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 59)), -1, 1923 DateTime(Date(1998, 12, 31), TimeOfDay(23, 59, 58))); 1924 1925 // Test B.C. 1926 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 0, 1927 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1928 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1, 1929 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); 1930 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2, 1931 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 35))); 1932 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3, 1933 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 36))); 1934 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 4, 1935 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 37))); 1936 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 5, 1937 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 38))); 1938 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 10, 1939 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 43))); 1940 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 15, 1941 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 48))); 1942 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 26, 1943 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); 1944 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 27, 1945 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); 1946 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 30, 1947 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 3))); 1948 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 59, 1949 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); 1950 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 60, 1951 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1952 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 61, 1953 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); 1954 1955 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1766, 1956 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); 1957 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1767, 1958 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); 1959 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 1768, 1960 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); 1961 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 2007, 1962 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); 1963 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3599, 1964 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); 1965 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3600, 1966 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1967 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 3601, 1968 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); 1969 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), 7200, 1970 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1971 1972 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -1, 1973 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); 1974 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -2, 1975 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 31))); 1976 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -3, 1977 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 30))); 1978 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -4, 1979 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 29))); 1980 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -5, 1981 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 28))); 1982 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -10, 1983 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 23))); 1984 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -15, 1985 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 18))); 1986 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -33, 1987 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); 1988 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -34, 1989 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); 1990 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -35, 1991 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 58))); 1992 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -59, 1993 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 34))); 1994 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -60, 1995 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 1996 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)), -61, 1997 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 32))); 1998 1999 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 1, 2000 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 1))); 2001 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), 0, 2002 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0))); 2003 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 0)), -1, 2004 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 59))); 2005 2006 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 1, 2007 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 1))); 2008 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), 0, 2009 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0))); 2010 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 0)), -1, 2011 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 0, 59))); 2012 2013 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 1, 2014 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 1))); 2015 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), 0, 2016 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0))); 2017 testDT(DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 0)), -1, 2018 DateTime(Date(-1999, 7, 6), TimeOfDay(0, 0, 59))); 2019 2020 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 1, 2021 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 0))); 2022 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), 0, 2023 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59))); 2024 testDT(DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 59)), -1, 2025 DateTime(Date(-1999, 7, 5), TimeOfDay(23, 59, 58))); 2026 2027 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 1, 2028 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 0))); 2029 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), 0, 2030 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59))); 2031 testDT(DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 59)), -1, 2032 DateTime(Date(-2000, 12, 31), TimeOfDay(23, 59, 58))); 2033 2034 // Test Both 2035 testDT(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)), -1, 2036 DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 59))); 2037 testDT(DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)), 1, 2038 DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 0))); 2039 2040 testDT(DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 0)), -1, 2041 DateTime(Date(0, 1, 1), TimeOfDay(0, 0, 59))); 2042 testDT(DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 59)), 1, 2043 DateTime(Date(-1, 12, 31), TimeOfDay(23, 59, 0))); 2044 2045 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_600L, 2046 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33))); 2047 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33)), -63_165_600L, 2048 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); 2049 2050 testDT(DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 33)), 63_165_617L, 2051 DateTime(Date(-1, 1, 1), TimeOfDay(11, 30, 50))); 2052 testDT(DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 50)), -63_165_617L, 2053 DateTime(Date(1, 1, 1), TimeOfDay(13, 30, 33))); 2054 2055 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 2056 dt.roll!"seconds"(92).roll!"seconds"(-292); 2057 assert(dt == DateTime(2000, 1, 31, 9, 7, 46)); 2058 2059 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2060 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2061 static assert(!__traits(compiles, cdt.roll!"seconds"(4))); 2062 static assert(!__traits(compiles, idt.roll!"seconds"(4))); 2063 } 2064 2065 2066 /++ 2067 Gives the result of adding or subtracting a $(REF Duration, core,time) 2068 from this $(LREF DateTime). 2069 2070 The legal types of arithmetic for $(LREF DateTime) using this operator 2071 are 2072 2073 $(BOOKTABLE, 2074 $(TR $(TD DateTime) $(TD +) $(TD Duration) $(TD -->) $(TD DateTime)) 2075 $(TR $(TD DateTime) $(TD -) $(TD Duration) $(TD -->) $(TD DateTime)) 2076 ) 2077 2078 Params: 2079 duration = The $(REF Duration, core,time) to add to or subtract from 2080 this $(LREF DateTime). 2081 +/ 2082 DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 2083 if (op == "+" || op == "-") 2084 { 2085 DateTime retval = this; 2086 immutable seconds = duration.total!"seconds"; 2087 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 2088 } 2089 2090 /// 2091 @safe unittest 2092 { 2093 import core.time : hours, seconds; 2094 2095 assert(DateTime(2015, 12, 31, 23, 59, 59) + seconds(1) == 2096 DateTime(2016, 1, 1, 0, 0, 0)); 2097 2098 assert(DateTime(2015, 12, 31, 23, 59, 59) + hours(1) == 2099 DateTime(2016, 1, 1, 0, 59, 59)); 2100 2101 assert(DateTime(2016, 1, 1, 0, 0, 0) - seconds(1) == 2102 DateTime(2015, 12, 31, 23, 59, 59)); 2103 2104 assert(DateTime(2016, 1, 1, 0, 59, 59) - hours(1) == 2105 DateTime(2015, 12, 31, 23, 59, 59)); 2106 } 2107 2108 @safe unittest 2109 { 2110 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2111 2112 assert(dt + dur!"weeks"(7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2113 assert(dt + dur!"weeks"(-7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2114 assert(dt + dur!"days"(7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2115 assert(dt + dur!"days"(-7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2116 2117 assert(dt + dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2118 assert(dt + dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2119 assert(dt + dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2120 assert(dt + dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2121 assert(dt + dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2122 assert(dt + dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2123 assert(dt + dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2124 assert(dt + dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2125 assert(dt + dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2126 assert(dt + dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2127 assert(dt + dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2128 assert(dt + dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2129 2130 assert(dt - dur!"weeks"(-7) == DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2131 assert(dt - dur!"weeks"(7) == DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2132 assert(dt - dur!"days"(-7) == DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2133 assert(dt - dur!"days"(7) == DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2134 2135 assert(dt - dur!"hours"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2136 assert(dt - dur!"hours"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2137 assert(dt - dur!"minutes"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2138 assert(dt - dur!"minutes"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2139 assert(dt - dur!"seconds"(-7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2140 assert(dt - dur!"seconds"(7) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2141 assert(dt - dur!"msecs"(-7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2142 assert(dt - dur!"msecs"(7_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2143 assert(dt - dur!"usecs"(-7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2144 assert(dt - dur!"usecs"(7_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2145 assert(dt - dur!"hnsecs"(-70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2146 assert(dt - dur!"hnsecs"(70_000_000) == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2147 2148 auto duration = dur!"seconds"(12); 2149 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2150 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2151 assert(cdt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2152 assert(idt + duration == DateTime(1999, 7, 6, 12, 30, 45)); 2153 assert(cdt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2154 assert(idt - duration == DateTime(1999, 7, 6, 12, 30, 21)); 2155 } 2156 2157 2158 /++ 2159 Gives the result of adding or subtracting a duration from this 2160 $(LREF DateTime), as well as assigning the result to this 2161 $(LREF DateTime). 2162 2163 The legal types of arithmetic for $(LREF DateTime) using this operator 2164 are 2165 2166 $(BOOKTABLE, 2167 $(TR $(TD DateTime) $(TD +) $(TD duration) $(TD -->) $(TD DateTime)) 2168 $(TR $(TD DateTime) $(TD -) $(TD duration) $(TD -->) $(TD DateTime)) 2169 ) 2170 2171 Params: 2172 duration = The duration to add to or subtract from this 2173 $(LREF DateTime). 2174 +/ 2175 ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 2176 if (op == "+" || op == "-") 2177 { 2178 import core.time : convert; 2179 import std.format : format; 2180 2181 DateTime retval = this; 2182 immutable hnsecs = duration.total!"hnsecs"; 2183 2184 mixin(format(`return _addSeconds(convert!("hnsecs", "seconds")(%shnsecs));`, op)); 2185 } 2186 2187 @safe unittest 2188 { 2189 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(7) == 2190 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2191 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"weeks"(-7) == 2192 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2193 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(7) == 2194 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2195 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"days"(-7) == 2196 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2197 2198 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(7) == 2199 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2200 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hours"(-7) == 2201 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2202 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(7) == 2203 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2204 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"minutes"(-7) == 2205 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2206 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(7) == 2207 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2208 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"seconds"(-7) == 2209 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2210 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(7_000) == 2211 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2212 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"msecs"(-7_000) == 2213 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2214 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(7_000_000) == 2215 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2216 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"usecs"(-7_000_000) == 2217 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2218 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(70_000_000) == 2219 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2220 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) + dur!"hnsecs"(-70_000_000) == 2221 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2222 2223 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(-7) == 2224 DateTime(Date(1999, 8, 24), TimeOfDay(12, 30, 33))); 2225 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"weeks"(7) == 2226 DateTime(Date(1999, 5, 18), TimeOfDay(12, 30, 33))); 2227 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(-7) == 2228 DateTime(Date(1999, 7, 13), TimeOfDay(12, 30, 33))); 2229 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"days"(7) == 2230 DateTime(Date(1999, 6, 29), TimeOfDay(12, 30, 33))); 2231 2232 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(-7) == 2233 DateTime(Date(1999, 7, 6), TimeOfDay(19, 30, 33))); 2234 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hours"(7) == 2235 DateTime(Date(1999, 7, 6), TimeOfDay(5, 30, 33))); 2236 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(-7) == 2237 DateTime(Date(1999, 7, 6), TimeOfDay(12, 37, 33))); 2238 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"minutes"(7) == 2239 DateTime(Date(1999, 7, 6), TimeOfDay(12, 23, 33))); 2240 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(-7) == 2241 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2242 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"seconds"(7) == 2243 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2244 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(-7_000) == 2245 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2246 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"msecs"(7_000) == 2247 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2248 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(-7_000_000) == 2249 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2250 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"usecs"(7_000_000) == 2251 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2252 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(-70_000_000) == 2253 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 40))); 2254 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - dur!"hnsecs"(70_000_000) == 2255 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 26))); 2256 2257 auto dt = DateTime(2000, 1, 31, 9, 7, 6); 2258 (dt += dur!"seconds"(92)) -= dur!"days"(-500); 2259 assert(dt == DateTime(2001, 6, 14, 9, 8, 38)); 2260 2261 auto duration = dur!"seconds"(12); 2262 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2263 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2264 static assert(!__traits(compiles, cdt += duration)); 2265 static assert(!__traits(compiles, idt += duration)); 2266 static assert(!__traits(compiles, cdt -= duration)); 2267 static assert(!__traits(compiles, idt -= duration)); 2268 } 2269 2270 2271 /++ 2272 Gives the difference between two $(LREF DateTime)s. 2273 2274 The legal types of arithmetic for $(LREF DateTime) using this operator are 2275 2276 $(BOOKTABLE, 2277 $(TR $(TD DateTime) $(TD -) $(TD DateTime) $(TD -->) $(TD duration)) 2278 ) 2279 +/ 2280 Duration opBinary(string op)(in DateTime rhs) const @safe pure nothrow @nogc 2281 if (op == "-") 2282 { 2283 immutable dateResult = _date - rhs.date; 2284 immutable todResult = _tod - rhs._tod; 2285 2286 return dur!"hnsecs"(dateResult.total!"hnsecs" + todResult.total!"hnsecs"); 2287 } 2288 2289 @safe unittest 2290 { 2291 auto dt = DateTime(1999, 7, 6, 12, 30, 33); 2292 2293 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) == 2294 dur!"seconds"(31_536_000)); 2295 assert(DateTime(Date(1998, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2296 dur!"seconds"(-31_536_000)); 2297 2298 assert(DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2299 dur!"seconds"(26_78_400)); 2300 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 8, 6), TimeOfDay(12, 30, 33)) == 2301 dur!"seconds"(-26_78_400)); 2302 2303 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) == 2304 dur!"seconds"(86_400)); 2305 assert(DateTime(Date(1999, 7, 5), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2306 dur!"seconds"(-86_400)); 2307 2308 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) == 2309 dur!"seconds"(3600)); 2310 assert(DateTime(Date(1999, 7, 6), TimeOfDay(11, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2311 dur!"seconds"(-3600)); 2312 2313 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2314 dur!"seconds"(60)); 2315 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 31, 33)) == 2316 dur!"seconds"(-60)); 2317 2318 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) == 2319 dur!"seconds"(1)); 2320 assert(DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)) - DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 34)) == 2321 dur!"seconds"(-1)); 2322 2323 assert(DateTime(1, 1, 1, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(45033)); 2324 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(1, 1, 1, 12, 30, 33) == dur!"seconds"(-45033)); 2325 assert(DateTime(0, 12, 31, 12, 30, 33) - DateTime(1, 1, 1, 0, 0, 0) == dur!"seconds"(-41367)); 2326 assert(DateTime(1, 1, 1, 0, 0, 0) - DateTime(0, 12, 31, 12, 30, 33) == dur!"seconds"(41367)); 2327 2328 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2329 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2330 assert(dt - dt == Duration.zero); 2331 assert(cdt - dt == Duration.zero); 2332 assert(idt - dt == Duration.zero); 2333 2334 assert(dt - cdt == Duration.zero); 2335 assert(cdt - cdt == Duration.zero); 2336 assert(idt - cdt == Duration.zero); 2337 2338 assert(dt - idt == Duration.zero); 2339 assert(cdt - idt == Duration.zero); 2340 assert(idt - idt == Duration.zero); 2341 } 2342 2343 2344 /++ 2345 Returns the difference between the two $(LREF DateTime)s in months. 2346 2347 To get the difference in years, subtract the year property 2348 of two $(LREF DateTime)s. To get the difference in days or weeks, 2349 subtract the $(LREF DateTime)s themselves and use the 2350 $(REF Duration, core,time) that results. Because converting between 2351 months and smaller units requires a specific date (which 2352 $(REF Duration, core,time)s don't have), getting the difference in 2353 months requires some math using both the year and month properties, so 2354 this is a convenience function for getting the difference in months. 2355 2356 Note that the number of days in the months or how far into the month 2357 either date is is irrelevant. It is the difference in the month property 2358 combined with the difference in years * 12. So, for instance, 2359 December 31st and January 1st are one month apart just as December 1st 2360 and January 31st are one month apart. 2361 2362 Params: 2363 rhs = The $(LREF DateTime) to subtract from this one. 2364 +/ 2365 int diffMonths(in DateTime rhs) const @safe pure nothrow @nogc 2366 { 2367 return _date.diffMonths(rhs._date); 2368 } 2369 2370 /// 2371 @safe unittest 2372 { 2373 assert(DateTime(1999, 2, 1, 12, 2, 3).diffMonths( 2374 DateTime(1999, 1, 31, 23, 59, 59)) == 1); 2375 2376 assert(DateTime(1999, 1, 31, 0, 0, 0).diffMonths( 2377 DateTime(1999, 2, 1, 12, 3, 42)) == -1); 2378 2379 assert(DateTime(1999, 3, 1, 5, 30, 0).diffMonths( 2380 DateTime(1999, 1, 1, 2, 4, 7)) == 2); 2381 2382 assert(DateTime(1999, 1, 1, 7, 2, 4).diffMonths( 2383 DateTime(1999, 3, 31, 0, 30, 58)) == -2); 2384 } 2385 2386 @safe unittest 2387 { 2388 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2389 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2390 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2391 assert(dt.diffMonths(dt) == 0); 2392 assert(cdt.diffMonths(dt) == 0); 2393 assert(idt.diffMonths(dt) == 0); 2394 2395 assert(dt.diffMonths(cdt) == 0); 2396 assert(cdt.diffMonths(cdt) == 0); 2397 assert(idt.diffMonths(cdt) == 0); 2398 2399 assert(dt.diffMonths(idt) == 0); 2400 assert(cdt.diffMonths(idt) == 0); 2401 assert(idt.diffMonths(idt) == 0); 2402 } 2403 2404 2405 /++ 2406 Whether this $(LREF DateTime) is in a leap year. 2407 +/ 2408 @property bool isLeapYear() const @safe pure nothrow @nogc 2409 { 2410 return _date.isLeapYear; 2411 } 2412 2413 @safe unittest 2414 { 2415 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2416 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2417 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2418 assert(!dt.isLeapYear); 2419 assert(!cdt.isLeapYear); 2420 assert(!idt.isLeapYear); 2421 } 2422 2423 2424 /++ 2425 Day of the week this $(LREF DateTime) is on. 2426 +/ 2427 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 2428 { 2429 return _date.dayOfWeek; 2430 } 2431 2432 @safe unittest 2433 { 2434 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2435 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2436 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2437 assert(dt.dayOfWeek == DayOfWeek.tue); 2438 assert(cdt.dayOfWeek == DayOfWeek.tue); 2439 assert(idt.dayOfWeek == DayOfWeek.tue); 2440 } 2441 2442 2443 /++ 2444 Day of the year this $(LREF DateTime) is on. 2445 +/ 2446 @property ushort dayOfYear() const @safe pure nothrow @nogc 2447 { 2448 return _date.dayOfYear; 2449 } 2450 2451 /// 2452 @safe unittest 2453 { 2454 assert(DateTime(Date(1999, 1, 1), TimeOfDay(12, 22, 7)).dayOfYear == 1); 2455 assert(DateTime(Date(1999, 12, 31), TimeOfDay(7, 2, 59)).dayOfYear == 365); 2456 assert(DateTime(Date(2000, 12, 31), TimeOfDay(21, 20, 0)).dayOfYear == 366); 2457 } 2458 2459 @safe unittest 2460 { 2461 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2462 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2463 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2464 assert(dt.dayOfYear == 187); 2465 assert(cdt.dayOfYear == 187); 2466 assert(idt.dayOfYear == 187); 2467 } 2468 2469 2470 /++ 2471 Day of the year. 2472 2473 Params: 2474 day = The day of the year to set which day of the year this 2475 $(LREF DateTime) is on. 2476 +/ 2477 @property void dayOfYear(int day) @safe pure 2478 { 2479 _date.dayOfYear = day; 2480 } 2481 2482 @safe unittest 2483 { 2484 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2485 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2486 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2487 dt.dayOfYear = 12; 2488 assert(dt.dayOfYear == 12); 2489 static assert(!__traits(compiles, cdt.dayOfYear = 12)); 2490 static assert(!__traits(compiles, idt.dayOfYear = 12)); 2491 } 2492 2493 2494 /++ 2495 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2496 +/ 2497 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 2498 { 2499 return _date.dayOfGregorianCal; 2500 } 2501 2502 /// 2503 @safe unittest 2504 { 2505 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).dayOfGregorianCal == 1); 2506 assert(DateTime(Date(1, 12, 31), TimeOfDay(23, 59, 59)).dayOfGregorianCal == 365); 2507 assert(DateTime(Date(2, 1, 1), TimeOfDay(2, 2, 2)).dayOfGregorianCal == 366); 2508 2509 assert(DateTime(Date(0, 12, 31), TimeOfDay(7, 7, 7)).dayOfGregorianCal == 0); 2510 assert(DateTime(Date(0, 1, 1), TimeOfDay(19, 30, 0)).dayOfGregorianCal == -365); 2511 assert(DateTime(Date(-1, 12, 31), TimeOfDay(4, 7, 0)).dayOfGregorianCal == -366); 2512 2513 assert(DateTime(Date(2000, 1, 1), TimeOfDay(9, 30, 20)).dayOfGregorianCal == 730_120); 2514 assert(DateTime(Date(2010, 12, 31), TimeOfDay(15, 45, 50)).dayOfGregorianCal == 734_137); 2515 } 2516 2517 @safe unittest 2518 { 2519 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2520 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2521 assert(cdt.dayOfGregorianCal == 729_941); 2522 assert(idt.dayOfGregorianCal == 729_941); 2523 } 2524 2525 2526 /++ 2527 The Xth day of the Gregorian Calendar that this $(LREF DateTime) is on. 2528 Setting this property does not affect the time portion of 2529 $(LREF DateTime). 2530 2531 Params: 2532 days = The day of the Gregorian Calendar to set this $(LREF DateTime) 2533 to. 2534 +/ 2535 @property void dayOfGregorianCal(int days) @safe pure nothrow @nogc 2536 { 2537 _date.dayOfGregorianCal = days; 2538 } 2539 2540 /// 2541 @safe unittest 2542 { 2543 auto dt = DateTime(Date.init, TimeOfDay(12, 0, 0)); 2544 dt.dayOfGregorianCal = 1; 2545 assert(dt == DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0))); 2546 2547 dt.dayOfGregorianCal = 365; 2548 assert(dt == DateTime(Date(1, 12, 31), TimeOfDay(12, 0, 0))); 2549 2550 dt.dayOfGregorianCal = 366; 2551 assert(dt == DateTime(Date(2, 1, 1), TimeOfDay(12, 0, 0))); 2552 2553 dt.dayOfGregorianCal = 0; 2554 assert(dt == DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0))); 2555 2556 dt.dayOfGregorianCal = -365; 2557 assert(dt == DateTime(Date(-0, 1, 1), TimeOfDay(12, 0, 0))); 2558 2559 dt.dayOfGregorianCal = -366; 2560 assert(dt == DateTime(Date(-1, 12, 31), TimeOfDay(12, 0, 0))); 2561 2562 dt.dayOfGregorianCal = 730_120; 2563 assert(dt == DateTime(Date(2000, 1, 1), TimeOfDay(12, 0, 0))); 2564 2565 dt.dayOfGregorianCal = 734_137; 2566 assert(dt == DateTime(Date(2010, 12, 31), TimeOfDay(12, 0, 0))); 2567 } 2568 2569 @safe unittest 2570 { 2571 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2572 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2573 static assert(!__traits(compiles, cdt.dayOfGregorianCal = 7)); 2574 static assert(!__traits(compiles, idt.dayOfGregorianCal = 7)); 2575 } 2576 2577 2578 /++ 2579 The ISO 8601 week of the year that this $(LREF DateTime) is in. 2580 2581 See_Also: 2582 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 2583 +/ 2584 @property ubyte isoWeek() const @safe pure nothrow 2585 { 2586 return _date.isoWeek; 2587 } 2588 2589 @safe unittest 2590 { 2591 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2592 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2593 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2594 assert(dt.isoWeek == 27); 2595 assert(cdt.isoWeek == 27); 2596 assert(idt.isoWeek == 27); 2597 } 2598 2599 2600 /++ 2601 $(LREF DateTime) for the last day in the month that this 2602 $(LREF DateTime) is in. The time portion of endOfMonth is always 2603 23:59:59. 2604 +/ 2605 @property DateTime endOfMonth() const @safe pure nothrow 2606 { 2607 try 2608 return DateTime(_date.endOfMonth, TimeOfDay(23, 59, 59)); 2609 catch (Exception e) 2610 assert(0, "DateTime constructor threw."); 2611 } 2612 2613 /// 2614 @safe unittest 2615 { 2616 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).endOfMonth == 2617 DateTime(Date(1999, 1, 31), TimeOfDay(23, 59, 59))); 2618 2619 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).endOfMonth == 2620 DateTime(Date(1999, 2, 28), TimeOfDay(23, 59, 59))); 2621 2622 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).endOfMonth == 2623 DateTime(Date(2000, 2, 29), TimeOfDay(23, 59, 59))); 2624 2625 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).endOfMonth == 2626 DateTime(Date(2000, 6, 30), TimeOfDay(23, 59, 59))); 2627 } 2628 2629 @safe unittest 2630 { 2631 // Test A.D. 2632 assert(DateTime(1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(1999, 1, 31, 23, 59, 59)); 2633 assert(DateTime(1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(1999, 2, 28, 23, 59, 59)); 2634 assert(DateTime(2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(2000, 2, 29, 23, 59, 59)); 2635 assert(DateTime(1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(1999, 3, 31, 23, 59, 59)); 2636 assert(DateTime(1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(1999, 4, 30, 23, 59, 59)); 2637 assert(DateTime(1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(1999, 5, 31, 23, 59, 59)); 2638 assert(DateTime(1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(1999, 6, 30, 23, 59, 59)); 2639 assert(DateTime(1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2640 assert(DateTime(1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(1999, 8, 31, 23, 59, 59)); 2641 assert(DateTime(1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(1999, 9, 30, 23, 59, 59)); 2642 assert(DateTime(1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(1999, 10, 31, 23, 59, 59)); 2643 assert(DateTime(1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(1999, 11, 30, 23, 59, 59)); 2644 assert(DateTime(1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(1999, 12, 31, 23, 59, 59)); 2645 2646 // Test B.C. 2647 assert(DateTime(-1999, 1, 1, 0, 13, 26).endOfMonth == DateTime(-1999, 1, 31, 23, 59, 59)); 2648 assert(DateTime(-1999, 2, 1, 1, 14, 27).endOfMonth == DateTime(-1999, 2, 28, 23, 59, 59)); 2649 assert(DateTime(-2000, 2, 1, 2, 15, 28).endOfMonth == DateTime(-2000, 2, 29, 23, 59, 59)); 2650 assert(DateTime(-1999, 3, 1, 3, 16, 29).endOfMonth == DateTime(-1999, 3, 31, 23, 59, 59)); 2651 assert(DateTime(-1999, 4, 1, 4, 17, 30).endOfMonth == DateTime(-1999, 4, 30, 23, 59, 59)); 2652 assert(DateTime(-1999, 5, 1, 5, 18, 31).endOfMonth == DateTime(-1999, 5, 31, 23, 59, 59)); 2653 assert(DateTime(-1999, 6, 1, 6, 19, 32).endOfMonth == DateTime(-1999, 6, 30, 23, 59, 59)); 2654 assert(DateTime(-1999, 7, 1, 7, 20, 33).endOfMonth == DateTime(-1999, 7, 31, 23, 59, 59)); 2655 assert(DateTime(-1999, 8, 1, 8, 21, 34).endOfMonth == DateTime(-1999, 8, 31, 23, 59, 59)); 2656 assert(DateTime(-1999, 9, 1, 9, 22, 35).endOfMonth == DateTime(-1999, 9, 30, 23, 59, 59)); 2657 assert(DateTime(-1999, 10, 1, 10, 23, 36).endOfMonth == DateTime(-1999, 10, 31, 23, 59, 59)); 2658 assert(DateTime(-1999, 11, 1, 11, 24, 37).endOfMonth == DateTime(-1999, 11, 30, 23, 59, 59)); 2659 assert(DateTime(-1999, 12, 1, 12, 25, 38).endOfMonth == DateTime(-1999, 12, 31, 23, 59, 59)); 2660 2661 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2662 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2663 assert(cdt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2664 assert(idt.endOfMonth == DateTime(1999, 7, 31, 23, 59, 59)); 2665 } 2666 2667 2668 /++ 2669 The last day in the month that this $(LREF DateTime) is in. 2670 +/ 2671 @property ubyte daysInMonth() const @safe pure nothrow @nogc 2672 { 2673 return _date.daysInMonth; 2674 } 2675 2676 /// 2677 @safe unittest 2678 { 2679 assert(DateTime(Date(1999, 1, 6), TimeOfDay(0, 0, 0)).daysInMonth == 31); 2680 assert(DateTime(Date(1999, 2, 7), TimeOfDay(19, 30, 0)).daysInMonth == 28); 2681 assert(DateTime(Date(2000, 2, 7), TimeOfDay(5, 12, 27)).daysInMonth == 29); 2682 assert(DateTime(Date(2000, 6, 4), TimeOfDay(12, 22, 9)).daysInMonth == 30); 2683 } 2684 2685 @safe unittest 2686 { 2687 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2688 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2689 assert(cdt.daysInMonth == 31); 2690 assert(idt.daysInMonth == 31); 2691 } 2692 2693 2694 /++ 2695 Whether the current year is a date in A.D. 2696 +/ 2697 @property bool isAD() const @safe pure nothrow @nogc 2698 { 2699 return _date.isAD; 2700 } 2701 2702 /// 2703 @safe unittest 2704 { 2705 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 7, 0)).isAD); 2706 assert(DateTime(Date(2010, 12, 31), TimeOfDay(0, 0, 0)).isAD); 2707 assert(!DateTime(Date(0, 12, 31), TimeOfDay(23, 59, 59)).isAD); 2708 assert(!DateTime(Date(-2010, 1, 1), TimeOfDay(2, 2, 2)).isAD); 2709 } 2710 2711 @safe unittest 2712 { 2713 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2714 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2715 assert(cdt.isAD); 2716 assert(idt.isAD); 2717 } 2718 2719 2720 /++ 2721 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 2722 $(LREF DateTime) at the given time. For example, prior to noon, 2723 1996-03-31 would be the Julian day number 2_450_173, so this function 2724 returns 2_450_173, while from noon onward, the julian day number would 2725 be 2_450_174, so this function returns 2_450_174. 2726 +/ 2727 @property long julianDay() const @safe pure nothrow @nogc 2728 { 2729 if (_tod._hour < 12) 2730 return _date.julianDay - 1; 2731 else 2732 return _date.julianDay; 2733 } 2734 2735 @safe unittest 2736 { 2737 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(0, 0, 0)).julianDay == -1); 2738 assert(DateTime(Date(-4713, 11, 24), TimeOfDay(12, 0, 0)).julianDay == 0); 2739 2740 assert(DateTime(Date(0, 12, 31), TimeOfDay(0, 0, 0)).julianDay == 1_721_424); 2741 assert(DateTime(Date(0, 12, 31), TimeOfDay(12, 0, 0)).julianDay == 1_721_425); 2742 2743 assert(DateTime(Date(1, 1, 1), TimeOfDay(0, 0, 0)).julianDay == 1_721_425); 2744 assert(DateTime(Date(1, 1, 1), TimeOfDay(12, 0, 0)).julianDay == 1_721_426); 2745 2746 assert(DateTime(Date(1582, 10, 15), TimeOfDay(0, 0, 0)).julianDay == 2_299_160); 2747 assert(DateTime(Date(1582, 10, 15), TimeOfDay(12, 0, 0)).julianDay == 2_299_161); 2748 2749 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).julianDay == 2_400_000); 2750 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).julianDay == 2_400_001); 2751 2752 assert(DateTime(Date(1982, 1, 4), TimeOfDay(0, 0, 0)).julianDay == 2_444_973); 2753 assert(DateTime(Date(1982, 1, 4), TimeOfDay(12, 0, 0)).julianDay == 2_444_974); 2754 2755 assert(DateTime(Date(1996, 3, 31), TimeOfDay(0, 0, 0)).julianDay == 2_450_173); 2756 assert(DateTime(Date(1996, 3, 31), TimeOfDay(12, 0, 0)).julianDay == 2_450_174); 2757 2758 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).julianDay == 2_455_432); 2759 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).julianDay == 2_455_433); 2760 2761 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2762 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2763 assert(cdt.julianDay == 2_451_366); 2764 assert(idt.julianDay == 2_451_366); 2765 } 2766 2767 2768 /++ 2769 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for any 2770 time on this date (since, the modified Julian day changes at midnight). 2771 +/ 2772 @property long modJulianDay() const @safe pure nothrow @nogc 2773 { 2774 return _date.modJulianDay; 2775 } 2776 2777 @safe unittest 2778 { 2779 assert(DateTime(Date(1858, 11, 17), TimeOfDay(0, 0, 0)).modJulianDay == 0); 2780 assert(DateTime(Date(1858, 11, 17), TimeOfDay(12, 0, 0)).modJulianDay == 0); 2781 2782 assert(DateTime(Date(2010, 8, 24), TimeOfDay(0, 0, 0)).modJulianDay == 55_432); 2783 assert(DateTime(Date(2010, 8, 24), TimeOfDay(12, 0, 0)).modJulianDay == 55_432); 2784 2785 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2786 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 2787 assert(cdt.modJulianDay == 51_365); 2788 assert(idt.modJulianDay == 51_365); 2789 } 2790 2791 2792 /++ 2793 Converts this $(LREF DateTime) to a string with the format YYYYMMDDTHHMMSS. 2794 +/ 2795 string toISOString() const @safe pure nothrow 2796 { 2797 import std.format : format; 2798 try 2799 { 2800 return format!("%sT%02d%02d%02d")( 2801 _date.toISOString(), 2802 _tod._hour, 2803 _tod._minute, 2804 _tod._second 2805 ); 2806 } 2807 catch (Exception e) 2808 { 2809 assert(0, "format() threw."); 2810 } 2811 } 2812 2813 /// 2814 @safe unittest 2815 { 2816 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOString() == 2817 "20100704T070612"); 2818 2819 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOString() == 2820 "19981225T021500"); 2821 2822 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOString() == 2823 "00000105T230959"); 2824 2825 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOString() == 2826 "-00040105T000002"); 2827 } 2828 2829 @safe unittest 2830 { 2831 // Test A.D. 2832 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "00091204T000000"); 2833 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "00991204T050612"); 2834 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "09991204T134459"); 2835 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "99990704T235959"); 2836 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "+100001020T010101"); 2837 2838 // Test B.C. 2839 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOString() == "00001204T001204"); 2840 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOString() == "-00091204T000000"); 2841 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOString() == "-00991204T050612"); 2842 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOString() == "-09991204T134459"); 2843 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOString() == "-99990704T235959"); 2844 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOString() == "-100001020T010101"); 2845 2846 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2847 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2848 assert(cdt.toISOString() == "19990706T123033"); 2849 assert(idt.toISOString() == "19990706T123033"); 2850 } 2851 2852 2853 /++ 2854 Converts this $(LREF DateTime) to a string with the format 2855 YYYY-MM-DDTHH:MM:SS. 2856 +/ 2857 string toISOExtString() const @safe pure nothrow 2858 { 2859 import std.format : format; 2860 try 2861 { 2862 return format!("%sT%02d:%02d:%02d")( 2863 _date.toISOExtString(), 2864 _tod._hour, 2865 _tod._minute, 2866 _tod._second 2867 ); 2868 } 2869 catch (Exception e) 2870 { 2871 assert(0, "format() threw."); 2872 } 2873 } 2874 2875 /// 2876 @safe unittest 2877 { 2878 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toISOExtString() == 2879 "2010-07-04T07:06:12"); 2880 2881 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toISOExtString() == 2882 "1998-12-25T02:15:00"); 2883 2884 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toISOExtString() == 2885 "0000-01-05T23:09:59"); 2886 2887 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toISOExtString() == 2888 "-0004-01-05T00:00:02"); 2889 } 2890 2891 @safe unittest 2892 { 2893 // Test A.D. 2894 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "0009-12-04T00:00:00"); 2895 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "0099-12-04T05:06:12"); 2896 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "0999-12-04T13:44:59"); 2897 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "9999-07-04T23:59:59"); 2898 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "+10000-10-20T01:01:01"); 2899 2900 // Test B.C. 2901 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toISOExtString() == "0000-12-04T00:12:04"); 2902 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toISOExtString() == "-0009-12-04T00:00:00"); 2903 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toISOExtString() == "-0099-12-04T05:06:12"); 2904 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toISOExtString() == "-0999-12-04T13:44:59"); 2905 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toISOExtString() == "-9999-07-04T23:59:59"); 2906 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toISOExtString() == "-10000-10-20T01:01:01"); 2907 2908 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2909 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2910 assert(cdt.toISOExtString() == "1999-07-06T12:30:33"); 2911 assert(idt.toISOExtString() == "1999-07-06T12:30:33"); 2912 } 2913 2914 /++ 2915 Converts this $(LREF DateTime) to a string with the format 2916 YYYY-Mon-DD HH:MM:SS. 2917 +/ 2918 string toSimpleString() const @safe pure nothrow 2919 { 2920 import std.format : format; 2921 try 2922 { 2923 return format!("%s %02d:%02d:%02d")( 2924 _date.toSimpleString(), 2925 _tod._hour, 2926 _tod._minute, 2927 _tod._second 2928 ); 2929 } 2930 catch (Exception e) 2931 { 2932 assert(0, "format() threw."); 2933 } 2934 } 2935 2936 /// 2937 @safe unittest 2938 { 2939 assert(DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12)).toSimpleString() == 2940 "2010-Jul-04 07:06:12"); 2941 2942 assert(DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0)).toSimpleString() == 2943 "1998-Dec-25 02:15:00"); 2944 2945 assert(DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59)).toSimpleString() == 2946 "0000-Jan-05 23:09:59"); 2947 2948 assert(DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2)).toSimpleString() == 2949 "-0004-Jan-05 00:00:02"); 2950 } 2951 2952 @safe unittest 2953 { 2954 // Test A.D. 2955 assert(DateTime(Date(9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "0009-Dec-04 00:00:00"); 2956 assert(DateTime(Date(99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "0099-Dec-04 05:06:12"); 2957 assert(DateTime(Date(999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "0999-Dec-04 13:44:59"); 2958 assert(DateTime(Date(9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "9999-Jul-04 23:59:59"); 2959 assert(DateTime(Date(10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "+10000-Oct-20 01:01:01"); 2960 2961 // Test B.C. 2962 assert(DateTime(Date(0, 12, 4), TimeOfDay(0, 12, 4)).toSimpleString() == "0000-Dec-04 00:12:04"); 2963 assert(DateTime(Date(-9, 12, 4), TimeOfDay(0, 0, 0)).toSimpleString() == "-0009-Dec-04 00:00:00"); 2964 assert(DateTime(Date(-99, 12, 4), TimeOfDay(5, 6, 12)).toSimpleString() == "-0099-Dec-04 05:06:12"); 2965 assert(DateTime(Date(-999, 12, 4), TimeOfDay(13, 44, 59)).toSimpleString() == "-0999-Dec-04 13:44:59"); 2966 assert(DateTime(Date(-9999, 7, 4), TimeOfDay(23, 59, 59)).toSimpleString() == "-9999-Jul-04 23:59:59"); 2967 assert(DateTime(Date(-10000, 10, 20), TimeOfDay(1, 1, 1)).toSimpleString() == "-10000-Oct-20 01:01:01"); 2968 2969 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 2970 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 2971 assert(cdt.toSimpleString() == "1999-Jul-06 12:30:33"); 2972 assert(idt.toSimpleString() == "1999-Jul-06 12:30:33"); 2973 } 2974 2975 2976 /++ 2977 Converts this $(LREF DateTime) to a string. 2978 2979 This function exists to make it easy to convert a $(LREF DateTime) to a 2980 string for code that does not care what the exact format is - just that 2981 it presents the information in a clear manner. It also makes it easy to 2982 simply convert a $(LREF DateTime) to a string when using functions such 2983 as `to!string`, `format`, or `writeln` which use toString to convert 2984 user-defined types. So, it is unlikely that much code will call 2985 toString directly. 2986 2987 The format of the string is purposefully unspecified, and code that 2988 cares about the format of the string should use `toISOString`, 2989 `toISOExtString`, `toSimpleString`, or some other custom formatting 2990 function that explicitly generates the format that the code needs. The 2991 reason is that the code is then clear about what format it's using, 2992 making it less error-prone to maintain the code and interact with other 2993 software that consumes the generated strings. It's for this same reason 2994 that $(LREF DateTime) has no `fromString` function, whereas it does have 2995 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 2996 2997 The format returned by toString may or may not change in the future. 2998 +/ 2999 string toString() const @safe pure nothrow 3000 { 3001 return toSimpleString(); 3002 } 3003 3004 @safe unittest 3005 { 3006 auto dt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3007 const cdt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3008 immutable idt = DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)); 3009 assert(dt.toString()); 3010 assert(cdt.toString()); 3011 assert(idt.toString()); 3012 } 3013 3014 3015 3016 /++ 3017 Creates a $(LREF DateTime) from a string with the format YYYYMMDDTHHMMSS. 3018 Whitespace is stripped from the given string. 3019 3020 Params: 3021 isoString = A string formatted in the ISO format for dates and times. 3022 3023 Throws: 3024 $(REF DateTimeException,std,datetime,date) if the given string is 3025 not in the ISO format or if the resulting $(LREF DateTime) would not 3026 be valid. 3027 +/ 3028 static DateTime fromISOString(S)(in S isoString) @safe pure 3029 if (isSomeString!S) 3030 { 3031 import std.algorithm.searching : countUntil; 3032 import std.exception : enforce; 3033 import std.format : format; 3034 import std.string : strip; 3035 3036 auto str = strip(isoString); 3037 3038 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO String: %s", isoString))); 3039 auto t = str.countUntil('T'); 3040 3041 enforce(t != -1, new DateTimeException(format("Invalid ISO String: %s", isoString))); 3042 3043 immutable date = Date.fromISOString(str[0 .. t]); 3044 immutable tod = TimeOfDay.fromISOString(str[t+1 .. $]); 3045 3046 return DateTime(date, tod); 3047 } 3048 3049 /// 3050 @safe unittest 3051 { 3052 assert(DateTime.fromISOString("20100704T070612") == 3053 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3054 3055 assert(DateTime.fromISOString("19981225T021500") == 3056 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3057 3058 assert(DateTime.fromISOString("00000105T230959") == 3059 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3060 3061 assert(DateTime.fromISOString("-00040105T000002") == 3062 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3063 3064 assert(DateTime.fromISOString(" 20100704T070612 ") == 3065 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3066 } 3067 3068 @safe unittest 3069 { 3070 assertThrown!DateTimeException(DateTime.fromISOString("")); 3071 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3072 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3073 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3074 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3075 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3076 3077 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3078 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3079 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3080 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3081 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3082 3083 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3084 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3085 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3086 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3087 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3088 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3089 3090 assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201")); 3091 assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01")); 3092 3093 assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); 3094 assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3095 assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3096 assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3097 assert(DateTime.fromISOString("19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3098 assert(DateTime.fromISOString(" 19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3099 assert(DateTime.fromISOString(" 19990706T123033 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3100 } 3101 3102 // bug# 17801 3103 @safe unittest 3104 { 3105 import std.conv : to; 3106 import std.meta : AliasSeq; 3107 foreach (C; AliasSeq!(char, wchar, dchar)) 3108 { 3109 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3110 assert(DateTime.fromISOString(to!S("20121221T141516")) == DateTime(2012, 12, 21, 14, 15, 16)); 3111 } 3112 } 3113 3114 3115 /++ 3116 Creates a $(LREF DateTime) from a string with the format 3117 YYYY-MM-DDTHH:MM:SS. Whitespace is stripped from the given string. 3118 3119 Params: 3120 isoExtString = A string formatted in the ISO Extended format for dates 3121 and times. 3122 3123 Throws: 3124 $(REF DateTimeException,std,datetime,date) if the given string is 3125 not in the ISO Extended format or if the resulting $(LREF DateTime) 3126 would not be valid. 3127 +/ 3128 static DateTime fromISOExtString(S)(in S isoExtString) @safe pure 3129 if (isSomeString!(S)) 3130 { 3131 import std.algorithm.searching : countUntil; 3132 import std.exception : enforce; 3133 import std.format : format; 3134 import std.string : strip; 3135 3136 auto str = strip(isoExtString); 3137 3138 enforce(str.length >= 15, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 3139 auto t = str.countUntil('T'); 3140 3141 enforce(t != -1, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 3142 3143 immutable date = Date.fromISOExtString(str[0 .. t]); 3144 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3145 3146 return DateTime(date, tod); 3147 } 3148 3149 /// 3150 @safe unittest 3151 { 3152 assert(DateTime.fromISOExtString("2010-07-04T07:06:12") == 3153 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3154 3155 assert(DateTime.fromISOExtString("1998-12-25T02:15:00") == 3156 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3157 3158 assert(DateTime.fromISOExtString("0000-01-05T23:09:59") == 3159 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3160 3161 assert(DateTime.fromISOExtString("-0004-01-05T00:00:02") == 3162 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3163 3164 assert(DateTime.fromISOExtString(" 2010-07-04T07:06:12 ") == 3165 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3166 } 3167 3168 @safe unittest 3169 { 3170 assertThrown!DateTimeException(DateTime.fromISOExtString("")); 3171 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704000000")); 3172 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704 000000")); 3173 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704t000000")); 3174 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.")); 3175 assertThrown!DateTimeException(DateTime.fromISOExtString("20100704T000000.0")); 3176 3177 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07:0400:00:00")); 3178 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3179 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04 00:00:00")); 3180 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04t00:00:00")); 3181 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.")); 3182 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-07-04T00:00:00.0")); 3183 3184 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-0400:00:00")); 3185 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04t00:00:00")); 3186 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.")); 3187 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Jul-04 00:00:00.0")); 3188 3189 assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201")); 3190 assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01")); 3191 3192 assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); 3193 assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3194 assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3195 assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3196 assert(DateTime.fromISOExtString("1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3197 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3198 assert(DateTime.fromISOExtString(" 1999-07-06T12:30:33 ") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3199 } 3200 3201 // bug# 17801 3202 @safe unittest 3203 { 3204 import std.conv : to; 3205 import std.meta : AliasSeq; 3206 foreach (C; AliasSeq!(char, wchar, dchar)) 3207 { 3208 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3209 assert(DateTime.fromISOExtString(to!S("2012-12-21T14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3210 } 3211 } 3212 3213 3214 /++ 3215 Creates a $(LREF DateTime) from a string with the format 3216 YYYY-Mon-DD HH:MM:SS. Whitespace is stripped from the given string. 3217 3218 Params: 3219 simpleString = A string formatted in the way that toSimpleString 3220 formats dates and times. 3221 3222 Throws: 3223 $(REF DateTimeException,std,datetime,date) if the given string is 3224 not in the correct format or if the resulting $(LREF DateTime) 3225 would not be valid. 3226 +/ 3227 static DateTime fromSimpleString(S)(in S simpleString) @safe pure 3228 if (isSomeString!(S)) 3229 { 3230 import std.algorithm.searching : countUntil; 3231 import std.exception : enforce; 3232 import std.format : format; 3233 import std.string : strip; 3234 3235 auto str = strip(simpleString); 3236 3237 enforce(str.length >= 15, new DateTimeException(format("Invalid string format: %s", simpleString))); 3238 auto t = str.countUntil(' '); 3239 3240 enforce(t != -1, new DateTimeException(format("Invalid string format: %s", simpleString))); 3241 3242 immutable date = Date.fromSimpleString(str[0 .. t]); 3243 immutable tod = TimeOfDay.fromISOExtString(str[t+1 .. $]); 3244 3245 return DateTime(date, tod); 3246 } 3247 3248 /// 3249 @safe unittest 3250 { 3251 assert(DateTime.fromSimpleString("2010-Jul-04 07:06:12") == 3252 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3253 assert(DateTime.fromSimpleString("1998-Dec-25 02:15:00") == 3254 DateTime(Date(1998, 12, 25), TimeOfDay(2, 15, 0))); 3255 assert(DateTime.fromSimpleString("0000-Jan-05 23:09:59") == 3256 DateTime(Date(0, 1, 5), TimeOfDay(23, 9, 59))); 3257 assert(DateTime.fromSimpleString("-0004-Jan-05 00:00:02") == 3258 DateTime(Date(-4, 1, 5), TimeOfDay(0, 0, 2))); 3259 assert(DateTime.fromSimpleString(" 2010-Jul-04 07:06:12 ") == 3260 DateTime(Date(2010, 7, 4), TimeOfDay(7, 6, 12))); 3261 } 3262 3263 @safe unittest 3264 { 3265 assertThrown!DateTimeException(DateTime.fromISOString("")); 3266 assertThrown!DateTimeException(DateTime.fromISOString("20100704000000")); 3267 assertThrown!DateTimeException(DateTime.fromISOString("20100704 000000")); 3268 assertThrown!DateTimeException(DateTime.fromISOString("20100704t000000")); 3269 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.")); 3270 assertThrown!DateTimeException(DateTime.fromISOString("20100704T000000.0")); 3271 3272 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-0400:00:00")); 3273 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04 00:00:00")); 3274 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04t00:00:00")); 3275 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.")); 3276 assertThrown!DateTimeException(DateTime.fromISOString("2010-07-04T00:00:00.0")); 3277 3278 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-0400:00:00")); 3279 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00")); 3280 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04t00:00:00")); 3281 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04T00:00:00")); 3282 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.")); 3283 assertThrown!DateTimeException(DateTime.fromISOString("2010-Jul-04 00:00:00.0")); 3284 3285 assertThrown!DateTimeException(DateTime.fromSimpleString("20101222T172201")); 3286 assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201")); 3287 3288 assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") == 3289 DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01))); 3290 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") == 3291 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3292 assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") == 3293 DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33))); 3294 assert(DateTime.fromSimpleString("+01999-Jul-06 12:30:33") == 3295 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3296 assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33 ") == 3297 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3298 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33") == 3299 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3300 assert(DateTime.fromSimpleString(" 1999-Jul-06 12:30:33 ") == 3301 DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33))); 3302 } 3303 3304 // bug# 17801 3305 @safe unittest 3306 { 3307 import std.conv : to; 3308 import std.meta : AliasSeq; 3309 foreach (C; AliasSeq!(char, wchar, dchar)) 3310 { 3311 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 3312 assert(DateTime.fromSimpleString(to!S("2012-Dec-21 14:15:16")) == DateTime(2012, 12, 21, 14, 15, 16)); 3313 } 3314 } 3315 3316 3317 /++ 3318 Returns the $(LREF DateTime) farthest in the past which is representable 3319 by $(LREF DateTime). 3320 +/ 3321 @property static DateTime min() @safe pure nothrow @nogc 3322 out(result) 3323 { 3324 assert(result._date == Date.min); 3325 assert(result._tod == TimeOfDay.min); 3326 } 3327 body 3328 { 3329 auto dt = DateTime.init; 3330 dt._date._year = short.min; 3331 dt._date._month = Month.jan; 3332 dt._date._day = 1; 3333 3334 return dt; 3335 } 3336 3337 @safe unittest 3338 { 3339 assert(DateTime.min.year < 0); 3340 assert(DateTime.min < DateTime.max); 3341 } 3342 3343 3344 /++ 3345 Returns the $(LREF DateTime) farthest in the future which is 3346 representable by $(LREF DateTime). 3347 +/ 3348 @property static DateTime max() @safe pure nothrow @nogc 3349 out(result) 3350 { 3351 assert(result._date == Date.max); 3352 assert(result._tod == TimeOfDay.max); 3353 } 3354 body 3355 { 3356 auto dt = DateTime.init; 3357 dt._date._year = short.max; 3358 dt._date._month = Month.dec; 3359 dt._date._day = 31; 3360 dt._tod._hour = TimeOfDay.maxHour; 3361 dt._tod._minute = TimeOfDay.maxMinute; 3362 dt._tod._second = TimeOfDay.maxSecond; 3363 3364 return dt; 3365 } 3366 3367 @safe unittest 3368 { 3369 assert(DateTime.max.year > 0); 3370 assert(DateTime.max > DateTime.min); 3371 } 3372 3373 3374 private: 3375 3376 /+ 3377 Add seconds to the time of day. Negative values will subtract. If the 3378 number of seconds overflows (or underflows), then the seconds will wrap, 3379 increasing (or decreasing) the number of minutes accordingly. The 3380 same goes for any larger units. 3381 3382 Params: 3383 seconds = The number of seconds to add to this $(LREF DateTime). 3384 +/ 3385 ref DateTime _addSeconds(long seconds) return @safe pure nothrow @nogc 3386 { 3387 long hnsecs = convert!("seconds", "hnsecs")(seconds); 3388 hnsecs += convert!("hours", "hnsecs")(_tod._hour); 3389 hnsecs += convert!("minutes", "hnsecs")(_tod._minute); 3390 hnsecs += convert!("seconds", "hnsecs")(_tod._second); 3391 3392 auto days = splitUnitsFromHNSecs!"days"(hnsecs); 3393 3394 if (hnsecs < 0) 3395 { 3396 hnsecs += convert!("days", "hnsecs")(1); 3397 --days; 3398 } 3399 3400 _date._addDays(days); 3401 3402 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 3403 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 3404 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 3405 3406 _tod._hour = cast(ubyte) newHours; 3407 _tod._minute = cast(ubyte) newMinutes; 3408 _tod._second = cast(ubyte) newSeconds; 3409 3410 return this; 3411 } 3412 3413 @safe unittest 3414 { 3415 static void testDT(DateTime orig, int seconds, in DateTime expected, size_t line = __LINE__) 3416 { 3417 orig._addSeconds(seconds); 3418 assert(orig == expected); 3419 } 3420 3421 // Test A.D. 3422 testDT(DateTime(1999, 7, 6, 12, 30, 33), 0, DateTime(1999, 7, 6, 12, 30, 33)); 3423 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1, DateTime(1999, 7, 6, 12, 30, 34)); 3424 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2, DateTime(1999, 7, 6, 12, 30, 35)); 3425 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3, DateTime(1999, 7, 6, 12, 30, 36)); 3426 testDT(DateTime(1999, 7, 6, 12, 30, 33), 4, DateTime(1999, 7, 6, 12, 30, 37)); 3427 testDT(DateTime(1999, 7, 6, 12, 30, 33), 5, DateTime(1999, 7, 6, 12, 30, 38)); 3428 testDT(DateTime(1999, 7, 6, 12, 30, 33), 10, DateTime(1999, 7, 6, 12, 30, 43)); 3429 testDT(DateTime(1999, 7, 6, 12, 30, 33), 15, DateTime(1999, 7, 6, 12, 30, 48)); 3430 testDT(DateTime(1999, 7, 6, 12, 30, 33), 26, DateTime(1999, 7, 6, 12, 30, 59)); 3431 testDT(DateTime(1999, 7, 6, 12, 30, 33), 27, DateTime(1999, 7, 6, 12, 31, 0)); 3432 testDT(DateTime(1999, 7, 6, 12, 30, 33), 30, DateTime(1999, 7, 6, 12, 31, 3)); 3433 testDT(DateTime(1999, 7, 6, 12, 30, 33), 59, DateTime(1999, 7, 6, 12, 31, 32)); 3434 testDT(DateTime(1999, 7, 6, 12, 30, 33), 60, DateTime(1999, 7, 6, 12, 31, 33)); 3435 testDT(DateTime(1999, 7, 6, 12, 30, 33), 61, DateTime(1999, 7, 6, 12, 31, 34)); 3436 3437 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1766, DateTime(1999, 7, 6, 12, 59, 59)); 3438 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1767, DateTime(1999, 7, 6, 13, 0, 0)); 3439 testDT(DateTime(1999, 7, 6, 12, 30, 33), 1768, DateTime(1999, 7, 6, 13, 0, 1)); 3440 testDT(DateTime(1999, 7, 6, 12, 30, 33), 2007, DateTime(1999, 7, 6, 13, 4, 0)); 3441 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3599, DateTime(1999, 7, 6, 13, 30, 32)); 3442 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3600, DateTime(1999, 7, 6, 13, 30, 33)); 3443 testDT(DateTime(1999, 7, 6, 12, 30, 33), 3601, DateTime(1999, 7, 6, 13, 30, 34)); 3444 testDT(DateTime(1999, 7, 6, 12, 30, 33), 7200, DateTime(1999, 7, 6, 14, 30, 33)); 3445 testDT(DateTime(1999, 7, 6, 23, 0, 0), 432_123, DateTime(1999, 7, 11, 23, 2, 3)); 3446 3447 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1, DateTime(1999, 7, 6, 12, 30, 32)); 3448 testDT(DateTime(1999, 7, 6, 12, 30, 33), -2, DateTime(1999, 7, 6, 12, 30, 31)); 3449 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3, DateTime(1999, 7, 6, 12, 30, 30)); 3450 testDT(DateTime(1999, 7, 6, 12, 30, 33), -4, DateTime(1999, 7, 6, 12, 30, 29)); 3451 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5, DateTime(1999, 7, 6, 12, 30, 28)); 3452 testDT(DateTime(1999, 7, 6, 12, 30, 33), -10, DateTime(1999, 7, 6, 12, 30, 23)); 3453 testDT(DateTime(1999, 7, 6, 12, 30, 33), -15, DateTime(1999, 7, 6, 12, 30, 18)); 3454 testDT(DateTime(1999, 7, 6, 12, 30, 33), -33, DateTime(1999, 7, 6, 12, 30, 0)); 3455 testDT(DateTime(1999, 7, 6, 12, 30, 33), -34, DateTime(1999, 7, 6, 12, 29, 59)); 3456 testDT(DateTime(1999, 7, 6, 12, 30, 33), -35, DateTime(1999, 7, 6, 12, 29, 58)); 3457 testDT(DateTime(1999, 7, 6, 12, 30, 33), -59, DateTime(1999, 7, 6, 12, 29, 34)); 3458 testDT(DateTime(1999, 7, 6, 12, 30, 33), -60, DateTime(1999, 7, 6, 12, 29, 33)); 3459 testDT(DateTime(1999, 7, 6, 12, 30, 33), -61, DateTime(1999, 7, 6, 12, 29, 32)); 3460 3461 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1833, DateTime(1999, 7, 6, 12, 0, 0)); 3462 testDT(DateTime(1999, 7, 6, 12, 30, 33), -1834, DateTime(1999, 7, 6, 11, 59, 59)); 3463 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3600, DateTime(1999, 7, 6, 11, 30, 33)); 3464 testDT(DateTime(1999, 7, 6, 12, 30, 33), -3601, DateTime(1999, 7, 6, 11, 30, 32)); 3465 testDT(DateTime(1999, 7, 6, 12, 30, 33), -5134, DateTime(1999, 7, 6, 11, 4, 59)); 3466 testDT(DateTime(1999, 7, 6, 23, 0, 0), -432_123, DateTime(1999, 7, 1, 22, 57, 57)); 3467 3468 testDT(DateTime(1999, 7, 6, 12, 30, 0), 1, DateTime(1999, 7, 6, 12, 30, 1)); 3469 testDT(DateTime(1999, 7, 6, 12, 30, 0), 0, DateTime(1999, 7, 6, 12, 30, 0)); 3470 testDT(DateTime(1999, 7, 6, 12, 30, 0), -1, DateTime(1999, 7, 6, 12, 29, 59)); 3471 3472 testDT(DateTime(1999, 7, 6, 12, 0, 0), 1, DateTime(1999, 7, 6, 12, 0, 1)); 3473 testDT(DateTime(1999, 7, 6, 12, 0, 0), 0, DateTime(1999, 7, 6, 12, 0, 0)); 3474 testDT(DateTime(1999, 7, 6, 12, 0, 0), -1, DateTime(1999, 7, 6, 11, 59, 59)); 3475 3476 testDT(DateTime(1999, 7, 6, 0, 0, 0), 1, DateTime(1999, 7, 6, 0, 0, 1)); 3477 testDT(DateTime(1999, 7, 6, 0, 0, 0), 0, DateTime(1999, 7, 6, 0, 0, 0)); 3478 testDT(DateTime(1999, 7, 6, 0, 0, 0), -1, DateTime(1999, 7, 5, 23, 59, 59)); 3479 3480 testDT(DateTime(1999, 7, 5, 23, 59, 59), 1, DateTime(1999, 7, 6, 0, 0, 0)); 3481 testDT(DateTime(1999, 7, 5, 23, 59, 59), 0, DateTime(1999, 7, 5, 23, 59, 59)); 3482 testDT(DateTime(1999, 7, 5, 23, 59, 59), -1, DateTime(1999, 7, 5, 23, 59, 58)); 3483 3484 testDT(DateTime(1998, 12, 31, 23, 59, 59), 1, DateTime(1999, 1, 1, 0, 0, 0)); 3485 testDT(DateTime(1998, 12, 31, 23, 59, 59), 0, DateTime(1998, 12, 31, 23, 59, 59)); 3486 testDT(DateTime(1998, 12, 31, 23, 59, 59), -1, DateTime(1998, 12, 31, 23, 59, 58)); 3487 3488 testDT(DateTime(1998, 1, 1, 0, 0, 0), 1, DateTime(1998, 1, 1, 0, 0, 1)); 3489 testDT(DateTime(1998, 1, 1, 0, 0, 0), 0, DateTime(1998, 1, 1, 0, 0, 0)); 3490 testDT(DateTime(1998, 1, 1, 0, 0, 0), -1, DateTime(1997, 12, 31, 23, 59, 59)); 3491 3492 // Test B.C. 3493 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 0, DateTime(-1999, 7, 6, 12, 30, 33)); 3494 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1, DateTime(-1999, 7, 6, 12, 30, 34)); 3495 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2, DateTime(-1999, 7, 6, 12, 30, 35)); 3496 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3, DateTime(-1999, 7, 6, 12, 30, 36)); 3497 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 4, DateTime(-1999, 7, 6, 12, 30, 37)); 3498 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 5, DateTime(-1999, 7, 6, 12, 30, 38)); 3499 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 10, DateTime(-1999, 7, 6, 12, 30, 43)); 3500 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 15, DateTime(-1999, 7, 6, 12, 30, 48)); 3501 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 26, DateTime(-1999, 7, 6, 12, 30, 59)); 3502 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 27, DateTime(-1999, 7, 6, 12, 31, 0)); 3503 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 30, DateTime(-1999, 7, 6, 12, 31, 3)); 3504 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 59, DateTime(-1999, 7, 6, 12, 31, 32)); 3505 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 60, DateTime(-1999, 7, 6, 12, 31, 33)); 3506 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 61, DateTime(-1999, 7, 6, 12, 31, 34)); 3507 3508 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1766, DateTime(-1999, 7, 6, 12, 59, 59)); 3509 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1767, DateTime(-1999, 7, 6, 13, 0, 0)); 3510 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 1768, DateTime(-1999, 7, 6, 13, 0, 1)); 3511 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 2007, DateTime(-1999, 7, 6, 13, 4, 0)); 3512 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3599, DateTime(-1999, 7, 6, 13, 30, 32)); 3513 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3600, DateTime(-1999, 7, 6, 13, 30, 33)); 3514 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 3601, DateTime(-1999, 7, 6, 13, 30, 34)); 3515 testDT(DateTime(-1999, 7, 6, 12, 30, 33), 7200, DateTime(-1999, 7, 6, 14, 30, 33)); 3516 testDT(DateTime(-1999, 7, 6, 23, 0, 0), 432_123, DateTime(-1999, 7, 11, 23, 2, 3)); 3517 3518 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1, DateTime(-1999, 7, 6, 12, 30, 32)); 3519 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -2, DateTime(-1999, 7, 6, 12, 30, 31)); 3520 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3, DateTime(-1999, 7, 6, 12, 30, 30)); 3521 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -4, DateTime(-1999, 7, 6, 12, 30, 29)); 3522 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5, DateTime(-1999, 7, 6, 12, 30, 28)); 3523 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -10, DateTime(-1999, 7, 6, 12, 30, 23)); 3524 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -15, DateTime(-1999, 7, 6, 12, 30, 18)); 3525 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -33, DateTime(-1999, 7, 6, 12, 30, 0)); 3526 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -34, DateTime(-1999, 7, 6, 12, 29, 59)); 3527 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -35, DateTime(-1999, 7, 6, 12, 29, 58)); 3528 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -59, DateTime(-1999, 7, 6, 12, 29, 34)); 3529 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -60, DateTime(-1999, 7, 6, 12, 29, 33)); 3530 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -61, DateTime(-1999, 7, 6, 12, 29, 32)); 3531 3532 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1833, DateTime(-1999, 7, 6, 12, 0, 0)); 3533 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -1834, DateTime(-1999, 7, 6, 11, 59, 59)); 3534 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3600, DateTime(-1999, 7, 6, 11, 30, 33)); 3535 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -3601, DateTime(-1999, 7, 6, 11, 30, 32)); 3536 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -5134, DateTime(-1999, 7, 6, 11, 4, 59)); 3537 testDT(DateTime(-1999, 7, 6, 12, 30, 33), -7200, DateTime(-1999, 7, 6, 10, 30, 33)); 3538 testDT(DateTime(-1999, 7, 6, 23, 0, 0), -432_123, DateTime(-1999, 7, 1, 22, 57, 57)); 3539 3540 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 1, DateTime(-1999, 7, 6, 12, 30, 1)); 3541 testDT(DateTime(-1999, 7, 6, 12, 30, 0), 0, DateTime(-1999, 7, 6, 12, 30, 0)); 3542 testDT(DateTime(-1999, 7, 6, 12, 30, 0), -1, DateTime(-1999, 7, 6, 12, 29, 59)); 3543 3544 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 1, DateTime(-1999, 7, 6, 12, 0, 1)); 3545 testDT(DateTime(-1999, 7, 6, 12, 0, 0), 0, DateTime(-1999, 7, 6, 12, 0, 0)); 3546 testDT(DateTime(-1999, 7, 6, 12, 0, 0), -1, DateTime(-1999, 7, 6, 11, 59, 59)); 3547 3548 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 1, DateTime(-1999, 7, 6, 0, 0, 1)); 3549 testDT(DateTime(-1999, 7, 6, 0, 0, 0), 0, DateTime(-1999, 7, 6, 0, 0, 0)); 3550 testDT(DateTime(-1999, 7, 6, 0, 0, 0), -1, DateTime(-1999, 7, 5, 23, 59, 59)); 3551 3552 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 1, DateTime(-1999, 7, 6, 0, 0, 0)); 3553 testDT(DateTime(-1999, 7, 5, 23, 59, 59), 0, DateTime(-1999, 7, 5, 23, 59, 59)); 3554 testDT(DateTime(-1999, 7, 5, 23, 59, 59), -1, DateTime(-1999, 7, 5, 23, 59, 58)); 3555 3556 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 1, DateTime(-1999, 1, 1, 0, 0, 0)); 3557 testDT(DateTime(-2000, 12, 31, 23, 59, 59), 0, DateTime(-2000, 12, 31, 23, 59, 59)); 3558 testDT(DateTime(-2000, 12, 31, 23, 59, 59), -1, DateTime(-2000, 12, 31, 23, 59, 58)); 3559 3560 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 1, DateTime(-2000, 1, 1, 0, 0, 1)); 3561 testDT(DateTime(-2000, 1, 1, 0, 0, 0), 0, DateTime(-2000, 1, 1, 0, 0, 0)); 3562 testDT(DateTime(-2000, 1, 1, 0, 0, 0), -1, DateTime(-2001, 12, 31, 23, 59, 59)); 3563 3564 // Test Both 3565 testDT(DateTime(1, 1, 1, 0, 0, 0), -1, DateTime(0, 12, 31, 23, 59, 59)); 3566 testDT(DateTime(0, 12, 31, 23, 59, 59), 1, DateTime(1, 1, 1, 0, 0, 0)); 3567 3568 testDT(DateTime(0, 1, 1, 0, 0, 0), -1, DateTime(-1, 12, 31, 23, 59, 59)); 3569 testDT(DateTime(-1, 12, 31, 23, 59, 59), 1, DateTime(0, 1, 1, 0, 0, 0)); 3570 3571 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_600L, DateTime(1, 1, 1, 13, 30, 33)); 3572 testDT(DateTime(1, 1, 1, 13, 30, 33), -63_165_600L, DateTime(-1, 1, 1, 11, 30, 33)); 3573 3574 testDT(DateTime(-1, 1, 1, 11, 30, 33), 63_165_617L, DateTime(1, 1, 1, 13, 30, 50)); 3575 testDT(DateTime(1, 1, 1, 13, 30, 50), -63_165_617L, DateTime(-1, 1, 1, 11, 30, 33)); 3576 3577 const cdt = DateTime(1999, 7, 6, 12, 30, 33); 3578 immutable idt = DateTime(1999, 7, 6, 12, 30, 33); 3579 static assert(!__traits(compiles, cdt._addSeconds(4))); 3580 static assert(!__traits(compiles, idt._addSeconds(4))); 3581 } 3582 3583 3584 Date _date; 3585 TimeOfDay _tod; 3586 } 3587 3588 3589 /++ 3590 Represents a date in the 3591 $(HTTP en.wikipedia.org/wiki/Proleptic_Gregorian_calendar, Proleptic 3592 Gregorian Calendar) ranging from 32,768 B.C. to 32,767 A.D. Positive years 3593 are A.D. Non-positive years are B.C. 3594 3595 Year, month, and day are kept separately internally so that $(D Date) is 3596 optimized for calendar-based operations. 3597 3598 $(D Date) uses the Proleptic Gregorian Calendar, so it assumes the Gregorian 3599 leap year calculations for its entire length. As per 3600 $(HTTP en.wikipedia.org/wiki/ISO_8601, ISO 8601), it treats 1 B.C. as 3601 year 0, i.e. 1 B.C. is 0, 2 B.C. is -1, etc. Use $(LREF yearBC) to use B.C. 3602 as a positive integer with 1 B.C. being the year prior to 1 A.D. 3603 3604 Year 0 is a leap year. 3605 +/ 3606 struct Date 3607 { 3608 public: 3609 3610 /++ 3611 Throws: 3612 $(REF DateTimeException,std,datetime,date) if the resulting 3613 $(LREF Date) would not be valid. 3614 3615 Params: 3616 year = Year of the Gregorian Calendar. Positive values are A.D. 3617 Non-positive values are B.C. with year 0 being the year 3618 prior to 1 A.D. 3619 month = Month of the year (January is 1). 3620 day = Day of the month. 3621 +/ 3622 this(int year, int month, int day) @safe pure 3623 { 3624 enforceValid!"months"(cast(Month) month); 3625 enforceValid!"days"(year, cast(Month) month, day); 3626 3627 _year = cast(short) year; 3628 _month = cast(Month) month; 3629 _day = cast(ubyte) day; 3630 } 3631 3632 @safe unittest 3633 { 3634 import std.exception : assertNotThrown; 3635 assert(Date(1, 1, 1) == Date.init); 3636 3637 static void testDate(in Date date, int year, int month, int day) 3638 { 3639 assert(date._year == year); 3640 assert(date._month == month); 3641 assert(date._day == day); 3642 } 3643 3644 testDate(Date(1999, 1 , 1), 1999, Month.jan, 1); 3645 testDate(Date(1999, 7 , 1), 1999, Month.jul, 1); 3646 testDate(Date(1999, 7 , 6), 1999, Month.jul, 6); 3647 3648 // Test A.D. 3649 assertThrown!DateTimeException(Date(1, 0, 1)); 3650 assertThrown!DateTimeException(Date(1, 1, 0)); 3651 assertThrown!DateTimeException(Date(1999, 13, 1)); 3652 assertThrown!DateTimeException(Date(1999, 1, 32)); 3653 assertThrown!DateTimeException(Date(1999, 2, 29)); 3654 assertThrown!DateTimeException(Date(2000, 2, 30)); 3655 assertThrown!DateTimeException(Date(1999, 3, 32)); 3656 assertThrown!DateTimeException(Date(1999, 4, 31)); 3657 assertThrown!DateTimeException(Date(1999, 5, 32)); 3658 assertThrown!DateTimeException(Date(1999, 6, 31)); 3659 assertThrown!DateTimeException(Date(1999, 7, 32)); 3660 assertThrown!DateTimeException(Date(1999, 8, 32)); 3661 assertThrown!DateTimeException(Date(1999, 9, 31)); 3662 assertThrown!DateTimeException(Date(1999, 10, 32)); 3663 assertThrown!DateTimeException(Date(1999, 11, 31)); 3664 assertThrown!DateTimeException(Date(1999, 12, 32)); 3665 3666 assertNotThrown!DateTimeException(Date(1999, 1, 31)); 3667 assertNotThrown!DateTimeException(Date(1999, 2, 28)); 3668 assertNotThrown!DateTimeException(Date(2000, 2, 29)); 3669 assertNotThrown!DateTimeException(Date(1999, 3, 31)); 3670 assertNotThrown!DateTimeException(Date(1999, 4, 30)); 3671 assertNotThrown!DateTimeException(Date(1999, 5, 31)); 3672 assertNotThrown!DateTimeException(Date(1999, 6, 30)); 3673 assertNotThrown!DateTimeException(Date(1999, 7, 31)); 3674 assertNotThrown!DateTimeException(Date(1999, 8, 31)); 3675 assertNotThrown!DateTimeException(Date(1999, 9, 30)); 3676 assertNotThrown!DateTimeException(Date(1999, 10, 31)); 3677 assertNotThrown!DateTimeException(Date(1999, 11, 30)); 3678 assertNotThrown!DateTimeException(Date(1999, 12, 31)); 3679 3680 // Test B.C. 3681 assertNotThrown!DateTimeException(Date(0, 1, 1)); 3682 assertNotThrown!DateTimeException(Date(-1, 1, 1)); 3683 assertNotThrown!DateTimeException(Date(-1, 12, 31)); 3684 assertNotThrown!DateTimeException(Date(-1, 2, 28)); 3685 assertNotThrown!DateTimeException(Date(-4, 2, 29)); 3686 3687 assertThrown!DateTimeException(Date(-1, 2, 29)); 3688 assertThrown!DateTimeException(Date(-2, 2, 29)); 3689 assertThrown!DateTimeException(Date(-3, 2, 29)); 3690 } 3691 3692 3693 /++ 3694 Params: 3695 day = The Xth day of the Gregorian Calendar that the constructed 3696 $(LREF Date) will be for. 3697 +/ 3698 this(int day) @safe pure nothrow @nogc 3699 { 3700 if (day > 0) 3701 { 3702 int years = (day / daysIn400Years) * 400 + 1; 3703 day %= daysIn400Years; 3704 3705 { 3706 immutable tempYears = day / daysIn100Years; 3707 3708 if (tempYears == 4) 3709 { 3710 years += 300; 3711 day -= daysIn100Years * 3; 3712 } 3713 else 3714 { 3715 years += tempYears * 100; 3716 day %= daysIn100Years; 3717 } 3718 } 3719 3720 years += (day / daysIn4Years) * 4; 3721 day %= daysIn4Years; 3722 3723 { 3724 immutable tempYears = day / daysInYear; 3725 3726 if (tempYears == 4) 3727 { 3728 years += 3; 3729 day -= daysInYear * 3; 3730 } 3731 else 3732 { 3733 years += tempYears; 3734 day %= daysInYear; 3735 } 3736 } 3737 3738 if (day == 0) 3739 { 3740 _year = cast(short)(years - 1); 3741 _month = Month.dec; 3742 _day = 31; 3743 } 3744 else 3745 { 3746 _year = cast(short) years; 3747 3748 setDayOfYear(day); 3749 } 3750 } 3751 else if (day <= 0 && -day < daysInLeapYear) 3752 { 3753 _year = 0; 3754 3755 setDayOfYear(daysInLeapYear + day); 3756 } 3757 else 3758 { 3759 day += daysInLeapYear - 1; 3760 int years = (day / daysIn400Years) * 400 - 1; 3761 day %= daysIn400Years; 3762 3763 { 3764 immutable tempYears = day / daysIn100Years; 3765 3766 if (tempYears == -4) 3767 { 3768 years -= 300; 3769 day += daysIn100Years * 3; 3770 } 3771 else 3772 { 3773 years += tempYears * 100; 3774 day %= daysIn100Years; 3775 } 3776 } 3777 3778 years += (day / daysIn4Years) * 4; 3779 day %= daysIn4Years; 3780 3781 { 3782 immutable tempYears = day / daysInYear; 3783 3784 if (tempYears == -4) 3785 { 3786 years -= 3; 3787 day += daysInYear * 3; 3788 } 3789 else 3790 { 3791 years += tempYears; 3792 day %= daysInYear; 3793 } 3794 } 3795 3796 if (day == 0) 3797 { 3798 _year = cast(short)(years + 1); 3799 _month = Month.jan; 3800 _day = 1; 3801 } 3802 else 3803 { 3804 _year = cast(short) years; 3805 immutable newDoY = (yearIsLeapYear(_year) ? daysInLeapYear : daysInYear) + day + 1; 3806 3807 setDayOfYear(newDoY); 3808 } 3809 } 3810 } 3811 3812 @safe unittest 3813 { 3814 import std.range : chain; 3815 3816 // Test A.D. 3817 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 3818 assert(Date(gd.day) == gd.date); 3819 } 3820 3821 3822 /++ 3823 Compares this $(LREF Date) with the given $(LREF Date). 3824 3825 Returns: 3826 $(BOOKTABLE, 3827 $(TR $(TD this < rhs) $(TD < 0)) 3828 $(TR $(TD this == rhs) $(TD 0)) 3829 $(TR $(TD this > rhs) $(TD > 0)) 3830 ) 3831 +/ 3832 int opCmp(in Date rhs) const @safe pure nothrow @nogc 3833 { 3834 if (_year < rhs._year) 3835 return -1; 3836 if (_year > rhs._year) 3837 return 1; 3838 3839 if (_month < rhs._month) 3840 return -1; 3841 if (_month > rhs._month) 3842 return 1; 3843 3844 if (_day < rhs._day) 3845 return -1; 3846 if (_day > rhs._day) 3847 return 1; 3848 3849 return 0; 3850 } 3851 3852 @safe unittest 3853 { 3854 // Test A.D. 3855 assert(Date(1, 1, 1).opCmp(Date.init) == 0); 3856 3857 assert(Date(1999, 1, 1).opCmp(Date(1999, 1, 1)) == 0); 3858 assert(Date(1, 7, 1).opCmp(Date(1, 7, 1)) == 0); 3859 assert(Date(1, 1, 6).opCmp(Date(1, 1, 6)) == 0); 3860 3861 assert(Date(1999, 7, 1).opCmp(Date(1999, 7, 1)) == 0); 3862 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 6)) == 0); 3863 3864 assert(Date(1, 7, 6).opCmp(Date(1, 7, 6)) == 0); 3865 3866 assert(Date(1999, 7, 6).opCmp(Date(2000, 7, 6)) < 0); 3867 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 6)) > 0); 3868 assert(Date(1999, 7, 6).opCmp(Date(1999, 8, 6)) < 0); 3869 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 6)) > 0); 3870 assert(Date(1999, 7, 6).opCmp(Date(1999, 7, 7)) < 0); 3871 assert(Date(1999, 7, 7).opCmp(Date(1999, 7, 6)) > 0); 3872 3873 assert(Date(1999, 8, 7).opCmp(Date(2000, 7, 6)) < 0); 3874 assert(Date(2000, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 3875 assert(Date(1999, 7, 7).opCmp(Date(2000, 7, 6)) < 0); 3876 assert(Date(2000, 7, 6).opCmp(Date(1999, 7, 7)) > 0); 3877 assert(Date(1999, 7, 7).opCmp(Date(1999, 8, 6)) < 0); 3878 assert(Date(1999, 8, 6).opCmp(Date(1999, 7, 7)) > 0); 3879 3880 // Test B.C. 3881 assert(Date(0, 1, 1).opCmp(Date(0, 1, 1)) == 0); 3882 assert(Date(-1, 1, 1).opCmp(Date(-1, 1, 1)) == 0); 3883 assert(Date(-1, 7, 1).opCmp(Date(-1, 7, 1)) == 0); 3884 assert(Date(-1, 1, 6).opCmp(Date(-1, 1, 6)) == 0); 3885 3886 assert(Date(-1999, 7, 1).opCmp(Date(-1999, 7, 1)) == 0); 3887 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 6)) == 0); 3888 3889 assert(Date(-1, 7, 6).opCmp(Date(-1, 7, 6)) == 0); 3890 3891 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 6)) < 0); 3892 assert(Date(-1999, 7, 6).opCmp(Date(-2000, 7, 6)) > 0); 3893 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 8, 6)) < 0); 3894 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 6)) > 0); 3895 assert(Date(-1999, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 3896 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 7, 6)) > 0); 3897 3898 assert(Date(-2000, 8, 6).opCmp(Date(-1999, 7, 7)) < 0); 3899 assert(Date(-1999, 8, 7).opCmp(Date(-2000, 7, 6)) > 0); 3900 assert(Date(-2000, 7, 6).opCmp(Date(-1999, 7, 7)) < 0); 3901 assert(Date(-1999, 7, 7).opCmp(Date(-2000, 7, 6)) > 0); 3902 assert(Date(-1999, 7, 7).opCmp(Date(-1999, 8, 6)) < 0); 3903 assert(Date(-1999, 8, 6).opCmp(Date(-1999, 7, 7)) > 0); 3904 3905 // Test Both 3906 assert(Date(-1999, 7, 6).opCmp(Date(1999, 7, 6)) < 0); 3907 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 6)) > 0); 3908 3909 assert(Date(-1999, 8, 6).opCmp(Date(1999, 7, 6)) < 0); 3910 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 6)) > 0); 3911 3912 assert(Date(-1999, 7, 7).opCmp(Date(1999, 7, 6)) < 0); 3913 assert(Date(1999, 7, 6).opCmp(Date(-1999, 7, 7)) > 0); 3914 3915 assert(Date(-1999, 8, 7).opCmp(Date(1999, 7, 6)) < 0); 3916 assert(Date(1999, 7, 6).opCmp(Date(-1999, 8, 7)) > 0); 3917 3918 assert(Date(-1999, 8, 6).opCmp(Date(1999, 6, 6)) < 0); 3919 assert(Date(1999, 6, 8).opCmp(Date(-1999, 7, 6)) > 0); 3920 3921 auto date = Date(1999, 7, 6); 3922 const cdate = Date(1999, 7, 6); 3923 immutable idate = Date(1999, 7, 6); 3924 assert(date.opCmp(date) == 0); 3925 assert(date.opCmp(cdate) == 0); 3926 assert(date.opCmp(idate) == 0); 3927 assert(cdate.opCmp(date) == 0); 3928 assert(cdate.opCmp(cdate) == 0); 3929 assert(cdate.opCmp(idate) == 0); 3930 assert(idate.opCmp(date) == 0); 3931 assert(idate.opCmp(cdate) == 0); 3932 assert(idate.opCmp(idate) == 0); 3933 } 3934 3935 3936 /++ 3937 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 3938 are B.C. 3939 +/ 3940 @property short year() const @safe pure nothrow @nogc 3941 { 3942 return _year; 3943 } 3944 3945 /// 3946 @safe unittest 3947 { 3948 assert(Date(1999, 7, 6).year == 1999); 3949 assert(Date(2010, 10, 4).year == 2010); 3950 assert(Date(-7, 4, 5).year == -7); 3951 } 3952 3953 @safe unittest 3954 { 3955 assert(Date.init.year == 1); 3956 assert(Date(1999, 7, 6).year == 1999); 3957 assert(Date(-1999, 7, 6).year == -1999); 3958 3959 const cdate = Date(1999, 7, 6); 3960 immutable idate = Date(1999, 7, 6); 3961 assert(cdate.year == 1999); 3962 assert(idate.year == 1999); 3963 } 3964 3965 /++ 3966 Year of the Gregorian Calendar. Positive numbers are A.D. Non-positive 3967 are B.C. 3968 3969 Params: 3970 year = The year to set this Date's year to. 3971 3972 Throws: 3973 $(REF DateTimeException,std,datetime,date) if the new year is not 3974 a leap year and the resulting date would be on February 29th. 3975 +/ 3976 @property void year(int year) @safe pure 3977 { 3978 enforceValid!"days"(year, _month, _day); 3979 _year = cast(short) year; 3980 } 3981 3982 /// 3983 @safe unittest 3984 { 3985 assert(Date(1999, 7, 6).year == 1999); 3986 assert(Date(2010, 10, 4).year == 2010); 3987 assert(Date(-7, 4, 5).year == -7); 3988 } 3989 3990 @safe unittest 3991 { 3992 static void testDateInvalid(Date date, int year) 3993 { 3994 date.year = year; 3995 } 3996 3997 static void testDate(Date date, int year, in Date expected) 3998 { 3999 date.year = year; 4000 assert(date == expected); 4001 } 4002 4003 assertThrown!DateTimeException(testDateInvalid(Date(4, 2, 29), 1)); 4004 4005 testDate(Date(1, 1, 1), 1999, Date(1999, 1, 1)); 4006 testDate(Date(1, 1, 1), 0, Date(0, 1, 1)); 4007 testDate(Date(1, 1, 1), -1999, Date(-1999, 1, 1)); 4008 4009 const cdate = Date(1999, 7, 6); 4010 immutable idate = Date(1999, 7, 6); 4011 static assert(!__traits(compiles, cdate.year = 1999)); 4012 static assert(!__traits(compiles, idate.year = 1999)); 4013 } 4014 4015 4016 /++ 4017 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4018 4019 Throws: 4020 $(REF DateTimeException,std,datetime,date) if $(D isAD) is true. 4021 +/ 4022 @property ushort yearBC() const @safe pure 4023 { 4024 import std.format : format; 4025 4026 if (isAD) 4027 throw new DateTimeException(format("Year %s is A.D.", _year)); 4028 return cast(ushort)((_year * -1) + 1); 4029 } 4030 4031 /// 4032 @safe unittest 4033 { 4034 assert(Date(0, 1, 1).yearBC == 1); 4035 assert(Date(-1, 1, 1).yearBC == 2); 4036 assert(Date(-100, 1, 1).yearBC == 101); 4037 } 4038 4039 @safe unittest 4040 { 4041 assertThrown!DateTimeException((in Date date){date.yearBC;}(Date(1, 1, 1))); 4042 4043 auto date = Date(0, 7, 6); 4044 const cdate = Date(0, 7, 6); 4045 immutable idate = Date(0, 7, 6); 4046 assert(date.yearBC == 1); 4047 assert(cdate.yearBC == 1); 4048 assert(idate.yearBC == 1); 4049 } 4050 4051 4052 /++ 4053 Year B.C. of the Gregorian Calendar counting year 0 as 1 B.C. 4054 4055 Params: 4056 year = The year B.C. to set this $(LREF Date)'s year to. 4057 4058 Throws: 4059 $(REF DateTimeException,std,datetime,date) if a non-positive value 4060 is given. 4061 +/ 4062 @property void yearBC(int year) @safe pure 4063 { 4064 if (year <= 0) 4065 throw new DateTimeException("The given year is not a year B.C."); 4066 _year = cast(short)((year - 1) * -1); 4067 } 4068 4069 /// 4070 @safe unittest 4071 { 4072 auto date = Date(2010, 1, 1); 4073 date.yearBC = 1; 4074 assert(date == Date(0, 1, 1)); 4075 4076 date.yearBC = 10; 4077 assert(date == Date(-9, 1, 1)); 4078 } 4079 4080 @safe unittest 4081 { 4082 assertThrown!DateTimeException((Date date){date.yearBC = -1;}(Date(1, 1, 1))); 4083 4084 auto date = Date(0, 7, 6); 4085 const cdate = Date(0, 7, 6); 4086 immutable idate = Date(0, 7, 6); 4087 date.yearBC = 7; 4088 assert(date.yearBC == 7); 4089 static assert(!__traits(compiles, cdate.yearBC = 7)); 4090 static assert(!__traits(compiles, idate.yearBC = 7)); 4091 } 4092 4093 4094 /++ 4095 Month of a Gregorian Year. 4096 +/ 4097 @property Month month() const @safe pure nothrow @nogc 4098 { 4099 return _month; 4100 } 4101 4102 /// 4103 @safe unittest 4104 { 4105 assert(Date(1999, 7, 6).month == 7); 4106 assert(Date(2010, 10, 4).month == 10); 4107 assert(Date(-7, 4, 5).month == 4); 4108 } 4109 4110 @safe unittest 4111 { 4112 assert(Date.init.month == 1); 4113 assert(Date(1999, 7, 6).month == 7); 4114 assert(Date(-1999, 7, 6).month == 7); 4115 4116 const cdate = Date(1999, 7, 6); 4117 immutable idate = Date(1999, 7, 6); 4118 assert(cdate.month == 7); 4119 assert(idate.month == 7); 4120 } 4121 4122 /++ 4123 Month of a Gregorian Year. 4124 4125 Params: 4126 month = The month to set this $(LREF Date)'s month to. 4127 4128 Throws: 4129 $(REF DateTimeException,std,datetime,date) if the given month is 4130 not a valid month or if the current day would not be valid in the 4131 given month. 4132 +/ 4133 @property void month(Month month) @safe pure 4134 { 4135 enforceValid!"months"(month); 4136 enforceValid!"days"(_year, month, _day); 4137 _month = cast(Month) month; 4138 } 4139 4140 @safe unittest 4141 { 4142 static void testDate(Date date, Month month, in Date expected = Date.init) 4143 { 4144 date.month = month; 4145 assert(expected != Date.init); 4146 assert(date == expected); 4147 } 4148 4149 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 0)); 4150 assertThrown!DateTimeException(testDate(Date(1, 1, 1), cast(Month) 13)); 4151 assertThrown!DateTimeException(testDate(Date(1, 1, 29), cast(Month) 2)); 4152 assertThrown!DateTimeException(testDate(Date(0, 1, 30), cast(Month) 2)); 4153 4154 testDate(Date(1, 1, 1), cast(Month) 7, Date(1, 7, 1)); 4155 testDate(Date(-1, 1, 1), cast(Month) 7, Date(-1, 7, 1)); 4156 4157 const cdate = Date(1999, 7, 6); 4158 immutable idate = Date(1999, 7, 6); 4159 static assert(!__traits(compiles, cdate.month = 7)); 4160 static assert(!__traits(compiles, idate.month = 7)); 4161 } 4162 4163 4164 /++ 4165 Day of a Gregorian Month. 4166 +/ 4167 @property ubyte day() const @safe pure nothrow @nogc 4168 { 4169 return _day; 4170 } 4171 4172 /// 4173 @safe unittest 4174 { 4175 assert(Date(1999, 7, 6).day == 6); 4176 assert(Date(2010, 10, 4).day == 4); 4177 assert(Date(-7, 4, 5).day == 5); 4178 } 4179 4180 @safe unittest 4181 { 4182 import std.format : format; 4183 import std.range : chain; 4184 4185 static void test(Date date, int expected) 4186 { 4187 assert(date.day == expected, format("Value given: %s", date)); 4188 } 4189 4190 foreach (year; chain(testYearsBC, testYearsAD)) 4191 { 4192 foreach (md; testMonthDays) 4193 test(Date(year, md.month, md.day), md.day); 4194 } 4195 4196 const cdate = Date(1999, 7, 6); 4197 immutable idate = Date(1999, 7, 6); 4198 assert(cdate.day == 6); 4199 assert(idate.day == 6); 4200 } 4201 4202 /++ 4203 Day of a Gregorian Month. 4204 4205 Params: 4206 day = The day of the month to set this $(LREF Date)'s day to. 4207 4208 Throws: 4209 $(REF DateTimeException,std,datetime,date) if the given day is not 4210 a valid day of the current month. 4211 +/ 4212 @property void day(int day) @safe pure 4213 { 4214 enforceValid!"days"(_year, _month, day); 4215 _day = cast(ubyte) day; 4216 } 4217 4218 @safe unittest 4219 { 4220 import std.exception : assertNotThrown; 4221 4222 static void testDate(Date date, int day) 4223 { 4224 date.day = day; 4225 } 4226 4227 // Test A.D. 4228 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 0)); 4229 assertThrown!DateTimeException(testDate(Date(1, 1, 1), 32)); 4230 assertThrown!DateTimeException(testDate(Date(1, 2, 1), 29)); 4231 assertThrown!DateTimeException(testDate(Date(4, 2, 1), 30)); 4232 assertThrown!DateTimeException(testDate(Date(1, 3, 1), 32)); 4233 assertThrown!DateTimeException(testDate(Date(1, 4, 1), 31)); 4234 assertThrown!DateTimeException(testDate(Date(1, 5, 1), 32)); 4235 assertThrown!DateTimeException(testDate(Date(1, 6, 1), 31)); 4236 assertThrown!DateTimeException(testDate(Date(1, 7, 1), 32)); 4237 assertThrown!DateTimeException(testDate(Date(1, 8, 1), 32)); 4238 assertThrown!DateTimeException(testDate(Date(1, 9, 1), 31)); 4239 assertThrown!DateTimeException(testDate(Date(1, 10, 1), 32)); 4240 assertThrown!DateTimeException(testDate(Date(1, 11, 1), 31)); 4241 assertThrown!DateTimeException(testDate(Date(1, 12, 1), 32)); 4242 4243 assertNotThrown!DateTimeException(testDate(Date(1, 1, 1), 31)); 4244 assertNotThrown!DateTimeException(testDate(Date(1, 2, 1), 28)); 4245 assertNotThrown!DateTimeException(testDate(Date(4, 2, 1), 29)); 4246 assertNotThrown!DateTimeException(testDate(Date(1, 3, 1), 31)); 4247 assertNotThrown!DateTimeException(testDate(Date(1, 4, 1), 30)); 4248 assertNotThrown!DateTimeException(testDate(Date(1, 5, 1), 31)); 4249 assertNotThrown!DateTimeException(testDate(Date(1, 6, 1), 30)); 4250 assertNotThrown!DateTimeException(testDate(Date(1, 7, 1), 31)); 4251 assertNotThrown!DateTimeException(testDate(Date(1, 8, 1), 31)); 4252 assertNotThrown!DateTimeException(testDate(Date(1, 9, 1), 30)); 4253 assertNotThrown!DateTimeException(testDate(Date(1, 10, 1), 31)); 4254 assertNotThrown!DateTimeException(testDate(Date(1, 11, 1), 30)); 4255 assertNotThrown!DateTimeException(testDate(Date(1, 12, 1), 31)); 4256 4257 { 4258 auto date = Date(1, 1, 1); 4259 date.day = 6; 4260 assert(date == Date(1, 1, 6)); 4261 } 4262 4263 // Test B.C. 4264 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 0)); 4265 assertThrown!DateTimeException(testDate(Date(-1, 1, 1), 32)); 4266 assertThrown!DateTimeException(testDate(Date(-1, 2, 1), 29)); 4267 assertThrown!DateTimeException(testDate(Date(0, 2, 1), 30)); 4268 assertThrown!DateTimeException(testDate(Date(-1, 3, 1), 32)); 4269 assertThrown!DateTimeException(testDate(Date(-1, 4, 1), 31)); 4270 assertThrown!DateTimeException(testDate(Date(-1, 5, 1), 32)); 4271 assertThrown!DateTimeException(testDate(Date(-1, 6, 1), 31)); 4272 assertThrown!DateTimeException(testDate(Date(-1, 7, 1), 32)); 4273 assertThrown!DateTimeException(testDate(Date(-1, 8, 1), 32)); 4274 assertThrown!DateTimeException(testDate(Date(-1, 9, 1), 31)); 4275 assertThrown!DateTimeException(testDate(Date(-1, 10, 1), 32)); 4276 assertThrown!DateTimeException(testDate(Date(-1, 11, 1), 31)); 4277 assertThrown!DateTimeException(testDate(Date(-1, 12, 1), 32)); 4278 4279 assertNotThrown!DateTimeException(testDate(Date(-1, 1, 1), 31)); 4280 assertNotThrown!DateTimeException(testDate(Date(-1, 2, 1), 28)); 4281 assertNotThrown!DateTimeException(testDate(Date(0, 2, 1), 29)); 4282 assertNotThrown!DateTimeException(testDate(Date(-1, 3, 1), 31)); 4283 assertNotThrown!DateTimeException(testDate(Date(-1, 4, 1), 30)); 4284 assertNotThrown!DateTimeException(testDate(Date(-1, 5, 1), 31)); 4285 assertNotThrown!DateTimeException(testDate(Date(-1, 6, 1), 30)); 4286 assertNotThrown!DateTimeException(testDate(Date(-1, 7, 1), 31)); 4287 assertNotThrown!DateTimeException(testDate(Date(-1, 8, 1), 31)); 4288 assertNotThrown!DateTimeException(testDate(Date(-1, 9, 1), 30)); 4289 assertNotThrown!DateTimeException(testDate(Date(-1, 10, 1), 31)); 4290 assertNotThrown!DateTimeException(testDate(Date(-1, 11, 1), 30)); 4291 assertNotThrown!DateTimeException(testDate(Date(-1, 12, 1), 31)); 4292 4293 { 4294 auto date = Date(-1, 1, 1); 4295 date.day = 6; 4296 assert(date == Date(-1, 1, 6)); 4297 } 4298 4299 const cdate = Date(1999, 7, 6); 4300 immutable idate = Date(1999, 7, 6); 4301 static assert(!__traits(compiles, cdate.day = 6)); 4302 static assert(!__traits(compiles, idate.day = 6)); 4303 } 4304 4305 4306 /++ 4307 Adds the given number of years or months to this $(LREF Date). A 4308 negative number will subtract. 4309 4310 Note that if day overflow is allowed, and the date with the adjusted 4311 year/month overflows the number of days in the new month, then the month 4312 will be incremented by one, and the day set to the number of days 4313 overflowed. (e.g. if the day were 31 and the new month were June, then 4314 the month would be incremented to July, and the new day would be 1). If 4315 day overflow is not allowed, then the day will be set to the last valid 4316 day in the month (e.g. June 31st would become June 30th). 4317 4318 Params: 4319 units = The type of units to add ("years" or "months"). 4320 value = The number of months or years to add to this 4321 $(LREF Date). 4322 allowOverflow = Whether the day should be allowed to overflow, 4323 causing the month to increment. 4324 +/ 4325 @safe pure nothrow @nogc 4326 ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4327 if (units == "years") 4328 { 4329 _year += value; 4330 4331 if (_month == Month.feb && _day == 29 && !yearIsLeapYear(_year)) 4332 { 4333 if (allowOverflow == AllowDayOverflow.yes) 4334 { 4335 _month = Month.mar; 4336 _day = 1; 4337 } 4338 else 4339 _day = 28; 4340 } 4341 4342 return this; 4343 } 4344 4345 /// 4346 @safe unittest 4347 { 4348 auto d1 = Date(2010, 1, 1); 4349 d1.add!"months"(11); 4350 assert(d1 == Date(2010, 12, 1)); 4351 4352 auto d2 = Date(2010, 1, 1); 4353 d2.add!"months"(-11); 4354 assert(d2 == Date(2009, 2, 1)); 4355 4356 auto d3 = Date(2000, 2, 29); 4357 d3.add!"years"(1); 4358 assert(d3 == Date(2001, 3, 1)); 4359 4360 auto d4 = Date(2000, 2, 29); 4361 d4.add!"years"(1, AllowDayOverflow.no); 4362 assert(d4 == Date(2001, 2, 28)); 4363 } 4364 4365 // Test add!"years"() with AllowDayOverflow.yes 4366 @safe unittest 4367 { 4368 // Test A.D. 4369 { 4370 auto date = Date(1999, 7, 6); 4371 date.add!"years"(7); 4372 assert(date == Date(2006, 7, 6)); 4373 date.add!"years"(-9); 4374 assert(date == Date(1997, 7, 6)); 4375 } 4376 4377 { 4378 auto date = Date(1999, 2, 28); 4379 date.add!"years"(1); 4380 assert(date == Date(2000, 2, 28)); 4381 } 4382 4383 { 4384 auto date = Date(2000, 2, 29); 4385 date.add!"years"(-1); 4386 assert(date == Date(1999, 3, 1)); 4387 } 4388 4389 // Test B.C. 4390 { 4391 auto date = Date(-1999, 7, 6); 4392 date.add!"years"(-7); 4393 assert(date == Date(-2006, 7, 6)); 4394 date.add!"years"(9); 4395 assert(date == Date(-1997, 7, 6)); 4396 } 4397 4398 { 4399 auto date = Date(-1999, 2, 28); 4400 date.add!"years"(-1); 4401 assert(date == Date(-2000, 2, 28)); 4402 } 4403 4404 { 4405 auto date = Date(-2000, 2, 29); 4406 date.add!"years"(1); 4407 assert(date == Date(-1999, 3, 1)); 4408 } 4409 4410 // Test Both 4411 { 4412 auto date = Date(4, 7, 6); 4413 date.add!"years"(-5); 4414 assert(date == Date(-1, 7, 6)); 4415 date.add!"years"(5); 4416 assert(date == Date(4, 7, 6)); 4417 } 4418 4419 { 4420 auto date = Date(-4, 7, 6); 4421 date.add!"years"(5); 4422 assert(date == Date(1, 7, 6)); 4423 date.add!"years"(-5); 4424 assert(date == Date(-4, 7, 6)); 4425 } 4426 4427 { 4428 auto date = Date(4, 7, 6); 4429 date.add!"years"(-8); 4430 assert(date == Date(-4, 7, 6)); 4431 date.add!"years"(8); 4432 assert(date == Date(4, 7, 6)); 4433 } 4434 4435 { 4436 auto date = Date(-4, 7, 6); 4437 date.add!"years"(8); 4438 assert(date == Date(4, 7, 6)); 4439 date.add!"years"(-8); 4440 assert(date == Date(-4, 7, 6)); 4441 } 4442 4443 { 4444 auto date = Date(-4, 2, 29); 4445 date.add!"years"(5); 4446 assert(date == Date(1, 3, 1)); 4447 } 4448 4449 { 4450 auto date = Date(4, 2, 29); 4451 date.add!"years"(-5); 4452 assert(date == Date(-1, 3, 1)); 4453 } 4454 4455 { 4456 auto date = Date(4, 2, 29); 4457 date.add!"years"(-5).add!"years"(7); 4458 assert(date == Date(6, 3, 1)); 4459 } 4460 4461 const cdate = Date(1999, 7, 6); 4462 immutable idate = Date(1999, 7, 6); 4463 static assert(!__traits(compiles, cdate.add!"years"(7))); 4464 static assert(!__traits(compiles, idate.add!"years"(7))); 4465 } 4466 4467 // Test add!"years"() with AllowDayOverflow.no 4468 @safe unittest 4469 { 4470 // Test A.D. 4471 { 4472 auto date = Date(1999, 7, 6); 4473 date.add!"years"(7, AllowDayOverflow.no); 4474 assert(date == Date(2006, 7, 6)); 4475 date.add!"years"(-9, AllowDayOverflow.no); 4476 assert(date == Date(1997, 7, 6)); 4477 } 4478 4479 { 4480 auto date = Date(1999, 2, 28); 4481 date.add!"years"(1, AllowDayOverflow.no); 4482 assert(date == Date(2000, 2, 28)); 4483 } 4484 4485 { 4486 auto date = Date(2000, 2, 29); 4487 date.add!"years"(-1, AllowDayOverflow.no); 4488 assert(date == Date(1999, 2, 28)); 4489 } 4490 4491 // Test B.C. 4492 { 4493 auto date = Date(-1999, 7, 6); 4494 date.add!"years"(-7, AllowDayOverflow.no); 4495 assert(date == Date(-2006, 7, 6)); 4496 date.add!"years"(9, AllowDayOverflow.no); 4497 assert(date == Date(-1997, 7, 6)); 4498 } 4499 4500 { 4501 auto date = Date(-1999, 2, 28); 4502 date.add!"years"(-1, AllowDayOverflow.no); 4503 assert(date == Date(-2000, 2, 28)); 4504 } 4505 4506 { 4507 auto date = Date(-2000, 2, 29); 4508 date.add!"years"(1, AllowDayOverflow.no); 4509 assert(date == Date(-1999, 2, 28)); 4510 } 4511 4512 // Test Both 4513 { 4514 auto date = Date(4, 7, 6); 4515 date.add!"years"(-5, AllowDayOverflow.no); 4516 assert(date == Date(-1, 7, 6)); 4517 date.add!"years"(5, AllowDayOverflow.no); 4518 assert(date == Date(4, 7, 6)); 4519 } 4520 4521 { 4522 auto date = Date(-4, 7, 6); 4523 date.add!"years"(5, AllowDayOverflow.no); 4524 assert(date == Date(1, 7, 6)); 4525 date.add!"years"(-5, AllowDayOverflow.no); 4526 assert(date == Date(-4, 7, 6)); 4527 } 4528 4529 { 4530 auto date = Date(4, 7, 6); 4531 date.add!"years"(-8, AllowDayOverflow.no); 4532 assert(date == Date(-4, 7, 6)); 4533 date.add!"years"(8, AllowDayOverflow.no); 4534 assert(date == Date(4, 7, 6)); 4535 } 4536 4537 { 4538 auto date = Date(-4, 7, 6); 4539 date.add!"years"(8, AllowDayOverflow.no); 4540 assert(date == Date(4, 7, 6)); 4541 date.add!"years"(-8, AllowDayOverflow.no); 4542 assert(date == Date(-4, 7, 6)); 4543 } 4544 4545 { 4546 auto date = Date(-4, 2, 29); 4547 date.add!"years"(5, AllowDayOverflow.no); 4548 assert(date == Date(1, 2, 28)); 4549 } 4550 4551 { 4552 auto date = Date(4, 2, 29); 4553 date.add!"years"(-5, AllowDayOverflow.no); 4554 assert(date == Date(-1, 2, 28)); 4555 } 4556 4557 { 4558 auto date = Date(4, 2, 29); 4559 date.add!"years"(-5, AllowDayOverflow.no).add!"years"(7, AllowDayOverflow.no); 4560 assert(date == Date(6, 2, 28)); 4561 } 4562 } 4563 4564 4565 // Shares documentation with "years" version. 4566 @safe pure nothrow @nogc 4567 ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 4568 if (units == "months") 4569 { 4570 auto years = months / 12; 4571 months %= 12; 4572 auto newMonth = _month + months; 4573 4574 if (months < 0) 4575 { 4576 if (newMonth < 1) 4577 { 4578 newMonth += 12; 4579 --years; 4580 } 4581 } 4582 else if (newMonth > 12) 4583 { 4584 newMonth -= 12; 4585 ++years; 4586 } 4587 4588 _year += years; 4589 _month = cast(Month) newMonth; 4590 4591 immutable currMaxDay = maxDay(_year, _month); 4592 immutable overflow = _day - currMaxDay; 4593 4594 if (overflow > 0) 4595 { 4596 if (allowOverflow == AllowDayOverflow.yes) 4597 { 4598 ++_month; 4599 _day = cast(ubyte) overflow; 4600 } 4601 else 4602 _day = cast(ubyte) currMaxDay; 4603 } 4604 4605 return this; 4606 } 4607 4608 // Test add!"months"() with AllowDayOverflow.yes 4609 @safe unittest 4610 { 4611 // Test A.D. 4612 { 4613 auto date = Date(1999, 7, 6); 4614 date.add!"months"(3); 4615 assert(date == Date(1999, 10, 6)); 4616 date.add!"months"(-4); 4617 assert(date == Date(1999, 6, 6)); 4618 } 4619 4620 { 4621 auto date = Date(1999, 7, 6); 4622 date.add!"months"(6); 4623 assert(date == Date(2000, 1, 6)); 4624 date.add!"months"(-6); 4625 assert(date == Date(1999, 7, 6)); 4626 } 4627 4628 { 4629 auto date = Date(1999, 7, 6); 4630 date.add!"months"(27); 4631 assert(date == Date(2001, 10, 6)); 4632 date.add!"months"(-28); 4633 assert(date == Date(1999, 6, 6)); 4634 } 4635 4636 { 4637 auto date = Date(1999, 5, 31); 4638 date.add!"months"(1); 4639 assert(date == Date(1999, 7, 1)); 4640 } 4641 4642 { 4643 auto date = Date(1999, 5, 31); 4644 date.add!"months"(-1); 4645 assert(date == Date(1999, 5, 1)); 4646 } 4647 4648 { 4649 auto date = Date(1999, 2, 28); 4650 date.add!"months"(12); 4651 assert(date == Date(2000, 2, 28)); 4652 } 4653 4654 { 4655 auto date = Date(2000, 2, 29); 4656 date.add!"months"(12); 4657 assert(date == Date(2001, 3, 1)); 4658 } 4659 4660 { 4661 auto date = Date(1999, 7, 31); 4662 date.add!"months"(1); 4663 assert(date == Date(1999, 8, 31)); 4664 date.add!"months"(1); 4665 assert(date == Date(1999, 10, 1)); 4666 } 4667 4668 { 4669 auto date = Date(1998, 8, 31); 4670 date.add!"months"(13); 4671 assert(date == Date(1999, 10, 1)); 4672 date.add!"months"(-13); 4673 assert(date == Date(1998, 9, 1)); 4674 } 4675 4676 { 4677 auto date = Date(1997, 12, 31); 4678 date.add!"months"(13); 4679 assert(date == Date(1999, 1, 31)); 4680 date.add!"months"(-13); 4681 assert(date == Date(1997, 12, 31)); 4682 } 4683 4684 { 4685 auto date = Date(1997, 12, 31); 4686 date.add!"months"(14); 4687 assert(date == Date(1999, 3, 3)); 4688 date.add!"months"(-14); 4689 assert(date == Date(1998, 1, 3)); 4690 } 4691 4692 { 4693 auto date = Date(1998, 12, 31); 4694 date.add!"months"(14); 4695 assert(date == Date(2000, 3, 2)); 4696 date.add!"months"(-14); 4697 assert(date == Date(1999, 1, 2)); 4698 } 4699 4700 { 4701 auto date = Date(1999, 12, 31); 4702 date.add!"months"(14); 4703 assert(date == Date(2001, 3, 3)); 4704 date.add!"months"(-14); 4705 assert(date == Date(2000, 1, 3)); 4706 } 4707 4708 // Test B.C. 4709 { 4710 auto date = Date(-1999, 7, 6); 4711 date.add!"months"(3); 4712 assert(date == Date(-1999, 10, 6)); 4713 date.add!"months"(-4); 4714 assert(date == Date(-1999, 6, 6)); 4715 } 4716 4717 { 4718 auto date = Date(-1999, 7, 6); 4719 date.add!"months"(6); 4720 assert(date == Date(-1998, 1, 6)); 4721 date.add!"months"(-6); 4722 assert(date == Date(-1999, 7, 6)); 4723 } 4724 4725 { 4726 auto date = Date(-1999, 7, 6); 4727 date.add!"months"(-27); 4728 assert(date == Date(-2001, 4, 6)); 4729 date.add!"months"(28); 4730 assert(date == Date(-1999, 8, 6)); 4731 } 4732 4733 { 4734 auto date = Date(-1999, 5, 31); 4735 date.add!"months"(1); 4736 assert(date == Date(-1999, 7, 1)); 4737 } 4738 4739 { 4740 auto date = Date(-1999, 5, 31); 4741 date.add!"months"(-1); 4742 assert(date == Date(-1999, 5, 1)); 4743 } 4744 4745 { 4746 auto date = Date(-1999, 2, 28); 4747 date.add!"months"(-12); 4748 assert(date == Date(-2000, 2, 28)); 4749 } 4750 4751 { 4752 auto date = Date(-2000, 2, 29); 4753 date.add!"months"(-12); 4754 assert(date == Date(-2001, 3, 1)); 4755 } 4756 4757 { 4758 auto date = Date(-1999, 7, 31); 4759 date.add!"months"(1); 4760 assert(date == Date(-1999, 8, 31)); 4761 date.add!"months"(1); 4762 assert(date == Date(-1999, 10, 1)); 4763 } 4764 4765 { 4766 auto date = Date(-1998, 8, 31); 4767 date.add!"months"(13); 4768 assert(date == Date(-1997, 10, 1)); 4769 date.add!"months"(-13); 4770 assert(date == Date(-1998, 9, 1)); 4771 } 4772 4773 { 4774 auto date = Date(-1997, 12, 31); 4775 date.add!"months"(13); 4776 assert(date == Date(-1995, 1, 31)); 4777 date.add!"months"(-13); 4778 assert(date == Date(-1997, 12, 31)); 4779 } 4780 4781 { 4782 auto date = Date(-1997, 12, 31); 4783 date.add!"months"(14); 4784 assert(date == Date(-1995, 3, 3)); 4785 date.add!"months"(-14); 4786 assert(date == Date(-1996, 1, 3)); 4787 } 4788 4789 { 4790 auto date = Date(-2002, 12, 31); 4791 date.add!"months"(14); 4792 assert(date == Date(-2000, 3, 2)); 4793 date.add!"months"(-14); 4794 assert(date == Date(-2001, 1, 2)); 4795 } 4796 4797 { 4798 auto date = Date(-2001, 12, 31); 4799 date.add!"months"(14); 4800 assert(date == Date(-1999, 3, 3)); 4801 date.add!"months"(-14); 4802 assert(date == Date(-2000, 1, 3)); 4803 } 4804 4805 // Test Both 4806 { 4807 auto date = Date(1, 1, 1); 4808 date.add!"months"(-1); 4809 assert(date == Date(0, 12, 1)); 4810 date.add!"months"(1); 4811 assert(date == Date(1, 1, 1)); 4812 } 4813 4814 { 4815 auto date = Date(4, 1, 1); 4816 date.add!"months"(-48); 4817 assert(date == Date(0, 1, 1)); 4818 date.add!"months"(48); 4819 assert(date == Date(4, 1, 1)); 4820 } 4821 4822 { 4823 auto date = Date(4, 3, 31); 4824 date.add!"months"(-49); 4825 assert(date == Date(0, 3, 2)); 4826 date.add!"months"(49); 4827 assert(date == Date(4, 4, 2)); 4828 } 4829 4830 { 4831 auto date = Date(4, 3, 31); 4832 date.add!"months"(-85); 4833 assert(date == Date(-3, 3, 3)); 4834 date.add!"months"(85); 4835 assert(date == Date(4, 4, 3)); 4836 } 4837 4838 { 4839 auto date = Date(-3, 3, 31); 4840 date.add!"months"(85).add!"months"(-83); 4841 assert(date == Date(-3, 6, 1)); 4842 } 4843 4844 const cdate = Date(1999, 7, 6); 4845 immutable idate = Date(1999, 7, 6); 4846 static assert(!__traits(compiles, cdate.add!"months"(3))); 4847 static assert(!__traits(compiles, idate.add!"months"(3))); 4848 } 4849 4850 // Test add!"months"() with AllowDayOverflow.no 4851 @safe unittest 4852 { 4853 // Test A.D. 4854 { 4855 auto date = Date(1999, 7, 6); 4856 date.add!"months"(3, AllowDayOverflow.no); 4857 assert(date == Date(1999, 10, 6)); 4858 date.add!"months"(-4, AllowDayOverflow.no); 4859 assert(date == Date(1999, 6, 6)); 4860 } 4861 4862 { 4863 auto date = Date(1999, 7, 6); 4864 date.add!"months"(6, AllowDayOverflow.no); 4865 assert(date == Date(2000, 1, 6)); 4866 date.add!"months"(-6, AllowDayOverflow.no); 4867 assert(date == Date(1999, 7, 6)); 4868 } 4869 4870 { 4871 auto date = Date(1999, 7, 6); 4872 date.add!"months"(27, AllowDayOverflow.no); 4873 assert(date == Date(2001, 10, 6)); 4874 date.add!"months"(-28, AllowDayOverflow.no); 4875 assert(date == Date(1999, 6, 6)); 4876 } 4877 4878 { 4879 auto date = Date(1999, 5, 31); 4880 date.add!"months"(1, AllowDayOverflow.no); 4881 assert(date == Date(1999, 6, 30)); 4882 } 4883 4884 { 4885 auto date = Date(1999, 5, 31); 4886 date.add!"months"(-1, AllowDayOverflow.no); 4887 assert(date == Date(1999, 4, 30)); 4888 } 4889 4890 { 4891 auto date = Date(1999, 2, 28); 4892 date.add!"months"(12, AllowDayOverflow.no); 4893 assert(date == Date(2000, 2, 28)); 4894 } 4895 4896 { 4897 auto date = Date(2000, 2, 29); 4898 date.add!"months"(12, AllowDayOverflow.no); 4899 assert(date == Date(2001, 2, 28)); 4900 } 4901 4902 { 4903 auto date = Date(1999, 7, 31); 4904 date.add!"months"(1, AllowDayOverflow.no); 4905 assert(date == Date(1999, 8, 31)); 4906 date.add!"months"(1, AllowDayOverflow.no); 4907 assert(date == Date(1999, 9, 30)); 4908 } 4909 4910 { 4911 auto date = Date(1998, 8, 31); 4912 date.add!"months"(13, AllowDayOverflow.no); 4913 assert(date == Date(1999, 9, 30)); 4914 date.add!"months"(-13, AllowDayOverflow.no); 4915 assert(date == Date(1998, 8, 30)); 4916 } 4917 4918 { 4919 auto date = Date(1997, 12, 31); 4920 date.add!"months"(13, AllowDayOverflow.no); 4921 assert(date == Date(1999, 1, 31)); 4922 date.add!"months"(-13, AllowDayOverflow.no); 4923 assert(date == Date(1997, 12, 31)); 4924 } 4925 4926 { 4927 auto date = Date(1997, 12, 31); 4928 date.add!"months"(14, AllowDayOverflow.no); 4929 assert(date == Date(1999, 2, 28)); 4930 date.add!"months"(-14, AllowDayOverflow.no); 4931 assert(date == Date(1997, 12, 28)); 4932 } 4933 4934 { 4935 auto date = Date(1998, 12, 31); 4936 date.add!"months"(14, AllowDayOverflow.no); 4937 assert(date == Date(2000, 2, 29)); 4938 date.add!"months"(-14, AllowDayOverflow.no); 4939 assert(date == Date(1998, 12, 29)); 4940 } 4941 4942 { 4943 auto date = Date(1999, 12, 31); 4944 date.add!"months"(14, AllowDayOverflow.no); 4945 assert(date == Date(2001, 2, 28)); 4946 date.add!"months"(-14, AllowDayOverflow.no); 4947 assert(date == Date(1999, 12, 28)); 4948 } 4949 4950 // Test B.C. 4951 { 4952 auto date = Date(-1999, 7, 6); 4953 date.add!"months"(3, AllowDayOverflow.no); 4954 assert(date == Date(-1999, 10, 6)); 4955 date.add!"months"(-4, AllowDayOverflow.no); 4956 assert(date == Date(-1999, 6, 6)); 4957 } 4958 4959 { 4960 auto date = Date(-1999, 7, 6); 4961 date.add!"months"(6, AllowDayOverflow.no); 4962 assert(date == Date(-1998, 1, 6)); 4963 date.add!"months"(-6, AllowDayOverflow.no); 4964 assert(date == Date(-1999, 7, 6)); 4965 } 4966 4967 { 4968 auto date = Date(-1999, 7, 6); 4969 date.add!"months"(-27, AllowDayOverflow.no); 4970 assert(date == Date(-2001, 4, 6)); 4971 date.add!"months"(28, AllowDayOverflow.no); 4972 assert(date == Date(-1999, 8, 6)); 4973 } 4974 4975 { 4976 auto date = Date(-1999, 5, 31); 4977 date.add!"months"(1, AllowDayOverflow.no); 4978 assert(date == Date(-1999, 6, 30)); 4979 } 4980 4981 { 4982 auto date = Date(-1999, 5, 31); 4983 date.add!"months"(-1, AllowDayOverflow.no); 4984 assert(date == Date(-1999, 4, 30)); 4985 } 4986 4987 { 4988 auto date = Date(-1999, 2, 28); 4989 date.add!"months"(-12, AllowDayOverflow.no); 4990 assert(date == Date(-2000, 2, 28)); 4991 } 4992 4993 { 4994 auto date = Date(-2000, 2, 29); 4995 date.add!"months"(-12, AllowDayOverflow.no); 4996 assert(date == Date(-2001, 2, 28)); 4997 } 4998 4999 { 5000 auto date = Date(-1999, 7, 31); 5001 date.add!"months"(1, AllowDayOverflow.no); 5002 assert(date == Date(-1999, 8, 31)); 5003 date.add!"months"(1, AllowDayOverflow.no); 5004 assert(date == Date(-1999, 9, 30)); 5005 } 5006 5007 { 5008 auto date = Date(-1998, 8, 31); 5009 date.add!"months"(13, AllowDayOverflow.no); 5010 assert(date == Date(-1997, 9, 30)); 5011 date.add!"months"(-13, AllowDayOverflow.no); 5012 assert(date == Date(-1998, 8, 30)); 5013 } 5014 5015 { 5016 auto date = Date(-1997, 12, 31); 5017 date.add!"months"(13, AllowDayOverflow.no); 5018 assert(date == Date(-1995, 1, 31)); 5019 date.add!"months"(-13, AllowDayOverflow.no); 5020 assert(date == Date(-1997, 12, 31)); 5021 } 5022 5023 { 5024 auto date = Date(-1997, 12, 31); 5025 date.add!"months"(14, AllowDayOverflow.no); 5026 assert(date == Date(-1995, 2, 28)); 5027 date.add!"months"(-14, AllowDayOverflow.no); 5028 assert(date == Date(-1997, 12, 28)); 5029 } 5030 5031 { 5032 auto date = Date(-2002, 12, 31); 5033 date.add!"months"(14, AllowDayOverflow.no); 5034 assert(date == Date(-2000, 2, 29)); 5035 date.add!"months"(-14, AllowDayOverflow.no); 5036 assert(date == Date(-2002, 12, 29)); 5037 } 5038 5039 { 5040 auto date = Date(-2001, 12, 31); 5041 date.add!"months"(14, AllowDayOverflow.no); 5042 assert(date == Date(-1999, 2, 28)); 5043 date.add!"months"(-14, AllowDayOverflow.no); 5044 assert(date == Date(-2001, 12, 28)); 5045 } 5046 5047 // Test Both 5048 { 5049 auto date = Date(1, 1, 1); 5050 date.add!"months"(-1, AllowDayOverflow.no); 5051 assert(date == Date(0, 12, 1)); 5052 date.add!"months"(1, AllowDayOverflow.no); 5053 assert(date == Date(1, 1, 1)); 5054 } 5055 5056 { 5057 auto date = Date(4, 1, 1); 5058 date.add!"months"(-48, AllowDayOverflow.no); 5059 assert(date == Date(0, 1, 1)); 5060 date.add!"months"(48, AllowDayOverflow.no); 5061 assert(date == Date(4, 1, 1)); 5062 } 5063 5064 { 5065 auto date = Date(4, 3, 31); 5066 date.add!"months"(-49, AllowDayOverflow.no); 5067 assert(date == Date(0, 2, 29)); 5068 date.add!"months"(49, AllowDayOverflow.no); 5069 assert(date == Date(4, 3, 29)); 5070 } 5071 5072 { 5073 auto date = Date(4, 3, 31); 5074 date.add!"months"(-85, AllowDayOverflow.no); 5075 assert(date == Date(-3, 2, 28)); 5076 date.add!"months"(85, AllowDayOverflow.no); 5077 assert(date == Date(4, 3, 28)); 5078 } 5079 5080 { 5081 auto date = Date(-3, 3, 31); 5082 date.add!"months"(85, AllowDayOverflow.no).add!"months"(-83, AllowDayOverflow.no); 5083 assert(date == Date(-3, 5, 30)); 5084 } 5085 } 5086 5087 5088 /++ 5089 Adds the given number of years or months to this $(LREF Date). A negative 5090 number will subtract. 5091 5092 The difference between rolling and adding is that rolling does not 5093 affect larger units. Rolling a $(LREF Date) 12 months gets 5094 the exact same $(LREF Date). However, the days can still be affected due 5095 to the differing number of days in each month. 5096 5097 Because there are no units larger than years, there is no difference 5098 between adding and rolling years. 5099 5100 Params: 5101 units = The type of units to add ("years" or "months"). 5102 value = The number of months or years to add to this 5103 $(LREF Date). 5104 allowOverflow = Whether the day should be allowed to overflow, 5105 causing the month to increment. 5106 +/ 5107 @safe pure nothrow @nogc 5108 ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5109 if (units == "years") 5110 { 5111 return add!"years"(value, allowOverflow); 5112 } 5113 5114 /// 5115 @safe unittest 5116 { 5117 auto d1 = Date(2010, 1, 1); 5118 d1.roll!"months"(1); 5119 assert(d1 == Date(2010, 2, 1)); 5120 5121 auto d2 = Date(2010, 1, 1); 5122 d2.roll!"months"(-1); 5123 assert(d2 == Date(2010, 12, 1)); 5124 5125 auto d3 = Date(1999, 1, 29); 5126 d3.roll!"months"(1); 5127 assert(d3 == Date(1999, 3, 1)); 5128 5129 auto d4 = Date(1999, 1, 29); 5130 d4.roll!"months"(1, AllowDayOverflow.no); 5131 assert(d4 == Date(1999, 2, 28)); 5132 5133 auto d5 = Date(2000, 2, 29); 5134 d5.roll!"years"(1); 5135 assert(d5 == Date(2001, 3, 1)); 5136 5137 auto d6 = Date(2000, 2, 29); 5138 d6.roll!"years"(1, AllowDayOverflow.no); 5139 assert(d6 == Date(2001, 2, 28)); 5140 } 5141 5142 @safe unittest 5143 { 5144 const cdate = Date(1999, 7, 6); 5145 immutable idate = Date(1999, 7, 6); 5146 static assert(!__traits(compiles, cdate.roll!"years"(3))); 5147 static assert(!__traits(compiles, idate.rolYears(3))); 5148 } 5149 5150 5151 // Shares documentation with "years" version. 5152 @safe pure nothrow @nogc 5153 ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) 5154 if (units == "months") 5155 { 5156 months %= 12; 5157 auto newMonth = _month + months; 5158 5159 if (months < 0) 5160 { 5161 if (newMonth < 1) 5162 newMonth += 12; 5163 } 5164 else 5165 { 5166 if (newMonth > 12) 5167 newMonth -= 12; 5168 } 5169 5170 _month = cast(Month) newMonth; 5171 5172 immutable currMaxDay = maxDay(_year, _month); 5173 immutable overflow = _day - currMaxDay; 5174 5175 if (overflow > 0) 5176 { 5177 if (allowOverflow == AllowDayOverflow.yes) 5178 { 5179 ++_month; 5180 _day = cast(ubyte) overflow; 5181 } 5182 else 5183 _day = cast(ubyte) currMaxDay; 5184 } 5185 5186 return this; 5187 } 5188 5189 // Test roll!"months"() with AllowDayOverflow.yes 5190 @safe unittest 5191 { 5192 // Test A.D. 5193 { 5194 auto date = Date(1999, 7, 6); 5195 date.roll!"months"(3); 5196 assert(date == Date(1999, 10, 6)); 5197 date.roll!"months"(-4); 5198 assert(date == Date(1999, 6, 6)); 5199 } 5200 5201 { 5202 auto date = Date(1999, 7, 6); 5203 date.roll!"months"(6); 5204 assert(date == Date(1999, 1, 6)); 5205 date.roll!"months"(-6); 5206 assert(date == Date(1999, 7, 6)); 5207 } 5208 5209 { 5210 auto date = Date(1999, 7, 6); 5211 date.roll!"months"(27); 5212 assert(date == Date(1999, 10, 6)); 5213 date.roll!"months"(-28); 5214 assert(date == Date(1999, 6, 6)); 5215 } 5216 5217 { 5218 auto date = Date(1999, 5, 31); 5219 date.roll!"months"(1); 5220 assert(date == Date(1999, 7, 1)); 5221 } 5222 5223 { 5224 auto date = Date(1999, 5, 31); 5225 date.roll!"months"(-1); 5226 assert(date == Date(1999, 5, 1)); 5227 } 5228 5229 { 5230 auto date = Date(1999, 2, 28); 5231 date.roll!"months"(12); 5232 assert(date == Date(1999, 2, 28)); 5233 } 5234 5235 { 5236 auto date = Date(2000, 2, 29); 5237 date.roll!"months"(12); 5238 assert(date == Date(2000, 2, 29)); 5239 } 5240 5241 { 5242 auto date = Date(1999, 7, 31); 5243 date.roll!"months"(1); 5244 assert(date == Date(1999, 8, 31)); 5245 date.roll!"months"(1); 5246 assert(date == Date(1999, 10, 1)); 5247 } 5248 5249 { 5250 auto date = Date(1998, 8, 31); 5251 date.roll!"months"(13); 5252 assert(date == Date(1998, 10, 1)); 5253 date.roll!"months"(-13); 5254 assert(date == Date(1998, 9, 1)); 5255 } 5256 5257 { 5258 auto date = Date(1997, 12, 31); 5259 date.roll!"months"(13); 5260 assert(date == Date(1997, 1, 31)); 5261 date.roll!"months"(-13); 5262 assert(date == Date(1997, 12, 31)); 5263 } 5264 5265 { 5266 auto date = Date(1997, 12, 31); 5267 date.roll!"months"(14); 5268 assert(date == Date(1997, 3, 3)); 5269 date.roll!"months"(-14); 5270 assert(date == Date(1997, 1, 3)); 5271 } 5272 5273 { 5274 auto date = Date(1998, 12, 31); 5275 date.roll!"months"(14); 5276 assert(date == Date(1998, 3, 3)); 5277 date.roll!"months"(-14); 5278 assert(date == Date(1998, 1, 3)); 5279 } 5280 5281 { 5282 auto date = Date(1999, 12, 31); 5283 date.roll!"months"(14); 5284 assert(date == Date(1999, 3, 3)); 5285 date.roll!"months"(-14); 5286 assert(date == Date(1999, 1, 3)); 5287 } 5288 5289 // Test B.C. 5290 { 5291 auto date = Date(-1999, 7, 6); 5292 date.roll!"months"(3); 5293 assert(date == Date(-1999, 10, 6)); 5294 date.roll!"months"(-4); 5295 assert(date == Date(-1999, 6, 6)); 5296 } 5297 5298 { 5299 auto date = Date(-1999, 7, 6); 5300 date.roll!"months"(6); 5301 assert(date == Date(-1999, 1, 6)); 5302 date.roll!"months"(-6); 5303 assert(date == Date(-1999, 7, 6)); 5304 } 5305 5306 { 5307 auto date = Date(-1999, 7, 6); 5308 date.roll!"months"(-27); 5309 assert(date == Date(-1999, 4, 6)); 5310 date.roll!"months"(28); 5311 assert(date == Date(-1999, 8, 6)); 5312 } 5313 5314 { 5315 auto date = Date(-1999, 5, 31); 5316 date.roll!"months"(1); 5317 assert(date == Date(-1999, 7, 1)); 5318 } 5319 5320 { 5321 auto date = Date(-1999, 5, 31); 5322 date.roll!"months"(-1); 5323 assert(date == Date(-1999, 5, 1)); 5324 } 5325 5326 { 5327 auto date = Date(-1999, 2, 28); 5328 date.roll!"months"(-12); 5329 assert(date == Date(-1999, 2, 28)); 5330 } 5331 5332 { 5333 auto date = Date(-2000, 2, 29); 5334 date.roll!"months"(-12); 5335 assert(date == Date(-2000, 2, 29)); 5336 } 5337 5338 { 5339 auto date = Date(-1999, 7, 31); 5340 date.roll!"months"(1); 5341 assert(date == Date(-1999, 8, 31)); 5342 date.roll!"months"(1); 5343 assert(date == Date(-1999, 10, 1)); 5344 } 5345 5346 { 5347 auto date = Date(-1998, 8, 31); 5348 date.roll!"months"(13); 5349 assert(date == Date(-1998, 10, 1)); 5350 date.roll!"months"(-13); 5351 assert(date == Date(-1998, 9, 1)); 5352 } 5353 5354 { 5355 auto date = Date(-1997, 12, 31); 5356 date.roll!"months"(13); 5357 assert(date == Date(-1997, 1, 31)); 5358 date.roll!"months"(-13); 5359 assert(date == Date(-1997, 12, 31)); 5360 } 5361 5362 { 5363 auto date = Date(-1997, 12, 31); 5364 date.roll!"months"(14); 5365 assert(date == Date(-1997, 3, 3)); 5366 date.roll!"months"(-14); 5367 assert(date == Date(-1997, 1, 3)); 5368 } 5369 5370 { 5371 auto date = Date(-2002, 12, 31); 5372 date.roll!"months"(14); 5373 assert(date == Date(-2002, 3, 3)); 5374 date.roll!"months"(-14); 5375 assert(date == Date(-2002, 1, 3)); 5376 } 5377 5378 { 5379 auto date = Date(-2001, 12, 31); 5380 date.roll!"months"(14); 5381 assert(date == Date(-2001, 3, 3)); 5382 date.roll!"months"(-14); 5383 assert(date == Date(-2001, 1, 3)); 5384 } 5385 5386 // Test Both 5387 { 5388 auto date = Date(1, 1, 1); 5389 date.roll!"months"(-1); 5390 assert(date == Date(1, 12, 1)); 5391 date.roll!"months"(1); 5392 assert(date == Date(1, 1, 1)); 5393 } 5394 5395 { 5396 auto date = Date(4, 1, 1); 5397 date.roll!"months"(-48); 5398 assert(date == Date(4, 1, 1)); 5399 date.roll!"months"(48); 5400 assert(date == Date(4, 1, 1)); 5401 } 5402 5403 { 5404 auto date = Date(4, 3, 31); 5405 date.roll!"months"(-49); 5406 assert(date == Date(4, 3, 2)); 5407 date.roll!"months"(49); 5408 assert(date == Date(4, 4, 2)); 5409 } 5410 5411 { 5412 auto date = Date(4, 3, 31); 5413 date.roll!"months"(-85); 5414 assert(date == Date(4, 3, 2)); 5415 date.roll!"months"(85); 5416 assert(date == Date(4, 4, 2)); 5417 } 5418 5419 { 5420 auto date = Date(-1, 1, 1); 5421 date.roll!"months"(-1); 5422 assert(date == Date(-1, 12, 1)); 5423 date.roll!"months"(1); 5424 assert(date == Date(-1, 1, 1)); 5425 } 5426 5427 { 5428 auto date = Date(-4, 1, 1); 5429 date.roll!"months"(-48); 5430 assert(date == Date(-4, 1, 1)); 5431 date.roll!"months"(48); 5432 assert(date == Date(-4, 1, 1)); 5433 } 5434 5435 { 5436 auto date = Date(-4, 3, 31); 5437 date.roll!"months"(-49); 5438 assert(date == Date(-4, 3, 2)); 5439 date.roll!"months"(49); 5440 assert(date == Date(-4, 4, 2)); 5441 } 5442 5443 { 5444 auto date = Date(-4, 3, 31); 5445 date.roll!"months"(-85); 5446 assert(date == Date(-4, 3, 2)); 5447 date.roll!"months"(85); 5448 assert(date == Date(-4, 4, 2)); 5449 } 5450 5451 { 5452 auto date = Date(-3, 3, 31); 5453 date.roll!"months"(85).roll!"months"(-83); 5454 assert(date == Date(-3, 6, 1)); 5455 } 5456 5457 const cdate = Date(1999, 7, 6); 5458 immutable idate = Date(1999, 7, 6); 5459 static assert(!__traits(compiles, cdate.roll!"months"(3))); 5460 static assert(!__traits(compiles, idate.roll!"months"(3))); 5461 } 5462 5463 // Test roll!"months"() with AllowDayOverflow.no 5464 @safe unittest 5465 { 5466 // Test A.D. 5467 { 5468 auto date = Date(1999, 7, 6); 5469 date.roll!"months"(3, AllowDayOverflow.no); 5470 assert(date == Date(1999, 10, 6)); 5471 date.roll!"months"(-4, AllowDayOverflow.no); 5472 assert(date == Date(1999, 6, 6)); 5473 } 5474 5475 { 5476 auto date = Date(1999, 7, 6); 5477 date.roll!"months"(6, AllowDayOverflow.no); 5478 assert(date == Date(1999, 1, 6)); 5479 date.roll!"months"(-6, AllowDayOverflow.no); 5480 assert(date == Date(1999, 7, 6)); 5481 } 5482 5483 { 5484 auto date = Date(1999, 7, 6); 5485 date.roll!"months"(27, AllowDayOverflow.no); 5486 assert(date == Date(1999, 10, 6)); 5487 date.roll!"months"(-28, AllowDayOverflow.no); 5488 assert(date == Date(1999, 6, 6)); 5489 } 5490 5491 { 5492 auto date = Date(1999, 5, 31); 5493 date.roll!"months"(1, AllowDayOverflow.no); 5494 assert(date == Date(1999, 6, 30)); 5495 } 5496 5497 { 5498 auto date = Date(1999, 5, 31); 5499 date.roll!"months"(-1, AllowDayOverflow.no); 5500 assert(date == Date(1999, 4, 30)); 5501 } 5502 5503 { 5504 auto date = Date(1999, 2, 28); 5505 date.roll!"months"(12, AllowDayOverflow.no); 5506 assert(date == Date(1999, 2, 28)); 5507 } 5508 5509 { 5510 auto date = Date(2000, 2, 29); 5511 date.roll!"months"(12, AllowDayOverflow.no); 5512 assert(date == Date(2000, 2, 29)); 5513 } 5514 5515 { 5516 auto date = Date(1999, 7, 31); 5517 date.roll!"months"(1, AllowDayOverflow.no); 5518 assert(date == Date(1999, 8, 31)); 5519 date.roll!"months"(1, AllowDayOverflow.no); 5520 assert(date == Date(1999, 9, 30)); 5521 } 5522 5523 { 5524 auto date = Date(1998, 8, 31); 5525 date.roll!"months"(13, AllowDayOverflow.no); 5526 assert(date == Date(1998, 9, 30)); 5527 date.roll!"months"(-13, AllowDayOverflow.no); 5528 assert(date == Date(1998, 8, 30)); 5529 } 5530 5531 { 5532 auto date = Date(1997, 12, 31); 5533 date.roll!"months"(13, AllowDayOverflow.no); 5534 assert(date == Date(1997, 1, 31)); 5535 date.roll!"months"(-13, AllowDayOverflow.no); 5536 assert(date == Date(1997, 12, 31)); 5537 } 5538 5539 { 5540 auto date = Date(1997, 12, 31); 5541 date.roll!"months"(14, AllowDayOverflow.no); 5542 assert(date == Date(1997, 2, 28)); 5543 date.roll!"months"(-14, AllowDayOverflow.no); 5544 assert(date == Date(1997, 12, 28)); 5545 } 5546 5547 { 5548 auto date = Date(1998, 12, 31); 5549 date.roll!"months"(14, AllowDayOverflow.no); 5550 assert(date == Date(1998, 2, 28)); 5551 date.roll!"months"(-14, AllowDayOverflow.no); 5552 assert(date == Date(1998, 12, 28)); 5553 } 5554 5555 { 5556 auto date = Date(1999, 12, 31); 5557 date.roll!"months"(14, AllowDayOverflow.no); 5558 assert(date == Date(1999, 2, 28)); 5559 date.roll!"months"(-14, AllowDayOverflow.no); 5560 assert(date == Date(1999, 12, 28)); 5561 } 5562 5563 // Test B.C. 5564 { 5565 auto date = Date(-1999, 7, 6); 5566 date.roll!"months"(3, AllowDayOverflow.no); 5567 assert(date == Date(-1999, 10, 6)); 5568 date.roll!"months"(-4, AllowDayOverflow.no); 5569 assert(date == Date(-1999, 6, 6)); 5570 } 5571 5572 { 5573 auto date = Date(-1999, 7, 6); 5574 date.roll!"months"(6, AllowDayOverflow.no); 5575 assert(date == Date(-1999, 1, 6)); 5576 date.roll!"months"(-6, AllowDayOverflow.no); 5577 assert(date == Date(-1999, 7, 6)); 5578 } 5579 5580 { 5581 auto date = Date(-1999, 7, 6); 5582 date.roll!"months"(-27, AllowDayOverflow.no); 5583 assert(date == Date(-1999, 4, 6)); 5584 date.roll!"months"(28, AllowDayOverflow.no); 5585 assert(date == Date(-1999, 8, 6)); 5586 } 5587 5588 { 5589 auto date = Date(-1999, 5, 31); 5590 date.roll!"months"(1, AllowDayOverflow.no); 5591 assert(date == Date(-1999, 6, 30)); 5592 } 5593 5594 { 5595 auto date = Date(-1999, 5, 31); 5596 date.roll!"months"(-1, AllowDayOverflow.no); 5597 assert(date == Date(-1999, 4, 30)); 5598 } 5599 5600 { 5601 auto date = Date(-1999, 2, 28); 5602 date.roll!"months"(-12, AllowDayOverflow.no); 5603 assert(date == Date(-1999, 2, 28)); 5604 } 5605 5606 { 5607 auto date = Date(-2000, 2, 29); 5608 date.roll!"months"(-12, AllowDayOverflow.no); 5609 assert(date == Date(-2000, 2, 29)); 5610 } 5611 5612 { 5613 auto date = Date(-1999, 7, 31); 5614 date.roll!"months"(1, AllowDayOverflow.no); 5615 assert(date == Date(-1999, 8, 31)); 5616 date.roll!"months"(1, AllowDayOverflow.no); 5617 assert(date == Date(-1999, 9, 30)); 5618 } 5619 5620 { 5621 auto date = Date(-1998, 8, 31); 5622 date.roll!"months"(13, AllowDayOverflow.no); 5623 assert(date == Date(-1998, 9, 30)); 5624 date.roll!"months"(-13, AllowDayOverflow.no); 5625 assert(date == Date(-1998, 8, 30)); 5626 } 5627 5628 { 5629 auto date = Date(-1997, 12, 31); 5630 date.roll!"months"(13, AllowDayOverflow.no); 5631 assert(date == Date(-1997, 1, 31)); 5632 date.roll!"months"(-13, AllowDayOverflow.no); 5633 assert(date == Date(-1997, 12, 31)); 5634 } 5635 5636 { 5637 auto date = Date(-1997, 12, 31); 5638 date.roll!"months"(14, AllowDayOverflow.no); 5639 assert(date == Date(-1997, 2, 28)); 5640 date.roll!"months"(-14, AllowDayOverflow.no); 5641 assert(date == Date(-1997, 12, 28)); 5642 } 5643 5644 { 5645 auto date = Date(-2002, 12, 31); 5646 date.roll!"months"(14, AllowDayOverflow.no); 5647 assert(date == Date(-2002, 2, 28)); 5648 date.roll!"months"(-14, AllowDayOverflow.no); 5649 assert(date == Date(-2002, 12, 28)); 5650 } 5651 5652 { 5653 auto date = Date(-2001, 12, 31); 5654 date.roll!"months"(14, AllowDayOverflow.no); 5655 assert(date == Date(-2001, 2, 28)); 5656 date.roll!"months"(-14, AllowDayOverflow.no); 5657 assert(date == Date(-2001, 12, 28)); 5658 } 5659 5660 // Test Both 5661 { 5662 auto date = Date(1, 1, 1); 5663 date.roll!"months"(-1, AllowDayOverflow.no); 5664 assert(date == Date(1, 12, 1)); 5665 date.roll!"months"(1, AllowDayOverflow.no); 5666 assert(date == Date(1, 1, 1)); 5667 } 5668 5669 { 5670 auto date = Date(4, 1, 1); 5671 date.roll!"months"(-48, AllowDayOverflow.no); 5672 assert(date == Date(4, 1, 1)); 5673 date.roll!"months"(48, AllowDayOverflow.no); 5674 assert(date == Date(4, 1, 1)); 5675 } 5676 5677 { 5678 auto date = Date(4, 3, 31); 5679 date.roll!"months"(-49, AllowDayOverflow.no); 5680 assert(date == Date(4, 2, 29)); 5681 date.roll!"months"(49, AllowDayOverflow.no); 5682 assert(date == Date(4, 3, 29)); 5683 } 5684 5685 { 5686 auto date = Date(4, 3, 31); 5687 date.roll!"months"(-85, AllowDayOverflow.no); 5688 assert(date == Date(4, 2, 29)); 5689 date.roll!"months"(85, AllowDayOverflow.no); 5690 assert(date == Date(4, 3, 29)); 5691 } 5692 5693 { 5694 auto date = Date(-1, 1, 1); 5695 date.roll!"months"(-1, AllowDayOverflow.no); 5696 assert(date == Date(-1, 12, 1)); 5697 date.roll!"months"(1, AllowDayOverflow.no); 5698 assert(date == Date(-1, 1, 1)); 5699 } 5700 5701 { 5702 auto date = Date(-4, 1, 1); 5703 date.roll!"months"(-48, AllowDayOverflow.no); 5704 assert(date == Date(-4, 1, 1)); 5705 date.roll!"months"(48, AllowDayOverflow.no); 5706 assert(date == Date(-4, 1, 1)); 5707 } 5708 5709 { 5710 auto date = Date(-4, 3, 31); 5711 date.roll!"months"(-49, AllowDayOverflow.no); 5712 assert(date == Date(-4, 2, 29)); 5713 date.roll!"months"(49, AllowDayOverflow.no); 5714 assert(date == Date(-4, 3, 29)); 5715 } 5716 5717 { 5718 auto date = Date(-4, 3, 31); 5719 date.roll!"months"(-85, AllowDayOverflow.no); 5720 assert(date == Date(-4, 2, 29)); 5721 date.roll!"months"(85, AllowDayOverflow.no); 5722 assert(date == Date(-4, 3, 29)); 5723 } 5724 5725 { 5726 auto date = Date(-3, 3, 31); 5727 date.roll!"months"(85, AllowDayOverflow.no).roll!"months"(-83, AllowDayOverflow.no); 5728 assert(date == Date(-3, 5, 30)); 5729 } 5730 } 5731 5732 5733 /++ 5734 Adds the given number of units to this $(LREF Date). A negative number 5735 will subtract. 5736 5737 The difference between rolling and adding is that rolling does not 5738 affect larger units. For instance, rolling a $(LREF Date) one 5739 year's worth of days gets the exact same $(LREF Date). 5740 5741 The only accepted units are $(D "days"). 5742 5743 Params: 5744 units = The units to add. Must be $(D "days"). 5745 days = The number of days to add to this $(LREF Date). 5746 +/ 5747 ref Date roll(string units)(long days) @safe pure nothrow @nogc 5748 if (units == "days") 5749 { 5750 immutable limit = maxDay(_year, _month); 5751 days %= limit; 5752 auto newDay = _day + days; 5753 5754 if (days < 0) 5755 { 5756 if (newDay < 1) 5757 newDay += limit; 5758 } 5759 else if (newDay > limit) 5760 newDay -= limit; 5761 5762 _day = cast(ubyte) newDay; 5763 return this; 5764 } 5765 5766 /// 5767 @safe unittest 5768 { 5769 auto d = Date(2010, 1, 1); 5770 d.roll!"days"(1); 5771 assert(d == Date(2010, 1, 2)); 5772 d.roll!"days"(365); 5773 assert(d == Date(2010, 1, 26)); 5774 d.roll!"days"(-32); 5775 assert(d == Date(2010, 1, 25)); 5776 } 5777 5778 @safe unittest 5779 { 5780 // Test A.D. 5781 { 5782 auto date = Date(1999, 2, 28); 5783 date.roll!"days"(1); 5784 assert(date == Date(1999, 2, 1)); 5785 date.roll!"days"(-1); 5786 assert(date == Date(1999, 2, 28)); 5787 } 5788 5789 { 5790 auto date = Date(2000, 2, 28); 5791 date.roll!"days"(1); 5792 assert(date == Date(2000, 2, 29)); 5793 date.roll!"days"(1); 5794 assert(date == Date(2000, 2, 1)); 5795 date.roll!"days"(-1); 5796 assert(date == Date(2000, 2, 29)); 5797 } 5798 5799 { 5800 auto date = Date(1999, 6, 30); 5801 date.roll!"days"(1); 5802 assert(date == Date(1999, 6, 1)); 5803 date.roll!"days"(-1); 5804 assert(date == Date(1999, 6, 30)); 5805 } 5806 5807 { 5808 auto date = Date(1999, 7, 31); 5809 date.roll!"days"(1); 5810 assert(date == Date(1999, 7, 1)); 5811 date.roll!"days"(-1); 5812 assert(date == Date(1999, 7, 31)); 5813 } 5814 5815 { 5816 auto date = Date(1999, 1, 1); 5817 date.roll!"days"(-1); 5818 assert(date == Date(1999, 1, 31)); 5819 date.roll!"days"(1); 5820 assert(date == Date(1999, 1, 1)); 5821 } 5822 5823 { 5824 auto date = Date(1999, 7, 6); 5825 date.roll!"days"(9); 5826 assert(date == Date(1999, 7, 15)); 5827 date.roll!"days"(-11); 5828 assert(date == Date(1999, 7, 4)); 5829 date.roll!"days"(30); 5830 assert(date == Date(1999, 7, 3)); 5831 date.roll!"days"(-3); 5832 assert(date == Date(1999, 7, 31)); 5833 } 5834 5835 { 5836 auto date = Date(1999, 7, 6); 5837 date.roll!"days"(365); 5838 assert(date == Date(1999, 7, 30)); 5839 date.roll!"days"(-365); 5840 assert(date == Date(1999, 7, 6)); 5841 date.roll!"days"(366); 5842 assert(date == Date(1999, 7, 31)); 5843 date.roll!"days"(730); 5844 assert(date == Date(1999, 7, 17)); 5845 date.roll!"days"(-1096); 5846 assert(date == Date(1999, 7, 6)); 5847 } 5848 5849 { 5850 auto date = Date(1999, 2, 6); 5851 date.roll!"days"(365); 5852 assert(date == Date(1999, 2, 7)); 5853 date.roll!"days"(-365); 5854 assert(date == Date(1999, 2, 6)); 5855 date.roll!"days"(366); 5856 assert(date == Date(1999, 2, 8)); 5857 date.roll!"days"(730); 5858 assert(date == Date(1999, 2, 10)); 5859 date.roll!"days"(-1096); 5860 assert(date == Date(1999, 2, 6)); 5861 } 5862 5863 // Test B.C. 5864 { 5865 auto date = Date(-1999, 2, 28); 5866 date.roll!"days"(1); 5867 assert(date == Date(-1999, 2, 1)); 5868 date.roll!"days"(-1); 5869 assert(date == Date(-1999, 2, 28)); 5870 } 5871 5872 { 5873 auto date = Date(-2000, 2, 28); 5874 date.roll!"days"(1); 5875 assert(date == Date(-2000, 2, 29)); 5876 date.roll!"days"(1); 5877 assert(date == Date(-2000, 2, 1)); 5878 date.roll!"days"(-1); 5879 assert(date == Date(-2000, 2, 29)); 5880 } 5881 5882 { 5883 auto date = Date(-1999, 6, 30); 5884 date.roll!"days"(1); 5885 assert(date == Date(-1999, 6, 1)); 5886 date.roll!"days"(-1); 5887 assert(date == Date(-1999, 6, 30)); 5888 } 5889 5890 { 5891 auto date = Date(-1999, 7, 31); 5892 date.roll!"days"(1); 5893 assert(date == Date(-1999, 7, 1)); 5894 date.roll!"days"(-1); 5895 assert(date == Date(-1999, 7, 31)); 5896 } 5897 5898 { 5899 auto date = Date(-1999, 1, 1); 5900 date.roll!"days"(-1); 5901 assert(date == Date(-1999, 1, 31)); 5902 date.roll!"days"(1); 5903 assert(date == Date(-1999, 1, 1)); 5904 } 5905 5906 { 5907 auto date = Date(-1999, 7, 6); 5908 date.roll!"days"(9); 5909 assert(date == Date(-1999, 7, 15)); 5910 date.roll!"days"(-11); 5911 assert(date == Date(-1999, 7, 4)); 5912 date.roll!"days"(30); 5913 assert(date == Date(-1999, 7, 3)); 5914 date.roll!"days"(-3); 5915 assert(date == Date(-1999, 7, 31)); 5916 } 5917 5918 { 5919 auto date = Date(-1999, 7, 6); 5920 date.roll!"days"(365); 5921 assert(date == Date(-1999, 7, 30)); 5922 date.roll!"days"(-365); 5923 assert(date == Date(-1999, 7, 6)); 5924 date.roll!"days"(366); 5925 assert(date == Date(-1999, 7, 31)); 5926 date.roll!"days"(730); 5927 assert(date == Date(-1999, 7, 17)); 5928 date.roll!"days"(-1096); 5929 assert(date == Date(-1999, 7, 6)); 5930 } 5931 5932 // Test Both 5933 { 5934 auto date = Date(1, 7, 6); 5935 date.roll!"days"(-365); 5936 assert(date == Date(1, 7, 13)); 5937 date.roll!"days"(365); 5938 assert(date == Date(1, 7, 6)); 5939 date.roll!"days"(-731); 5940 assert(date == Date(1, 7, 19)); 5941 date.roll!"days"(730); 5942 assert(date == Date(1, 7, 5)); 5943 } 5944 5945 { 5946 auto date = Date(0, 7, 6); 5947 date.roll!"days"(-365); 5948 assert(date == Date(0, 7, 13)); 5949 date.roll!"days"(365); 5950 assert(date == Date(0, 7, 6)); 5951 date.roll!"days"(-731); 5952 assert(date == Date(0, 7, 19)); 5953 date.roll!"days"(730); 5954 assert(date == Date(0, 7, 5)); 5955 } 5956 5957 { 5958 auto date = Date(0, 7, 6); 5959 date.roll!"days"(-365).roll!"days"(362).roll!"days"(-12).roll!"days"(730); 5960 assert(date == Date(0, 7, 8)); 5961 } 5962 5963 const cdate = Date(1999, 7, 6); 5964 immutable idate = Date(1999, 7, 6); 5965 static assert(!__traits(compiles, cdate.roll!"days"(12))); 5966 static assert(!__traits(compiles, idate.roll!"days"(12))); 5967 } 5968 5969 5970 /++ 5971 Gives the result of adding or subtracting a $(REF Duration, core,time) 5972 from 5973 5974 The legal types of arithmetic for $(LREF Date) using this operator are 5975 5976 $(BOOKTABLE, 5977 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 5978 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 5979 ) 5980 5981 Params: 5982 duration = The $(REF Duration, core,time) to add to or subtract from 5983 this $(LREF Date). 5984 +/ 5985 Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 5986 if (op == "+" || op == "-") 5987 { 5988 Date retval = this; 5989 immutable days = duration.total!"days"; 5990 mixin("return retval._addDays(" ~ op ~ "days);"); 5991 } 5992 5993 /// 5994 @safe unittest 5995 { 5996 import core.time : days; 5997 5998 assert(Date(2015, 12, 31) + days(1) == Date(2016, 1, 1)); 5999 assert(Date(2004, 2, 26) + days(4) == Date(2004, 3, 1)); 6000 6001 assert(Date(2016, 1, 1) - days(1) == Date(2015, 12, 31)); 6002 assert(Date(2004, 3, 1) - days(4) == Date(2004, 2, 26)); 6003 } 6004 6005 @safe unittest 6006 { 6007 auto date = Date(1999, 7, 6); 6008 6009 assert(date + dur!"weeks"(7) == Date(1999, 8, 24)); 6010 assert(date + dur!"weeks"(-7) == Date(1999, 5, 18)); 6011 assert(date + dur!"days"(7) == Date(1999, 7, 13)); 6012 assert(date + dur!"days"(-7) == Date(1999, 6, 29)); 6013 6014 assert(date + dur!"hours"(24) == Date(1999, 7, 7)); 6015 assert(date + dur!"hours"(-24) == Date(1999, 7, 5)); 6016 assert(date + dur!"minutes"(1440) == Date(1999, 7, 7)); 6017 assert(date + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6018 assert(date + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6019 assert(date + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6020 assert(date + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6021 assert(date + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6022 assert(date + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6023 assert(date + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6024 assert(date + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6025 assert(date + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6026 6027 assert(date - dur!"weeks"(-7) == Date(1999, 8, 24)); 6028 assert(date - dur!"weeks"(7) == Date(1999, 5, 18)); 6029 assert(date - dur!"days"(-7) == Date(1999, 7, 13)); 6030 assert(date - dur!"days"(7) == Date(1999, 6, 29)); 6031 6032 assert(date - dur!"hours"(-24) == Date(1999, 7, 7)); 6033 assert(date - dur!"hours"(24) == Date(1999, 7, 5)); 6034 assert(date - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6035 assert(date - dur!"minutes"(1440) == Date(1999, 7, 5)); 6036 assert(date - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6037 assert(date - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6038 assert(date - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6039 assert(date - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6040 assert(date - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6041 assert(date - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6042 assert(date - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6043 assert(date - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6044 6045 auto duration = dur!"days"(12); 6046 const cdate = Date(1999, 7, 6); 6047 immutable idate = Date(1999, 7, 6); 6048 assert(date + duration == Date(1999, 7, 18)); 6049 assert(cdate + duration == Date(1999, 7, 18)); 6050 assert(idate + duration == Date(1999, 7, 18)); 6051 6052 assert(date - duration == Date(1999, 6, 24)); 6053 assert(cdate - duration == Date(1999, 6, 24)); 6054 assert(idate - duration == Date(1999, 6, 24)); 6055 } 6056 6057 6058 /++ 6059 Gives the result of adding or subtracting a $(REF Duration, core,time) 6060 from this $(LREF Date), as well as assigning the result to this 6061 $(LREF Date). 6062 6063 The legal types of arithmetic for $(LREF Date) using this operator are 6064 6065 $(BOOKTABLE, 6066 $(TR $(TD Date) $(TD +) $(TD Duration) $(TD -->) $(TD Date)) 6067 $(TR $(TD Date) $(TD -) $(TD Duration) $(TD -->) $(TD Date)) 6068 ) 6069 6070 Params: 6071 duration = The $(REF Duration, core,time) to add to or subtract from 6072 this $(LREF Date). 6073 +/ 6074 ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 6075 if (op == "+" || op == "-") 6076 { 6077 immutable days = duration.total!"days"; 6078 mixin("return _addDays(" ~ op ~ "days);"); 6079 } 6080 6081 @safe unittest 6082 { 6083 assert(Date(1999, 7, 6) + dur!"weeks"(7) == Date(1999, 8, 24)); 6084 assert(Date(1999, 7, 6) + dur!"weeks"(-7) == Date(1999, 5, 18)); 6085 assert(Date(1999, 7, 6) + dur!"days"(7) == Date(1999, 7, 13)); 6086 assert(Date(1999, 7, 6) + dur!"days"(-7) == Date(1999, 6, 29)); 6087 6088 assert(Date(1999, 7, 6) + dur!"hours"(24) == Date(1999, 7, 7)); 6089 assert(Date(1999, 7, 6) + dur!"hours"(-24) == Date(1999, 7, 5)); 6090 assert(Date(1999, 7, 6) + dur!"minutes"(1440) == Date(1999, 7, 7)); 6091 assert(Date(1999, 7, 6) + dur!"minutes"(-1440) == Date(1999, 7, 5)); 6092 assert(Date(1999, 7, 6) + dur!"seconds"(86_400) == Date(1999, 7, 7)); 6093 assert(Date(1999, 7, 6) + dur!"seconds"(-86_400) == Date(1999, 7, 5)); 6094 assert(Date(1999, 7, 6) + dur!"msecs"(86_400_000) == Date(1999, 7, 7)); 6095 assert(Date(1999, 7, 6) + dur!"msecs"(-86_400_000) == Date(1999, 7, 5)); 6096 assert(Date(1999, 7, 6) + dur!"usecs"(86_400_000_000) == Date(1999, 7, 7)); 6097 assert(Date(1999, 7, 6) + dur!"usecs"(-86_400_000_000) == Date(1999, 7, 5)); 6098 assert(Date(1999, 7, 6) + dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 7)); 6099 assert(Date(1999, 7, 6) + dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 5)); 6100 6101 assert(Date(1999, 7, 6) - dur!"weeks"(-7) == Date(1999, 8, 24)); 6102 assert(Date(1999, 7, 6) - dur!"weeks"(7) == Date(1999, 5, 18)); 6103 assert(Date(1999, 7, 6) - dur!"days"(-7) == Date(1999, 7, 13)); 6104 assert(Date(1999, 7, 6) - dur!"days"(7) == Date(1999, 6, 29)); 6105 6106 assert(Date(1999, 7, 6) - dur!"hours"(-24) == Date(1999, 7, 7)); 6107 assert(Date(1999, 7, 6) - dur!"hours"(24) == Date(1999, 7, 5)); 6108 assert(Date(1999, 7, 6) - dur!"minutes"(-1440) == Date(1999, 7, 7)); 6109 assert(Date(1999, 7, 6) - dur!"minutes"(1440) == Date(1999, 7, 5)); 6110 assert(Date(1999, 7, 6) - dur!"seconds"(-86_400) == Date(1999, 7, 7)); 6111 assert(Date(1999, 7, 6) - dur!"seconds"(86_400) == Date(1999, 7, 5)); 6112 assert(Date(1999, 7, 6) - dur!"msecs"(-86_400_000) == Date(1999, 7, 7)); 6113 assert(Date(1999, 7, 6) - dur!"msecs"(86_400_000) == Date(1999, 7, 5)); 6114 assert(Date(1999, 7, 6) - dur!"usecs"(-86_400_000_000) == Date(1999, 7, 7)); 6115 assert(Date(1999, 7, 6) - dur!"usecs"(86_400_000_000) == Date(1999, 7, 5)); 6116 assert(Date(1999, 7, 6) - dur!"hnsecs"(-864_000_000_000) == Date(1999, 7, 7)); 6117 assert(Date(1999, 7, 6) - dur!"hnsecs"(864_000_000_000) == Date(1999, 7, 5)); 6118 6119 { 6120 auto date = Date(0, 1, 31); 6121 (date += dur!"days"(507)) += dur!"days"(-2); 6122 assert(date == Date(1, 6, 19)); 6123 } 6124 6125 auto duration = dur!"days"(12); 6126 auto date = Date(1999, 7, 6); 6127 const cdate = Date(1999, 7, 6); 6128 immutable idate = Date(1999, 7, 6); 6129 date += duration; 6130 static assert(!__traits(compiles, cdate += duration)); 6131 static assert(!__traits(compiles, idate += duration)); 6132 6133 date -= duration; 6134 static assert(!__traits(compiles, cdate -= duration)); 6135 static assert(!__traits(compiles, idate -= duration)); 6136 } 6137 6138 6139 /++ 6140 Gives the difference between two $(LREF Date)s. 6141 6142 The legal types of arithmetic for $(LREF Date) using this operator are 6143 6144 $(BOOKTABLE, 6145 $(TR $(TD Date) $(TD -) $(TD Date) $(TD -->) $(TD duration)) 6146 ) 6147 +/ 6148 Duration opBinary(string op)(in Date rhs) const @safe pure nothrow @nogc 6149 if (op == "-") 6150 { 6151 return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal); 6152 } 6153 6154 @safe unittest 6155 { 6156 auto date = Date(1999, 7, 6); 6157 6158 assert(Date(1999, 7, 6) - Date(1998, 7, 6) == dur!"days"(365)); 6159 assert(Date(1998, 7, 6) - Date(1999, 7, 6) == dur!"days"(-365)); 6160 assert(Date(1999, 6, 6) - Date(1999, 5, 6) == dur!"days"(31)); 6161 assert(Date(1999, 5, 6) - Date(1999, 6, 6) == dur!"days"(-31)); 6162 assert(Date(1999, 1, 1) - Date(1998, 12, 31) == dur!"days"(1)); 6163 assert(Date(1998, 12, 31) - Date(1999, 1, 1) == dur!"days"(-1)); 6164 6165 const cdate = Date(1999, 7, 6); 6166 immutable idate = Date(1999, 7, 6); 6167 assert(date - date == Duration.zero); 6168 assert(cdate - date == Duration.zero); 6169 assert(idate - date == Duration.zero); 6170 6171 assert(date - cdate == Duration.zero); 6172 assert(cdate - cdate == Duration.zero); 6173 assert(idate - cdate == Duration.zero); 6174 6175 assert(date - idate == Duration.zero); 6176 assert(cdate - idate == Duration.zero); 6177 assert(idate - idate == Duration.zero); 6178 } 6179 6180 6181 /++ 6182 Returns the difference between the two $(LREF Date)s in months. 6183 6184 To get the difference in years, subtract the year property 6185 of two $(LREF Date)s. To get the difference in days or weeks, 6186 subtract the $(LREF Date)s themselves and use the 6187 $(REF Duration, core,time) that results. Because converting between 6188 months and smaller units requires a specific date (which 6189 $(REF Duration, core,time)s don't have), getting the difference in 6190 months requires some math using both the year and month properties, so 6191 this is a convenience function for getting the difference in months. 6192 6193 Note that the number of days in the months or how far into the month 6194 either $(LREF Date) is is irrelevant. It is the difference in the month 6195 property combined with the difference in years * 12. So, for instance, 6196 December 31st and January 1st are one month apart just as December 1st 6197 and January 31st are one month apart. 6198 6199 Params: 6200 rhs = The $(LREF Date) to subtract from this one. 6201 +/ 6202 int diffMonths(in Date rhs) const @safe pure nothrow @nogc 6203 { 6204 immutable yearDiff = _year - rhs._year; 6205 immutable monthDiff = _month - rhs._month; 6206 6207 return yearDiff * 12 + monthDiff; 6208 } 6209 6210 /// 6211 @safe unittest 6212 { 6213 assert(Date(1999, 2, 1).diffMonths(Date(1999, 1, 31)) == 1); 6214 assert(Date(1999, 1, 31).diffMonths(Date(1999, 2, 1)) == -1); 6215 assert(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1)) == 2); 6216 assert(Date(1999, 1, 1).diffMonths(Date(1999, 3, 31)) == -2); 6217 } 6218 6219 @safe unittest 6220 { 6221 auto date = Date(1999, 7, 6); 6222 6223 // Test A.D. 6224 assert(date.diffMonths(Date(1998, 6, 5)) == 13); 6225 assert(date.diffMonths(Date(1998, 7, 5)) == 12); 6226 assert(date.diffMonths(Date(1998, 8, 5)) == 11); 6227 assert(date.diffMonths(Date(1998, 9, 5)) == 10); 6228 assert(date.diffMonths(Date(1998, 10, 5)) == 9); 6229 assert(date.diffMonths(Date(1998, 11, 5)) == 8); 6230 assert(date.diffMonths(Date(1998, 12, 5)) == 7); 6231 assert(date.diffMonths(Date(1999, 1, 5)) == 6); 6232 assert(date.diffMonths(Date(1999, 2, 6)) == 5); 6233 assert(date.diffMonths(Date(1999, 3, 6)) == 4); 6234 assert(date.diffMonths(Date(1999, 4, 6)) == 3); 6235 assert(date.diffMonths(Date(1999, 5, 6)) == 2); 6236 assert(date.diffMonths(Date(1999, 6, 6)) == 1); 6237 assert(date.diffMonths(date) == 0); 6238 assert(date.diffMonths(Date(1999, 8, 6)) == -1); 6239 assert(date.diffMonths(Date(1999, 9, 6)) == -2); 6240 assert(date.diffMonths(Date(1999, 10, 6)) == -3); 6241 assert(date.diffMonths(Date(1999, 11, 6)) == -4); 6242 assert(date.diffMonths(Date(1999, 12, 6)) == -5); 6243 assert(date.diffMonths(Date(2000, 1, 6)) == -6); 6244 assert(date.diffMonths(Date(2000, 2, 6)) == -7); 6245 assert(date.diffMonths(Date(2000, 3, 6)) == -8); 6246 assert(date.diffMonths(Date(2000, 4, 6)) == -9); 6247 assert(date.diffMonths(Date(2000, 5, 6)) == -10); 6248 assert(date.diffMonths(Date(2000, 6, 6)) == -11); 6249 assert(date.diffMonths(Date(2000, 7, 6)) == -12); 6250 assert(date.diffMonths(Date(2000, 8, 6)) == -13); 6251 6252 assert(Date(1998, 6, 5).diffMonths(date) == -13); 6253 assert(Date(1998, 7, 5).diffMonths(date) == -12); 6254 assert(Date(1998, 8, 5).diffMonths(date) == -11); 6255 assert(Date(1998, 9, 5).diffMonths(date) == -10); 6256 assert(Date(1998, 10, 5).diffMonths(date) == -9); 6257 assert(Date(1998, 11, 5).diffMonths(date) == -8); 6258 assert(Date(1998, 12, 5).diffMonths(date) == -7); 6259 assert(Date(1999, 1, 5).diffMonths(date) == -6); 6260 assert(Date(1999, 2, 6).diffMonths(date) == -5); 6261 assert(Date(1999, 3, 6).diffMonths(date) == -4); 6262 assert(Date(1999, 4, 6).diffMonths(date) == -3); 6263 assert(Date(1999, 5, 6).diffMonths(date) == -2); 6264 assert(Date(1999, 6, 6).diffMonths(date) == -1); 6265 assert(Date(1999, 8, 6).diffMonths(date) == 1); 6266 assert(Date(1999, 9, 6).diffMonths(date) == 2); 6267 assert(Date(1999, 10, 6).diffMonths(date) == 3); 6268 assert(Date(1999, 11, 6).diffMonths(date) == 4); 6269 assert(Date(1999, 12, 6).diffMonths(date) == 5); 6270 assert(Date(2000, 1, 6).diffMonths(date) == 6); 6271 assert(Date(2000, 2, 6).diffMonths(date) == 7); 6272 assert(Date(2000, 3, 6).diffMonths(date) == 8); 6273 assert(Date(2000, 4, 6).diffMonths(date) == 9); 6274 assert(Date(2000, 5, 6).diffMonths(date) == 10); 6275 assert(Date(2000, 6, 6).diffMonths(date) == 11); 6276 assert(Date(2000, 7, 6).diffMonths(date) == 12); 6277 assert(Date(2000, 8, 6).diffMonths(date) == 13); 6278 6279 assert(date.diffMonths(Date(1999, 6, 30)) == 1); 6280 assert(date.diffMonths(Date(1999, 7, 1)) == 0); 6281 assert(date.diffMonths(Date(1999, 7, 6)) == 0); 6282 assert(date.diffMonths(Date(1999, 7, 11)) == 0); 6283 assert(date.diffMonths(Date(1999, 7, 16)) == 0); 6284 assert(date.diffMonths(Date(1999, 7, 21)) == 0); 6285 assert(date.diffMonths(Date(1999, 7, 26)) == 0); 6286 assert(date.diffMonths(Date(1999, 7, 31)) == 0); 6287 assert(date.diffMonths(Date(1999, 8, 1)) == -1); 6288 6289 assert(date.diffMonths(Date(1990, 6, 30)) == 109); 6290 assert(date.diffMonths(Date(1990, 7, 1)) == 108); 6291 assert(date.diffMonths(Date(1990, 7, 6)) == 108); 6292 assert(date.diffMonths(Date(1990, 7, 11)) == 108); 6293 assert(date.diffMonths(Date(1990, 7, 16)) == 108); 6294 assert(date.diffMonths(Date(1990, 7, 21)) == 108); 6295 assert(date.diffMonths(Date(1990, 7, 26)) == 108); 6296 assert(date.diffMonths(Date(1990, 7, 31)) == 108); 6297 assert(date.diffMonths(Date(1990, 8, 1)) == 107); 6298 6299 assert(Date(1999, 6, 30).diffMonths(date) == -1); 6300 assert(Date(1999, 7, 1).diffMonths(date) == 0); 6301 assert(Date(1999, 7, 6).diffMonths(date) == 0); 6302 assert(Date(1999, 7, 11).diffMonths(date) == 0); 6303 assert(Date(1999, 7, 16).diffMonths(date) == 0); 6304 assert(Date(1999, 7, 21).diffMonths(date) == 0); 6305 assert(Date(1999, 7, 26).diffMonths(date) == 0); 6306 assert(Date(1999, 7, 31).diffMonths(date) == 0); 6307 assert(Date(1999, 8, 1).diffMonths(date) == 1); 6308 6309 assert(Date(1990, 6, 30).diffMonths(date) == -109); 6310 assert(Date(1990, 7, 1).diffMonths(date) == -108); 6311 assert(Date(1990, 7, 6).diffMonths(date) == -108); 6312 assert(Date(1990, 7, 11).diffMonths(date) == -108); 6313 assert(Date(1990, 7, 16).diffMonths(date) == -108); 6314 assert(Date(1990, 7, 21).diffMonths(date) == -108); 6315 assert(Date(1990, 7, 26).diffMonths(date) == -108); 6316 assert(Date(1990, 7, 31).diffMonths(date) == -108); 6317 assert(Date(1990, 8, 1).diffMonths(date) == -107); 6318 6319 // Test B.C. 6320 auto dateBC = Date(-1999, 7, 6); 6321 6322 assert(dateBC.diffMonths(Date(-2000, 6, 5)) == 13); 6323 assert(dateBC.diffMonths(Date(-2000, 7, 5)) == 12); 6324 assert(dateBC.diffMonths(Date(-2000, 8, 5)) == 11); 6325 assert(dateBC.diffMonths(Date(-2000, 9, 5)) == 10); 6326 assert(dateBC.diffMonths(Date(-2000, 10, 5)) == 9); 6327 assert(dateBC.diffMonths(Date(-2000, 11, 5)) == 8); 6328 assert(dateBC.diffMonths(Date(-2000, 12, 5)) == 7); 6329 assert(dateBC.diffMonths(Date(-1999, 1, 5)) == 6); 6330 assert(dateBC.diffMonths(Date(-1999, 2, 6)) == 5); 6331 assert(dateBC.diffMonths(Date(-1999, 3, 6)) == 4); 6332 assert(dateBC.diffMonths(Date(-1999, 4, 6)) == 3); 6333 assert(dateBC.diffMonths(Date(-1999, 5, 6)) == 2); 6334 assert(dateBC.diffMonths(Date(-1999, 6, 6)) == 1); 6335 assert(dateBC.diffMonths(dateBC) == 0); 6336 assert(dateBC.diffMonths(Date(-1999, 8, 6)) == -1); 6337 assert(dateBC.diffMonths(Date(-1999, 9, 6)) == -2); 6338 assert(dateBC.diffMonths(Date(-1999, 10, 6)) == -3); 6339 assert(dateBC.diffMonths(Date(-1999, 11, 6)) == -4); 6340 assert(dateBC.diffMonths(Date(-1999, 12, 6)) == -5); 6341 assert(dateBC.diffMonths(Date(-1998, 1, 6)) == -6); 6342 assert(dateBC.diffMonths(Date(-1998, 2, 6)) == -7); 6343 assert(dateBC.diffMonths(Date(-1998, 3, 6)) == -8); 6344 assert(dateBC.diffMonths(Date(-1998, 4, 6)) == -9); 6345 assert(dateBC.diffMonths(Date(-1998, 5, 6)) == -10); 6346 assert(dateBC.diffMonths(Date(-1998, 6, 6)) == -11); 6347 assert(dateBC.diffMonths(Date(-1998, 7, 6)) == -12); 6348 assert(dateBC.diffMonths(Date(-1998, 8, 6)) == -13); 6349 6350 assert(Date(-2000, 6, 5).diffMonths(dateBC) == -13); 6351 assert(Date(-2000, 7, 5).diffMonths(dateBC) == -12); 6352 assert(Date(-2000, 8, 5).diffMonths(dateBC) == -11); 6353 assert(Date(-2000, 9, 5).diffMonths(dateBC) == -10); 6354 assert(Date(-2000, 10, 5).diffMonths(dateBC) == -9); 6355 assert(Date(-2000, 11, 5).diffMonths(dateBC) == -8); 6356 assert(Date(-2000, 12, 5).diffMonths(dateBC) == -7); 6357 assert(Date(-1999, 1, 5).diffMonths(dateBC) == -6); 6358 assert(Date(-1999, 2, 6).diffMonths(dateBC) == -5); 6359 assert(Date(-1999, 3, 6).diffMonths(dateBC) == -4); 6360 assert(Date(-1999, 4, 6).diffMonths(dateBC) == -3); 6361 assert(Date(-1999, 5, 6).diffMonths(dateBC) == -2); 6362 assert(Date(-1999, 6, 6).diffMonths(dateBC) == -1); 6363 assert(Date(-1999, 8, 6).diffMonths(dateBC) == 1); 6364 assert(Date(-1999, 9, 6).diffMonths(dateBC) == 2); 6365 assert(Date(-1999, 10, 6).diffMonths(dateBC) == 3); 6366 assert(Date(-1999, 11, 6).diffMonths(dateBC) == 4); 6367 assert(Date(-1999, 12, 6).diffMonths(dateBC) == 5); 6368 assert(Date(-1998, 1, 6).diffMonths(dateBC) == 6); 6369 assert(Date(-1998, 2, 6).diffMonths(dateBC) == 7); 6370 assert(Date(-1998, 3, 6).diffMonths(dateBC) == 8); 6371 assert(Date(-1998, 4, 6).diffMonths(dateBC) == 9); 6372 assert(Date(-1998, 5, 6).diffMonths(dateBC) == 10); 6373 assert(Date(-1998, 6, 6).diffMonths(dateBC) == 11); 6374 assert(Date(-1998, 7, 6).diffMonths(dateBC) == 12); 6375 assert(Date(-1998, 8, 6).diffMonths(dateBC) == 13); 6376 6377 assert(dateBC.diffMonths(Date(-1999, 6, 30)) == 1); 6378 assert(dateBC.diffMonths(Date(-1999, 7, 1)) == 0); 6379 assert(dateBC.diffMonths(Date(-1999, 7, 6)) == 0); 6380 assert(dateBC.diffMonths(Date(-1999, 7, 11)) == 0); 6381 assert(dateBC.diffMonths(Date(-1999, 7, 16)) == 0); 6382 assert(dateBC.diffMonths(Date(-1999, 7, 21)) == 0); 6383 assert(dateBC.diffMonths(Date(-1999, 7, 26)) == 0); 6384 assert(dateBC.diffMonths(Date(-1999, 7, 31)) == 0); 6385 assert(dateBC.diffMonths(Date(-1999, 8, 1)) == -1); 6386 6387 assert(dateBC.diffMonths(Date(-2008, 6, 30)) == 109); 6388 assert(dateBC.diffMonths(Date(-2008, 7, 1)) == 108); 6389 assert(dateBC.diffMonths(Date(-2008, 7, 6)) == 108); 6390 assert(dateBC.diffMonths(Date(-2008, 7, 11)) == 108); 6391 assert(dateBC.diffMonths(Date(-2008, 7, 16)) == 108); 6392 assert(dateBC.diffMonths(Date(-2008, 7, 21)) == 108); 6393 assert(dateBC.diffMonths(Date(-2008, 7, 26)) == 108); 6394 assert(dateBC.diffMonths(Date(-2008, 7, 31)) == 108); 6395 assert(dateBC.diffMonths(Date(-2008, 8, 1)) == 107); 6396 6397 assert(Date(-1999, 6, 30).diffMonths(dateBC) == -1); 6398 assert(Date(-1999, 7, 1).diffMonths(dateBC) == 0); 6399 assert(Date(-1999, 7, 6).diffMonths(dateBC) == 0); 6400 assert(Date(-1999, 7, 11).diffMonths(dateBC) == 0); 6401 assert(Date(-1999, 7, 16).diffMonths(dateBC) == 0); 6402 assert(Date(-1999, 7, 21).diffMonths(dateBC) == 0); 6403 assert(Date(-1999, 7, 26).diffMonths(dateBC) == 0); 6404 assert(Date(-1999, 7, 31).diffMonths(dateBC) == 0); 6405 assert(Date(-1999, 8, 1).diffMonths(dateBC) == 1); 6406 6407 assert(Date(-2008, 6, 30).diffMonths(dateBC) == -109); 6408 assert(Date(-2008, 7, 1).diffMonths(dateBC) == -108); 6409 assert(Date(-2008, 7, 6).diffMonths(dateBC) == -108); 6410 assert(Date(-2008, 7, 11).diffMonths(dateBC) == -108); 6411 assert(Date(-2008, 7, 16).diffMonths(dateBC) == -108); 6412 assert(Date(-2008, 7, 21).diffMonths(dateBC) == -108); 6413 assert(Date(-2008, 7, 26).diffMonths(dateBC) == -108); 6414 assert(Date(-2008, 7, 31).diffMonths(dateBC) == -108); 6415 assert(Date(-2008, 8, 1).diffMonths(dateBC) == -107); 6416 6417 // Test Both 6418 assert(Date(3, 3, 3).diffMonths(Date(-5, 5, 5)) == 94); 6419 assert(Date(-5, 5, 5).diffMonths(Date(3, 3, 3)) == -94); 6420 6421 const cdate = Date(1999, 7, 6); 6422 immutable idate = Date(1999, 7, 6); 6423 assert(date.diffMonths(date) == 0); 6424 assert(cdate.diffMonths(date) == 0); 6425 assert(idate.diffMonths(date) == 0); 6426 6427 assert(date.diffMonths(cdate) == 0); 6428 assert(cdate.diffMonths(cdate) == 0); 6429 assert(idate.diffMonths(cdate) == 0); 6430 6431 assert(date.diffMonths(idate) == 0); 6432 assert(cdate.diffMonths(idate) == 0); 6433 assert(idate.diffMonths(idate) == 0); 6434 } 6435 6436 6437 /++ 6438 Whether this $(LREF Date) is in a leap year. 6439 +/ 6440 @property bool isLeapYear() const @safe pure nothrow @nogc 6441 { 6442 return yearIsLeapYear(_year); 6443 } 6444 6445 @safe unittest 6446 { 6447 auto date = Date(1999, 7, 6); 6448 const cdate = Date(1999, 7, 6); 6449 immutable idate = Date(1999, 7, 6); 6450 static assert(!__traits(compiles, date.isLeapYear = true)); 6451 static assert(!__traits(compiles, cdate.isLeapYear = true)); 6452 static assert(!__traits(compiles, idate.isLeapYear = true)); 6453 } 6454 6455 6456 /++ 6457 Day of the week this $(LREF Date) is on. 6458 +/ 6459 @property DayOfWeek dayOfWeek() const @safe pure nothrow @nogc 6460 { 6461 return getDayOfWeek(dayOfGregorianCal); 6462 } 6463 6464 @safe unittest 6465 { 6466 const cdate = Date(1999, 7, 6); 6467 immutable idate = Date(1999, 7, 6); 6468 assert(cdate.dayOfWeek == DayOfWeek.tue); 6469 static assert(!__traits(compiles, cdate.dayOfWeek = DayOfWeek.sun)); 6470 assert(idate.dayOfWeek == DayOfWeek.tue); 6471 static assert(!__traits(compiles, idate.dayOfWeek = DayOfWeek.sun)); 6472 } 6473 6474 6475 /++ 6476 Day of the year this $(LREF Date) is on. 6477 +/ 6478 @property ushort dayOfYear() const @safe pure nothrow @nogc 6479 { 6480 if (_month >= Month.jan && _month <= Month.dec) 6481 { 6482 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6483 auto monthIndex = _month - Month.jan; 6484 6485 return cast(ushort)(lastDay[monthIndex] + _day); 6486 } 6487 assert(0, "Invalid month."); 6488 } 6489 6490 /// 6491 @safe unittest 6492 { 6493 assert(Date(1999, 1, 1).dayOfYear == 1); 6494 assert(Date(1999, 12, 31).dayOfYear == 365); 6495 assert(Date(2000, 12, 31).dayOfYear == 366); 6496 } 6497 6498 @safe unittest 6499 { 6500 import std.algorithm.iteration : filter; 6501 import std.range : chain; 6502 6503 foreach (year; filter!((a){return !yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6504 { 6505 foreach (doy; testDaysOfYear) 6506 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6507 } 6508 6509 foreach (year; filter!((a){return yearIsLeapYear(a);})(chain(testYearsBC, testYearsAD))) 6510 { 6511 foreach (doy; testDaysOfLeapYear) 6512 assert(Date(year, doy.md.month, doy.md.day).dayOfYear == doy.day); 6513 } 6514 6515 const cdate = Date(1999, 7, 6); 6516 immutable idate = Date(1999, 7, 6); 6517 assert(cdate.dayOfYear == 187); 6518 assert(idate.dayOfYear == 187); 6519 } 6520 6521 /++ 6522 Day of the year. 6523 6524 Params: 6525 day = The day of the year to set which day of the year this 6526 $(LREF Date) is on. 6527 6528 Throws: 6529 $(REF DateTimeException,std,datetime,date) if the given day is an 6530 invalid day of the year. 6531 +/ 6532 @property void dayOfYear(int day) @safe pure 6533 { 6534 setDayOfYear!true(day); 6535 } 6536 6537 private void setDayOfYear(bool useExceptions = false)(int day) 6538 { 6539 immutable int[] lastDay = isLeapYear ? lastDayLeap : lastDayNonLeap; 6540 6541 bool dayOutOfRange = day <= 0 || day > (isLeapYear ? daysInLeapYear : daysInYear); 6542 enum errorMsg = "Invalid day of the year."; 6543 6544 static if (useExceptions) 6545 { 6546 if (dayOutOfRange) throw new DateTimeException(errorMsg); 6547 } 6548 else 6549 { 6550 assert(!dayOutOfRange, errorMsg); 6551 } 6552 6553 foreach (i; 1 .. lastDay.length) 6554 { 6555 if (day <= lastDay[i]) 6556 { 6557 _month = cast(Month)(cast(int) Month.jan + i - 1); 6558 _day = cast(ubyte)(day - lastDay[i - 1]); 6559 return; 6560 } 6561 } 6562 assert(0, "Invalid day of the year."); 6563 } 6564 6565 @safe unittest 6566 { 6567 static void test(Date date, int day, MonthDay expected, size_t line = __LINE__) 6568 { 6569 date.dayOfYear = day; 6570 assert(date.month == expected.month); 6571 assert(date.day == expected.day); 6572 } 6573 6574 foreach (doy; testDaysOfYear) 6575 { 6576 test(Date(1999, 1, 1), doy.day, doy.md); 6577 test(Date(-1, 1, 1), doy.day, doy.md); 6578 } 6579 6580 foreach (doy; testDaysOfLeapYear) 6581 { 6582 test(Date(2000, 1, 1), doy.day, doy.md); 6583 test(Date(-4, 1, 1), doy.day, doy.md); 6584 } 6585 6586 const cdate = Date(1999, 7, 6); 6587 immutable idate = Date(1999, 7, 6); 6588 static assert(!__traits(compiles, cdate.dayOfYear = 187)); 6589 static assert(!__traits(compiles, idate.dayOfYear = 187)); 6590 } 6591 6592 6593 /++ 6594 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6595 +/ 6596 @property int dayOfGregorianCal() const @safe pure nothrow @nogc 6597 { 6598 if (isAD) 6599 { 6600 if (_year == 1) 6601 return dayOfYear; 6602 6603 int years = _year - 1; 6604 auto days = (years / 400) * daysIn400Years; 6605 years %= 400; 6606 6607 days += (years / 100) * daysIn100Years; 6608 years %= 100; 6609 6610 days += (years / 4) * daysIn4Years; 6611 years %= 4; 6612 6613 days += years * daysInYear; 6614 6615 days += dayOfYear; 6616 6617 return days; 6618 } 6619 else if (_year == 0) 6620 return dayOfYear - daysInLeapYear; 6621 else 6622 { 6623 int years = _year; 6624 auto days = (years / 400) * daysIn400Years; 6625 years %= 400; 6626 6627 days += (years / 100) * daysIn100Years; 6628 years %= 100; 6629 6630 days += (years / 4) * daysIn4Years; 6631 years %= 4; 6632 6633 if (years < 0) 6634 { 6635 days -= daysInLeapYear; 6636 ++years; 6637 6638 days += years * daysInYear; 6639 6640 days -= daysInYear - dayOfYear; 6641 } 6642 else 6643 days -= daysInLeapYear - dayOfYear; 6644 6645 return days; 6646 } 6647 } 6648 6649 /// 6650 @safe unittest 6651 { 6652 assert(Date(1, 1, 1).dayOfGregorianCal == 1); 6653 assert(Date(1, 12, 31).dayOfGregorianCal == 365); 6654 assert(Date(2, 1, 1).dayOfGregorianCal == 366); 6655 6656 assert(Date(0, 12, 31).dayOfGregorianCal == 0); 6657 assert(Date(0, 1, 1).dayOfGregorianCal == -365); 6658 assert(Date(-1, 12, 31).dayOfGregorianCal == -366); 6659 6660 assert(Date(2000, 1, 1).dayOfGregorianCal == 730_120); 6661 assert(Date(2010, 12, 31).dayOfGregorianCal == 734_137); 6662 } 6663 6664 @safe unittest 6665 { 6666 import std.range : chain; 6667 6668 foreach (gd; chain(testGregDaysBC, testGregDaysAD)) 6669 assert(gd.date.dayOfGregorianCal == gd.day); 6670 6671 auto date = Date(1999, 7, 6); 6672 const cdate = Date(1999, 7, 6); 6673 immutable idate = Date(1999, 7, 6); 6674 assert(date.dayOfGregorianCal == 729_941); 6675 assert(cdate.dayOfGregorianCal == 729_941); 6676 assert(idate.dayOfGregorianCal == 729_941); 6677 } 6678 6679 /++ 6680 The Xth day of the Gregorian Calendar that this $(LREF Date) is on. 6681 6682 Params: 6683 day = The day of the Gregorian Calendar to set this $(LREF Date) to. 6684 +/ 6685 @property void dayOfGregorianCal(int day) @safe pure nothrow @nogc 6686 { 6687 this = Date(day); 6688 } 6689 6690 /// 6691 @safe unittest 6692 { 6693 auto date = Date.init; 6694 date.dayOfGregorianCal = 1; 6695 assert(date == Date(1, 1, 1)); 6696 6697 date.dayOfGregorianCal = 365; 6698 assert(date == Date(1, 12, 31)); 6699 6700 date.dayOfGregorianCal = 366; 6701 assert(date == Date(2, 1, 1)); 6702 6703 date.dayOfGregorianCal = 0; 6704 assert(date == Date(0, 12, 31)); 6705 6706 date.dayOfGregorianCal = -365; 6707 assert(date == Date(-0, 1, 1)); 6708 6709 date.dayOfGregorianCal = -366; 6710 assert(date == Date(-1, 12, 31)); 6711 6712 date.dayOfGregorianCal = 730_120; 6713 assert(date == Date(2000, 1, 1)); 6714 6715 date.dayOfGregorianCal = 734_137; 6716 assert(date == Date(2010, 12, 31)); 6717 } 6718 6719 @safe unittest 6720 { 6721 auto date = Date(1999, 7, 6); 6722 const cdate = Date(1999, 7, 6); 6723 immutable idate = Date(1999, 7, 6); 6724 date.dayOfGregorianCal = 187; 6725 assert(date.dayOfGregorianCal == 187); 6726 static assert(!__traits(compiles, cdate.dayOfGregorianCal = 187)); 6727 static assert(!__traits(compiles, idate.dayOfGregorianCal = 187)); 6728 } 6729 6730 6731 /++ 6732 The ISO 8601 week of the year that this $(LREF Date) is in. 6733 6734 See_Also: 6735 $(HTTP en.wikipedia.org/wiki/ISO_week_date, ISO Week Date) 6736 +/ 6737 @property ubyte isoWeek() const @safe pure nothrow 6738 { 6739 immutable weekday = dayOfWeek; 6740 immutable adjustedWeekday = weekday == DayOfWeek.sun ? 7 : weekday; 6741 immutable week = (dayOfYear - adjustedWeekday + 10) / 7; 6742 6743 try 6744 { 6745 if (week == 53) 6746 { 6747 switch (Date(_year + 1, 1, 1).dayOfWeek) 6748 { 6749 case DayOfWeek.mon: 6750 case DayOfWeek.tue: 6751 case DayOfWeek.wed: 6752 case DayOfWeek.thu: 6753 return 1; 6754 case DayOfWeek.fri: 6755 case DayOfWeek.sat: 6756 case DayOfWeek.sun: 6757 return 53; 6758 default: 6759 assert(0, "Invalid ISO Week"); 6760 } 6761 } 6762 else if (week > 0) 6763 return cast(ubyte) week; 6764 else 6765 return Date(_year - 1, 12, 31).isoWeek; 6766 } 6767 catch (Exception e) 6768 assert(0, "Date's constructor threw."); 6769 } 6770 6771 @safe unittest 6772 { 6773 // Test A.D. 6774 assert(Date(2009, 12, 28).isoWeek == 53); 6775 assert(Date(2009, 12, 29).isoWeek == 53); 6776 assert(Date(2009, 12, 30).isoWeek == 53); 6777 assert(Date(2009, 12, 31).isoWeek == 53); 6778 assert(Date(2010, 1, 1).isoWeek == 53); 6779 assert(Date(2010, 1, 2).isoWeek == 53); 6780 assert(Date(2010, 1, 3).isoWeek == 53); 6781 assert(Date(2010, 1, 4).isoWeek == 1); 6782 assert(Date(2010, 1, 5).isoWeek == 1); 6783 assert(Date(2010, 1, 6).isoWeek == 1); 6784 assert(Date(2010, 1, 7).isoWeek == 1); 6785 assert(Date(2010, 1, 8).isoWeek == 1); 6786 assert(Date(2010, 1, 9).isoWeek == 1); 6787 assert(Date(2010, 1, 10).isoWeek == 1); 6788 assert(Date(2010, 1, 11).isoWeek == 2); 6789 assert(Date(2010, 12, 31).isoWeek == 52); 6790 6791 assert(Date(2004, 12, 26).isoWeek == 52); 6792 assert(Date(2004, 12, 27).isoWeek == 53); 6793 assert(Date(2004, 12, 28).isoWeek == 53); 6794 assert(Date(2004, 12, 29).isoWeek == 53); 6795 assert(Date(2004, 12, 30).isoWeek == 53); 6796 assert(Date(2004, 12, 31).isoWeek == 53); 6797 assert(Date(2005, 1, 1).isoWeek == 53); 6798 assert(Date(2005, 1, 2).isoWeek == 53); 6799 6800 assert(Date(2005, 12, 31).isoWeek == 52); 6801 assert(Date(2007, 1, 1).isoWeek == 1); 6802 6803 assert(Date(2007, 12, 30).isoWeek == 52); 6804 assert(Date(2007, 12, 31).isoWeek == 1); 6805 assert(Date(2008, 1, 1).isoWeek == 1); 6806 6807 assert(Date(2008, 12, 28).isoWeek == 52); 6808 assert(Date(2008, 12, 29).isoWeek == 1); 6809 assert(Date(2008, 12, 30).isoWeek == 1); 6810 assert(Date(2008, 12, 31).isoWeek == 1); 6811 assert(Date(2009, 1, 1).isoWeek == 1); 6812 assert(Date(2009, 1, 2).isoWeek == 1); 6813 assert(Date(2009, 1, 3).isoWeek == 1); 6814 assert(Date(2009, 1, 4).isoWeek == 1); 6815 6816 // Test B.C. 6817 // The algorithm should work identically for both A.D. and B.C. since 6818 // it doesn't really take the year into account, so B.C. testing 6819 // probably isn't really needed. 6820 assert(Date(0, 12, 31).isoWeek == 52); 6821 assert(Date(0, 1, 4).isoWeek == 1); 6822 assert(Date(0, 1, 1).isoWeek == 52); 6823 6824 const cdate = Date(1999, 7, 6); 6825 immutable idate = Date(1999, 7, 6); 6826 assert(cdate.isoWeek == 27); 6827 static assert(!__traits(compiles, cdate.isoWeek = 3)); 6828 assert(idate.isoWeek == 27); 6829 static assert(!__traits(compiles, idate.isoWeek = 3)); 6830 } 6831 6832 6833 /++ 6834 $(LREF Date) for the last day in the month that this $(LREF Date) is in. 6835 +/ 6836 @property Date endOfMonth() const @safe pure nothrow 6837 { 6838 try 6839 return Date(_year, _month, maxDay(_year, _month)); 6840 catch (Exception e) 6841 assert(0, "Date's constructor threw."); 6842 } 6843 6844 /// 6845 @safe unittest 6846 { 6847 assert(Date(1999, 1, 6).endOfMonth == Date(1999, 1, 31)); 6848 assert(Date(1999, 2, 7).endOfMonth == Date(1999, 2, 28)); 6849 assert(Date(2000, 2, 7).endOfMonth == Date(2000, 2, 29)); 6850 assert(Date(2000, 6, 4).endOfMonth == Date(2000, 6, 30)); 6851 } 6852 6853 @safe unittest 6854 { 6855 // Test A.D. 6856 assert(Date(1999, 1, 1).endOfMonth == Date(1999, 1, 31)); 6857 assert(Date(1999, 2, 1).endOfMonth == Date(1999, 2, 28)); 6858 assert(Date(2000, 2, 1).endOfMonth == Date(2000, 2, 29)); 6859 assert(Date(1999, 3, 1).endOfMonth == Date(1999, 3, 31)); 6860 assert(Date(1999, 4, 1).endOfMonth == Date(1999, 4, 30)); 6861 assert(Date(1999, 5, 1).endOfMonth == Date(1999, 5, 31)); 6862 assert(Date(1999, 6, 1).endOfMonth == Date(1999, 6, 30)); 6863 assert(Date(1999, 7, 1).endOfMonth == Date(1999, 7, 31)); 6864 assert(Date(1999, 8, 1).endOfMonth == Date(1999, 8, 31)); 6865 assert(Date(1999, 9, 1).endOfMonth == Date(1999, 9, 30)); 6866 assert(Date(1999, 10, 1).endOfMonth == Date(1999, 10, 31)); 6867 assert(Date(1999, 11, 1).endOfMonth == Date(1999, 11, 30)); 6868 assert(Date(1999, 12, 1).endOfMonth == Date(1999, 12, 31)); 6869 6870 // Test B.C. 6871 assert(Date(-1999, 1, 1).endOfMonth == Date(-1999, 1, 31)); 6872 assert(Date(-1999, 2, 1).endOfMonth == Date(-1999, 2, 28)); 6873 assert(Date(-2000, 2, 1).endOfMonth == Date(-2000, 2, 29)); 6874 assert(Date(-1999, 3, 1).endOfMonth == Date(-1999, 3, 31)); 6875 assert(Date(-1999, 4, 1).endOfMonth == Date(-1999, 4, 30)); 6876 assert(Date(-1999, 5, 1).endOfMonth == Date(-1999, 5, 31)); 6877 assert(Date(-1999, 6, 1).endOfMonth == Date(-1999, 6, 30)); 6878 assert(Date(-1999, 7, 1).endOfMonth == Date(-1999, 7, 31)); 6879 assert(Date(-1999, 8, 1).endOfMonth == Date(-1999, 8, 31)); 6880 assert(Date(-1999, 9, 1).endOfMonth == Date(-1999, 9, 30)); 6881 assert(Date(-1999, 10, 1).endOfMonth == Date(-1999, 10, 31)); 6882 assert(Date(-1999, 11, 1).endOfMonth == Date(-1999, 11, 30)); 6883 assert(Date(-1999, 12, 1).endOfMonth == Date(-1999, 12, 31)); 6884 6885 const cdate = Date(1999, 7, 6); 6886 immutable idate = Date(1999, 7, 6); 6887 static assert(!__traits(compiles, cdate.endOfMonth = Date(1999, 7, 30))); 6888 static assert(!__traits(compiles, idate.endOfMonth = Date(1999, 7, 30))); 6889 } 6890 6891 6892 /++ 6893 The last day in the month that this $(LREF Date) is in. 6894 +/ 6895 @property ubyte daysInMonth() const @safe pure nothrow @nogc 6896 { 6897 return maxDay(_year, _month); 6898 } 6899 6900 /// 6901 @safe unittest 6902 { 6903 assert(Date(1999, 1, 6).daysInMonth == 31); 6904 assert(Date(1999, 2, 7).daysInMonth == 28); 6905 assert(Date(2000, 2, 7).daysInMonth == 29); 6906 assert(Date(2000, 6, 4).daysInMonth == 30); 6907 } 6908 6909 @safe unittest 6910 { 6911 // Test A.D. 6912 assert(Date(1999, 1, 1).daysInMonth == 31); 6913 assert(Date(1999, 2, 1).daysInMonth == 28); 6914 assert(Date(2000, 2, 1).daysInMonth == 29); 6915 assert(Date(1999, 3, 1).daysInMonth == 31); 6916 assert(Date(1999, 4, 1).daysInMonth == 30); 6917 assert(Date(1999, 5, 1).daysInMonth == 31); 6918 assert(Date(1999, 6, 1).daysInMonth == 30); 6919 assert(Date(1999, 7, 1).daysInMonth == 31); 6920 assert(Date(1999, 8, 1).daysInMonth == 31); 6921 assert(Date(1999, 9, 1).daysInMonth == 30); 6922 assert(Date(1999, 10, 1).daysInMonth == 31); 6923 assert(Date(1999, 11, 1).daysInMonth == 30); 6924 assert(Date(1999, 12, 1).daysInMonth == 31); 6925 6926 // Test B.C. 6927 assert(Date(-1999, 1, 1).daysInMonth == 31); 6928 assert(Date(-1999, 2, 1).daysInMonth == 28); 6929 assert(Date(-2000, 2, 1).daysInMonth == 29); 6930 assert(Date(-1999, 3, 1).daysInMonth == 31); 6931 assert(Date(-1999, 4, 1).daysInMonth == 30); 6932 assert(Date(-1999, 5, 1).daysInMonth == 31); 6933 assert(Date(-1999, 6, 1).daysInMonth == 30); 6934 assert(Date(-1999, 7, 1).daysInMonth == 31); 6935 assert(Date(-1999, 8, 1).daysInMonth == 31); 6936 assert(Date(-1999, 9, 1).daysInMonth == 30); 6937 assert(Date(-1999, 10, 1).daysInMonth == 31); 6938 assert(Date(-1999, 11, 1).daysInMonth == 30); 6939 assert(Date(-1999, 12, 1).daysInMonth == 31); 6940 6941 const cdate = Date(1999, 7, 6); 6942 immutable idate = Date(1999, 7, 6); 6943 static assert(!__traits(compiles, cdate.daysInMonth = 30)); 6944 static assert(!__traits(compiles, idate.daysInMonth = 30)); 6945 } 6946 6947 6948 /++ 6949 Whether the current year is a date in A.D. 6950 +/ 6951 @property bool isAD() const @safe pure nothrow @nogc 6952 { 6953 return _year > 0; 6954 } 6955 6956 /// 6957 @safe unittest 6958 { 6959 assert(Date(1, 1, 1).isAD); 6960 assert(Date(2010, 12, 31).isAD); 6961 assert(!Date(0, 12, 31).isAD); 6962 assert(!Date(-2010, 1, 1).isAD); 6963 } 6964 6965 @safe unittest 6966 { 6967 assert(Date(2010, 7, 4).isAD); 6968 assert(Date(1, 1, 1).isAD); 6969 assert(!Date(0, 1, 1).isAD); 6970 assert(!Date(-1, 1, 1).isAD); 6971 assert(!Date(-2010, 7, 4).isAD); 6972 6973 const cdate = Date(1999, 7, 6); 6974 immutable idate = Date(1999, 7, 6); 6975 assert(cdate.isAD); 6976 assert(idate.isAD); 6977 } 6978 6979 6980 /++ 6981 The $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for this 6982 $(LREF Date) at noon (since the Julian day changes at noon). 6983 +/ 6984 @property long julianDay() const @safe pure nothrow @nogc 6985 { 6986 return dayOfGregorianCal + 1_721_425; 6987 } 6988 6989 @safe unittest 6990 { 6991 assert(Date(-4713, 11, 24).julianDay == 0); 6992 assert(Date(0, 12, 31).julianDay == 1_721_425); 6993 assert(Date(1, 1, 1).julianDay == 1_721_426); 6994 assert(Date(1582, 10, 15).julianDay == 2_299_161); 6995 assert(Date(1858, 11, 17).julianDay == 2_400_001); 6996 assert(Date(1982, 1, 4).julianDay == 2_444_974); 6997 assert(Date(1996, 3, 31).julianDay == 2_450_174); 6998 assert(Date(2010, 8, 24).julianDay == 2_455_433); 6999 7000 const cdate = Date(1999, 7, 6); 7001 immutable idate = Date(1999, 7, 6); 7002 assert(cdate.julianDay == 2_451_366); 7003 assert(idate.julianDay == 2_451_366); 7004 } 7005 7006 7007 /++ 7008 The modified $(HTTP en.wikipedia.org/wiki/Julian_day, Julian day) for 7009 any time on this date (since, the modified Julian day changes at 7010 midnight). 7011 +/ 7012 @property long modJulianDay() const @safe pure nothrow @nogc 7013 { 7014 return julianDay - 2_400_001; 7015 } 7016 7017 @safe unittest 7018 { 7019 assert(Date(1858, 11, 17).modJulianDay == 0); 7020 assert(Date(2010, 8, 24).modJulianDay == 55_432); 7021 7022 const cdate = Date(1999, 7, 6); 7023 immutable idate = Date(1999, 7, 6); 7024 assert(cdate.modJulianDay == 51_365); 7025 assert(idate.modJulianDay == 51_365); 7026 } 7027 7028 7029 /++ 7030 Converts this $(LREF Date) to a string with the format YYYYMMDD. 7031 +/ 7032 string toISOString() const @safe pure nothrow 7033 { 7034 import std.format : format; 7035 try 7036 { 7037 if (_year >= 0) 7038 { 7039 if (_year < 10_000) 7040 return format("%04d%02d%02d", _year, _month, _day); 7041 else 7042 return format("+%05d%02d%02d", _year, _month, _day); 7043 } 7044 else if (_year > -10_000) 7045 return format("%05d%02d%02d", _year, _month, _day); 7046 else 7047 return format("%06d%02d%02d", _year, _month, _day); 7048 } 7049 catch (Exception e) 7050 assert(0, "format() threw."); 7051 } 7052 7053 /// 7054 @safe unittest 7055 { 7056 assert(Date(2010, 7, 4).toISOString() == "20100704"); 7057 assert(Date(1998, 12, 25).toISOString() == "19981225"); 7058 assert(Date(0, 1, 5).toISOString() == "00000105"); 7059 assert(Date(-4, 1, 5).toISOString() == "-00040105"); 7060 } 7061 7062 @safe unittest 7063 { 7064 // Test A.D. 7065 assert(Date(9, 12, 4).toISOString() == "00091204"); 7066 assert(Date(99, 12, 4).toISOString() == "00991204"); 7067 assert(Date(999, 12, 4).toISOString() == "09991204"); 7068 assert(Date(9999, 7, 4).toISOString() == "99990704"); 7069 assert(Date(10000, 10, 20).toISOString() == "+100001020"); 7070 7071 // Test B.C. 7072 assert(Date(0, 12, 4).toISOString() == "00001204"); 7073 assert(Date(-9, 12, 4).toISOString() == "-00091204"); 7074 assert(Date(-99, 12, 4).toISOString() == "-00991204"); 7075 assert(Date(-999, 12, 4).toISOString() == "-09991204"); 7076 assert(Date(-9999, 7, 4).toISOString() == "-99990704"); 7077 assert(Date(-10000, 10, 20).toISOString() == "-100001020"); 7078 7079 const cdate = Date(1999, 7, 6); 7080 immutable idate = Date(1999, 7, 6); 7081 assert(cdate.toISOString() == "19990706"); 7082 assert(idate.toISOString() == "19990706"); 7083 } 7084 7085 /++ 7086 Converts this $(LREF Date) to a string with the format YYYY-MM-DD. 7087 +/ 7088 string toISOExtString() const @safe pure nothrow 7089 { 7090 import std.format : format; 7091 try 7092 { 7093 if (_year >= 0) 7094 { 7095 if (_year < 10_000) 7096 return format("%04d-%02d-%02d", _year, _month, _day); 7097 else 7098 return format("+%05d-%02d-%02d", _year, _month, _day); 7099 } 7100 else if (_year > -10_000) 7101 return format("%05d-%02d-%02d", _year, _month, _day); 7102 else 7103 return format("%06d-%02d-%02d", _year, _month, _day); 7104 } 7105 catch (Exception e) 7106 assert(0, "format() threw."); 7107 } 7108 7109 /// 7110 @safe unittest 7111 { 7112 assert(Date(2010, 7, 4).toISOExtString() == "2010-07-04"); 7113 assert(Date(1998, 12, 25).toISOExtString() == "1998-12-25"); 7114 assert(Date(0, 1, 5).toISOExtString() == "0000-01-05"); 7115 assert(Date(-4, 1, 5).toISOExtString() == "-0004-01-05"); 7116 } 7117 7118 @safe unittest 7119 { 7120 // Test A.D. 7121 assert(Date(9, 12, 4).toISOExtString() == "0009-12-04"); 7122 assert(Date(99, 12, 4).toISOExtString() == "0099-12-04"); 7123 assert(Date(999, 12, 4).toISOExtString() == "0999-12-04"); 7124 assert(Date(9999, 7, 4).toISOExtString() == "9999-07-04"); 7125 assert(Date(10000, 10, 20).toISOExtString() == "+10000-10-20"); 7126 7127 // Test B.C. 7128 assert(Date(0, 12, 4).toISOExtString() == "0000-12-04"); 7129 assert(Date(-9, 12, 4).toISOExtString() == "-0009-12-04"); 7130 assert(Date(-99, 12, 4).toISOExtString() == "-0099-12-04"); 7131 assert(Date(-999, 12, 4).toISOExtString() == "-0999-12-04"); 7132 assert(Date(-9999, 7, 4).toISOExtString() == "-9999-07-04"); 7133 assert(Date(-10000, 10, 20).toISOExtString() == "-10000-10-20"); 7134 7135 const cdate = Date(1999, 7, 6); 7136 immutable idate = Date(1999, 7, 6); 7137 assert(cdate.toISOExtString() == "1999-07-06"); 7138 assert(idate.toISOExtString() == "1999-07-06"); 7139 } 7140 7141 /++ 7142 Converts this $(LREF Date) to a string with the format YYYY-Mon-DD. 7143 +/ 7144 string toSimpleString() const @safe pure nothrow 7145 { 7146 import std.format : format; 7147 try 7148 { 7149 if (_year >= 0) 7150 { 7151 if (_year < 10_000) 7152 return format("%04d-%s-%02d", _year, monthToString(_month), _day); 7153 else 7154 return format("+%05d-%s-%02d", _year, monthToString(_month), _day); 7155 } 7156 else if (_year > -10_000) 7157 return format("%05d-%s-%02d", _year, monthToString(_month), _day); 7158 else 7159 return format("%06d-%s-%02d", _year, monthToString(_month), _day); 7160 } 7161 catch (Exception e) 7162 assert(0, "format() threw."); 7163 } 7164 7165 /// 7166 @safe unittest 7167 { 7168 assert(Date(2010, 7, 4).toSimpleString() == "2010-Jul-04"); 7169 assert(Date(1998, 12, 25).toSimpleString() == "1998-Dec-25"); 7170 assert(Date(0, 1, 5).toSimpleString() == "0000-Jan-05"); 7171 assert(Date(-4, 1, 5).toSimpleString() == "-0004-Jan-05"); 7172 } 7173 7174 @safe unittest 7175 { 7176 // Test A.D. 7177 assert(Date(9, 12, 4).toSimpleString() == "0009-Dec-04"); 7178 assert(Date(99, 12, 4).toSimpleString() == "0099-Dec-04"); 7179 assert(Date(999, 12, 4).toSimpleString() == "0999-Dec-04"); 7180 assert(Date(9999, 7, 4).toSimpleString() == "9999-Jul-04"); 7181 assert(Date(10000, 10, 20).toSimpleString() == "+10000-Oct-20"); 7182 7183 // Test B.C. 7184 assert(Date(0, 12, 4).toSimpleString() == "0000-Dec-04"); 7185 assert(Date(-9, 12, 4).toSimpleString() == "-0009-Dec-04"); 7186 assert(Date(-99, 12, 4).toSimpleString() == "-0099-Dec-04"); 7187 assert(Date(-999, 12, 4).toSimpleString() == "-0999-Dec-04"); 7188 assert(Date(-9999, 7, 4).toSimpleString() == "-9999-Jul-04"); 7189 assert(Date(-10000, 10, 20).toSimpleString() == "-10000-Oct-20"); 7190 7191 const cdate = Date(1999, 7, 6); 7192 immutable idate = Date(1999, 7, 6); 7193 assert(cdate.toSimpleString() == "1999-Jul-06"); 7194 assert(idate.toSimpleString() == "1999-Jul-06"); 7195 } 7196 7197 7198 /++ 7199 Converts this $(LREF Date) to a string. 7200 7201 This function exists to make it easy to convert a $(LREF Date) to a 7202 string for code that does not care what the exact format is - just that 7203 it presents the information in a clear manner. It also makes it easy to 7204 simply convert a $(LREF Date) to a string when using functions such as 7205 `to!string`, `format`, or `writeln` which use toString to convert 7206 user-defined types. So, it is unlikely that much code will call 7207 toString directly. 7208 7209 The format of the string is purposefully unspecified, and code that 7210 cares about the format of the string should use `toISOString`, 7211 `toISOExtString`, `toSimpleString`, or some other custom formatting 7212 function that explicitly generates the format that the code needs. The 7213 reason is that the code is then clear about what format it's using, 7214 making it less error-prone to maintain the code and interact with other 7215 software that consumes the generated strings. It's for this same reason 7216 $(LREF Date) has no `fromString` function, whereas it does have 7217 `fromISOString`, `fromISOExtString`, and `fromSimpleString`. 7218 7219 The format returned by toString may or may not change in the future. 7220 +/ 7221 string toString() const @safe pure nothrow 7222 { 7223 return toSimpleString(); 7224 } 7225 7226 @safe unittest 7227 { 7228 auto date = Date(1999, 7, 6); 7229 const cdate = Date(1999, 7, 6); 7230 immutable idate = Date(1999, 7, 6); 7231 assert(date.toString()); 7232 assert(cdate.toString()); 7233 assert(idate.toString()); 7234 } 7235 7236 7237 /++ 7238 Creates a $(LREF Date) from a string with the format YYYYMMDD. Whitespace 7239 is stripped from the given string. 7240 7241 Params: 7242 isoString = A string formatted in the ISO format for dates. 7243 7244 Throws: 7245 $(REF DateTimeException,std,datetime,date) if the given string is 7246 not in the ISO format or if the resulting $(LREF Date) would not be 7247 valid. 7248 +/ 7249 static Date fromISOString(S)(in S isoString) @safe pure 7250 if (isSomeString!S) 7251 { 7252 import std.algorithm.searching : startsWith; 7253 import std.conv : to, text, ConvException; 7254 import std.exception : enforce; 7255 import std.string : strip; 7256 7257 auto str = isoString.strip; 7258 7259 enforce!DateTimeException(str.length >= 8, text("Invalid ISO String: ", isoString)); 7260 7261 int day, month, year; 7262 auto yearStr = str[0 .. $ - 4]; 7263 7264 try 7265 { 7266 // using conversion to uint plus cast because it checks for +/- 7267 // for us quickly while throwing ConvException 7268 day = cast(int) to!uint(str[$ - 2 .. $]); 7269 month = cast(int) to!uint(str[$ - 4 .. $ - 2]); 7270 7271 if (yearStr.length > 4) 7272 { 7273 enforce!DateTimeException(yearStr.startsWith('-', '+'), 7274 text("Invalid ISO String: ", isoString)); 7275 year = to!int(yearStr); 7276 } 7277 else 7278 { 7279 year = cast(int) to!uint(yearStr); 7280 } 7281 } 7282 catch (ConvException) 7283 { 7284 throw new DateTimeException(text("Invalid ISO String: ", isoString)); 7285 } 7286 7287 return Date(year, month, day); 7288 } 7289 7290 /// 7291 @safe unittest 7292 { 7293 assert(Date.fromISOString("20100704") == Date(2010, 7, 4)); 7294 assert(Date.fromISOString("19981225") == Date(1998, 12, 25)); 7295 assert(Date.fromISOString("00000105") == Date(0, 1, 5)); 7296 assert(Date.fromISOString("-00040105") == Date(-4, 1, 5)); 7297 assert(Date.fromISOString(" 20100704 ") == Date(2010, 7, 4)); 7298 } 7299 7300 @safe unittest 7301 { 7302 assertThrown!DateTimeException(Date.fromISOString("")); 7303 assertThrown!DateTimeException(Date.fromISOString("990704")); 7304 assertThrown!DateTimeException(Date.fromISOString("0100704")); 7305 assertThrown!DateTimeException(Date.fromISOString("2010070")); 7306 assertThrown!DateTimeException(Date.fromISOString("2010070 ")); 7307 assertThrown!DateTimeException(Date.fromISOString("120100704")); 7308 assertThrown!DateTimeException(Date.fromISOString("-0100704")); 7309 assertThrown!DateTimeException(Date.fromISOString("+0100704")); 7310 assertThrown!DateTimeException(Date.fromISOString("2010070a")); 7311 assertThrown!DateTimeException(Date.fromISOString("20100a04")); 7312 assertThrown!DateTimeException(Date.fromISOString("2010a704")); 7313 7314 assertThrown!DateTimeException(Date.fromISOString("99-07-04")); 7315 assertThrown!DateTimeException(Date.fromISOString("010-07-04")); 7316 assertThrown!DateTimeException(Date.fromISOString("2010-07-0")); 7317 assertThrown!DateTimeException(Date.fromISOString("2010-07-0 ")); 7318 assertThrown!DateTimeException(Date.fromISOString("12010-07-04")); 7319 assertThrown!DateTimeException(Date.fromISOString("-010-07-04")); 7320 assertThrown!DateTimeException(Date.fromISOString("+010-07-04")); 7321 assertThrown!DateTimeException(Date.fromISOString("2010-07-0a")); 7322 assertThrown!DateTimeException(Date.fromISOString("2010-0a-04")); 7323 assertThrown!DateTimeException(Date.fromISOString("2010-a7-04")); 7324 assertThrown!DateTimeException(Date.fromISOString("2010/07/04")); 7325 assertThrown!DateTimeException(Date.fromISOString("2010/7/04")); 7326 assertThrown!DateTimeException(Date.fromISOString("2010/7/4")); 7327 assertThrown!DateTimeException(Date.fromISOString("2010/07/4")); 7328 assertThrown!DateTimeException(Date.fromISOString("2010-7-04")); 7329 assertThrown!DateTimeException(Date.fromISOString("2010-7-4")); 7330 assertThrown!DateTimeException(Date.fromISOString("2010-07-4")); 7331 7332 assertThrown!DateTimeException(Date.fromISOString("99Jul04")); 7333 assertThrown!DateTimeException(Date.fromISOString("010Jul04")); 7334 assertThrown!DateTimeException(Date.fromISOString("2010Jul0")); 7335 assertThrown!DateTimeException(Date.fromISOString("2010Jul0 ")); 7336 assertThrown!DateTimeException(Date.fromISOString("12010Jul04")); 7337 assertThrown!DateTimeException(Date.fromISOString("-010Jul04")); 7338 assertThrown!DateTimeException(Date.fromISOString("+010Jul04")); 7339 assertThrown!DateTimeException(Date.fromISOString("2010Jul0a")); 7340 assertThrown!DateTimeException(Date.fromISOString("2010Jua04")); 7341 assertThrown!DateTimeException(Date.fromISOString("2010aul04")); 7342 7343 assertThrown!DateTimeException(Date.fromISOString("99-Jul-04")); 7344 assertThrown!DateTimeException(Date.fromISOString("010-Jul-04")); 7345 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0")); 7346 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0 ")); 7347 assertThrown!DateTimeException(Date.fromISOString("12010-Jul-04")); 7348 assertThrown!DateTimeException(Date.fromISOString("-010-Jul-04")); 7349 assertThrown!DateTimeException(Date.fromISOString("+010-Jul-04")); 7350 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-0a")); 7351 assertThrown!DateTimeException(Date.fromISOString("2010-Jua-04")); 7352 assertThrown!DateTimeException(Date.fromISOString("2010-Jal-04")); 7353 assertThrown!DateTimeException(Date.fromISOString("2010-aul-04")); 7354 7355 assertThrown!DateTimeException(Date.fromISOString("2010-07-04")); 7356 assertThrown!DateTimeException(Date.fromISOString("2010-Jul-04")); 7357 7358 assert(Date.fromISOString("19990706") == Date(1999, 7, 6)); 7359 assert(Date.fromISOString("-19990706") == Date(-1999, 7, 6)); 7360 assert(Date.fromISOString("+019990706") == Date(1999, 7, 6)); 7361 assert(Date.fromISOString("19990706 ") == Date(1999, 7, 6)); 7362 assert(Date.fromISOString(" 19990706") == Date(1999, 7, 6)); 7363 assert(Date.fromISOString(" 19990706 ") == Date(1999, 7, 6)); 7364 } 7365 7366 // bug# 17801 7367 @safe unittest 7368 { 7369 import std.conv : to; 7370 import std.meta : AliasSeq; 7371 foreach (C; AliasSeq!(char, wchar, dchar)) 7372 { 7373 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7374 assert(Date.fromISOString(to!S("20121221")) == Date(2012, 12, 21)); 7375 } 7376 } 7377 7378 7379 /++ 7380 Creates a $(LREF Date) from a string with the format YYYY-MM-DD. 7381 Whitespace is stripped from the given string. 7382 7383 Params: 7384 isoExtString = A string formatted in the ISO Extended format for 7385 dates. 7386 7387 Throws: 7388 $(REF DateTimeException,std,datetime,date) if the given string is 7389 not in the ISO Extended format or if the resulting $(LREF Date) 7390 would not be valid. 7391 +/ 7392 static Date fromISOExtString(S)(in S isoExtString) @safe pure 7393 if (isSomeString!(S)) 7394 { 7395 import std.algorithm.searching : all, startsWith; 7396 import std.ascii : isDigit; 7397 import std.conv : to; 7398 import std.exception : enforce; 7399 import std.format : format; 7400 import std.string : strip; 7401 7402 auto dstr = to!dstring(strip(isoExtString)); 7403 7404 enforce(dstr.length >= 10, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7405 7406 auto day = dstr[$-2 .. $]; 7407 auto month = dstr[$-5 .. $-3]; 7408 auto year = dstr[0 .. $-6]; 7409 7410 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7411 enforce(dstr[$-6] == '-', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7412 enforce(all!isDigit(day), 7413 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7414 enforce(all!isDigit(month), 7415 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7416 7417 if (year.length > 4) 7418 { 7419 enforce(year.startsWith('-', '+'), 7420 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7421 enforce(all!isDigit(year[1..$]), 7422 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7423 } 7424 else 7425 enforce(all!isDigit(year), 7426 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 7427 7428 return Date(to!short(year), to!ubyte(month), to!ubyte(day)); 7429 } 7430 7431 /// 7432 @safe unittest 7433 { 7434 assert(Date.fromISOExtString("2010-07-04") == Date(2010, 7, 4)); 7435 assert(Date.fromISOExtString("1998-12-25") == Date(1998, 12, 25)); 7436 assert(Date.fromISOExtString("0000-01-05") == Date(0, 1, 5)); 7437 assert(Date.fromISOExtString("-0004-01-05") == Date(-4, 1, 5)); 7438 assert(Date.fromISOExtString(" 2010-07-04 ") == Date(2010, 7, 4)); 7439 } 7440 7441 @safe unittest 7442 { 7443 assertThrown!DateTimeException(Date.fromISOExtString("")); 7444 assertThrown!DateTimeException(Date.fromISOExtString("990704")); 7445 assertThrown!DateTimeException(Date.fromISOExtString("0100704")); 7446 assertThrown!DateTimeException(Date.fromISOExtString("2010070")); 7447 assertThrown!DateTimeException(Date.fromISOExtString("2010070 ")); 7448 assertThrown!DateTimeException(Date.fromISOExtString("120100704")); 7449 assertThrown!DateTimeException(Date.fromISOExtString("-0100704")); 7450 assertThrown!DateTimeException(Date.fromISOExtString("+0100704")); 7451 assertThrown!DateTimeException(Date.fromISOExtString("2010070a")); 7452 assertThrown!DateTimeException(Date.fromISOExtString("20100a04")); 7453 assertThrown!DateTimeException(Date.fromISOExtString("2010a704")); 7454 7455 assertThrown!DateTimeException(Date.fromISOExtString("99-07-04")); 7456 assertThrown!DateTimeException(Date.fromISOExtString("010-07-04")); 7457 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0")); 7458 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0 ")); 7459 assertThrown!DateTimeException(Date.fromISOExtString("12010-07-04")); 7460 assertThrown!DateTimeException(Date.fromISOExtString("-010-07-04")); 7461 assertThrown!DateTimeException(Date.fromISOExtString("+010-07-04")); 7462 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-0a")); 7463 assertThrown!DateTimeException(Date.fromISOExtString("2010-0a-04")); 7464 assertThrown!DateTimeException(Date.fromISOExtString("2010-a7-04")); 7465 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/04")); 7466 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/04")); 7467 assertThrown!DateTimeException(Date.fromISOExtString("2010/7/4")); 7468 assertThrown!DateTimeException(Date.fromISOExtString("2010/07/4")); 7469 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-04")); 7470 assertThrown!DateTimeException(Date.fromISOExtString("2010-7-4")); 7471 assertThrown!DateTimeException(Date.fromISOExtString("2010-07-4")); 7472 7473 assertThrown!DateTimeException(Date.fromISOExtString("99Jul04")); 7474 assertThrown!DateTimeException(Date.fromISOExtString("010Jul04")); 7475 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0")); 7476 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0 ")); 7477 assertThrown!DateTimeException(Date.fromISOExtString("12010Jul04")); 7478 assertThrown!DateTimeException(Date.fromISOExtString("-010Jul04")); 7479 assertThrown!DateTimeException(Date.fromISOExtString("+010Jul04")); 7480 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0a")); 7481 assertThrown!DateTimeException(Date.fromISOExtString("2010Jua04")); 7482 assertThrown!DateTimeException(Date.fromISOExtString("2010aul04")); 7483 7484 assertThrown!DateTimeException(Date.fromISOExtString("99-Jul-04")); 7485 assertThrown!DateTimeException(Date.fromISOExtString("010-Jul-04")); 7486 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0")); 7487 assertThrown!DateTimeException(Date.fromISOExtString("2010Jul0 ")); 7488 assertThrown!DateTimeException(Date.fromISOExtString("12010-Jul-04")); 7489 assertThrown!DateTimeException(Date.fromISOExtString("-010-Jul-04")); 7490 assertThrown!DateTimeException(Date.fromISOExtString("+010-Jul-04")); 7491 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-0a")); 7492 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jua-04")); 7493 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jal-04")); 7494 assertThrown!DateTimeException(Date.fromISOExtString("2010-aul-04")); 7495 7496 assertThrown!DateTimeException(Date.fromISOExtString("20100704")); 7497 assertThrown!DateTimeException(Date.fromISOExtString("2010-Jul-04")); 7498 7499 assert(Date.fromISOExtString("1999-07-06") == Date(1999, 7, 6)); 7500 assert(Date.fromISOExtString("-1999-07-06") == Date(-1999, 7, 6)); 7501 assert(Date.fromISOExtString("+01999-07-06") == Date(1999, 7, 6)); 7502 assert(Date.fromISOExtString("1999-07-06 ") == Date(1999, 7, 6)); 7503 assert(Date.fromISOExtString(" 1999-07-06") == Date(1999, 7, 6)); 7504 assert(Date.fromISOExtString(" 1999-07-06 ") == Date(1999, 7, 6)); 7505 } 7506 7507 // bug# 17801 7508 @safe unittest 7509 { 7510 import std.conv : to; 7511 import std.meta : AliasSeq; 7512 foreach (C; AliasSeq!(char, wchar, dchar)) 7513 { 7514 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7515 assert(Date.fromISOExtString(to!S("2012-12-21")) == Date(2012, 12, 21)); 7516 } 7517 } 7518 7519 7520 /++ 7521 Creates a $(LREF Date) from a string with the format YYYY-Mon-DD. 7522 Whitespace is stripped from the given string. 7523 7524 Params: 7525 simpleString = A string formatted in the way that toSimpleString 7526 formats dates. 7527 7528 Throws: 7529 $(REF DateTimeException,std,datetime,date) if the given string is 7530 not in the correct format or if the resulting $(LREF Date) would not 7531 be valid. 7532 +/ 7533 static Date fromSimpleString(S)(in S simpleString) @safe pure 7534 if (isSomeString!(S)) 7535 { 7536 import std.algorithm.searching : all, startsWith; 7537 import std.ascii : isDigit; 7538 import std.conv : to; 7539 import std.exception : enforce; 7540 import std.format : format; 7541 import std.string : strip; 7542 7543 auto dstr = to!dstring(strip(simpleString)); 7544 7545 enforce(dstr.length >= 11, new DateTimeException(format("Invalid string format: %s", simpleString))); 7546 7547 auto day = dstr[$-2 .. $]; 7548 auto month = monthFromString(to!string(dstr[$-6 .. $-3])); 7549 auto year = dstr[0 .. $-7]; 7550 7551 enforce(dstr[$-3] == '-', new DateTimeException(format("Invalid string format: %s", simpleString))); 7552 enforce(dstr[$-7] == '-', new DateTimeException(format("Invalid string format: %s", simpleString))); 7553 enforce(all!isDigit(day), new DateTimeException(format("Invalid string format: %s", simpleString))); 7554 7555 if (year.length > 4) 7556 { 7557 enforce(year.startsWith('-', '+'), 7558 new DateTimeException(format("Invalid string format: %s", simpleString))); 7559 enforce(all!isDigit(year[1..$]), 7560 new DateTimeException(format("Invalid string format: %s", simpleString))); 7561 } 7562 else 7563 enforce(all!isDigit(year), 7564 new DateTimeException(format("Invalid string format: %s", simpleString))); 7565 7566 return Date(to!short(year), month, to!ubyte(day)); 7567 } 7568 7569 /// 7570 @safe unittest 7571 { 7572 assert(Date.fromSimpleString("2010-Jul-04") == Date(2010, 7, 4)); 7573 assert(Date.fromSimpleString("1998-Dec-25") == Date(1998, 12, 25)); 7574 assert(Date.fromSimpleString("0000-Jan-05") == Date(0, 1, 5)); 7575 assert(Date.fromSimpleString("-0004-Jan-05") == Date(-4, 1, 5)); 7576 assert(Date.fromSimpleString(" 2010-Jul-04 ") == Date(2010, 7, 4)); 7577 } 7578 7579 @safe unittest 7580 { 7581 assertThrown!DateTimeException(Date.fromSimpleString("")); 7582 assertThrown!DateTimeException(Date.fromSimpleString("990704")); 7583 assertThrown!DateTimeException(Date.fromSimpleString("0100704")); 7584 assertThrown!DateTimeException(Date.fromSimpleString("2010070")); 7585 assertThrown!DateTimeException(Date.fromSimpleString("2010070 ")); 7586 assertThrown!DateTimeException(Date.fromSimpleString("120100704")); 7587 assertThrown!DateTimeException(Date.fromSimpleString("-0100704")); 7588 assertThrown!DateTimeException(Date.fromSimpleString("+0100704")); 7589 assertThrown!DateTimeException(Date.fromSimpleString("2010070a")); 7590 assertThrown!DateTimeException(Date.fromSimpleString("20100a04")); 7591 assertThrown!DateTimeException(Date.fromSimpleString("2010a704")); 7592 7593 assertThrown!DateTimeException(Date.fromSimpleString("99-07-04")); 7594 assertThrown!DateTimeException(Date.fromSimpleString("010-07-04")); 7595 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0")); 7596 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0 ")); 7597 assertThrown!DateTimeException(Date.fromSimpleString("12010-07-04")); 7598 assertThrown!DateTimeException(Date.fromSimpleString("-010-07-04")); 7599 assertThrown!DateTimeException(Date.fromSimpleString("+010-07-04")); 7600 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-0a")); 7601 assertThrown!DateTimeException(Date.fromSimpleString("2010-0a-04")); 7602 assertThrown!DateTimeException(Date.fromSimpleString("2010-a7-04")); 7603 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/04")); 7604 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/04")); 7605 assertThrown!DateTimeException(Date.fromSimpleString("2010/7/4")); 7606 assertThrown!DateTimeException(Date.fromSimpleString("2010/07/4")); 7607 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-04")); 7608 assertThrown!DateTimeException(Date.fromSimpleString("2010-7-4")); 7609 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-4")); 7610 7611 assertThrown!DateTimeException(Date.fromSimpleString("99Jul04")); 7612 assertThrown!DateTimeException(Date.fromSimpleString("010Jul04")); 7613 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0")); 7614 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0 ")); 7615 assertThrown!DateTimeException(Date.fromSimpleString("12010Jul04")); 7616 assertThrown!DateTimeException(Date.fromSimpleString("-010Jul04")); 7617 assertThrown!DateTimeException(Date.fromSimpleString("+010Jul04")); 7618 assertThrown!DateTimeException(Date.fromSimpleString("2010Jul0a")); 7619 assertThrown!DateTimeException(Date.fromSimpleString("2010Jua04")); 7620 assertThrown!DateTimeException(Date.fromSimpleString("2010aul04")); 7621 7622 assertThrown!DateTimeException(Date.fromSimpleString("99-Jul-04")); 7623 assertThrown!DateTimeException(Date.fromSimpleString("010-Jul-04")); 7624 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0")); 7625 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0 ")); 7626 assertThrown!DateTimeException(Date.fromSimpleString("12010-Jul-04")); 7627 assertThrown!DateTimeException(Date.fromSimpleString("-010-Jul-04")); 7628 assertThrown!DateTimeException(Date.fromSimpleString("+010-Jul-04")); 7629 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jul-0a")); 7630 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jua-04")); 7631 assertThrown!DateTimeException(Date.fromSimpleString("2010-Jal-04")); 7632 assertThrown!DateTimeException(Date.fromSimpleString("2010-aul-04")); 7633 7634 assertThrown!DateTimeException(Date.fromSimpleString("20100704")); 7635 assertThrown!DateTimeException(Date.fromSimpleString("2010-07-04")); 7636 7637 assert(Date.fromSimpleString("1999-Jul-06") == Date(1999, 7, 6)); 7638 assert(Date.fromSimpleString("-1999-Jul-06") == Date(-1999, 7, 6)); 7639 assert(Date.fromSimpleString("+01999-Jul-06") == Date(1999, 7, 6)); 7640 assert(Date.fromSimpleString("1999-Jul-06 ") == Date(1999, 7, 6)); 7641 assert(Date.fromSimpleString(" 1999-Jul-06") == Date(1999, 7, 6)); 7642 assert(Date.fromSimpleString(" 1999-Jul-06 ") == Date(1999, 7, 6)); 7643 } 7644 7645 // bug# 17801 7646 @safe unittest 7647 { 7648 import std.conv : to; 7649 import std.meta : AliasSeq; 7650 foreach (C; AliasSeq!(char, wchar, dchar)) 7651 { 7652 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 7653 assert(Date.fromSimpleString(to!S("2012-Dec-21")) == Date(2012, 12, 21)); 7654 } 7655 } 7656 7657 7658 /++ 7659 Returns the $(LREF Date) farthest in the past which is representable by 7660 $(LREF Date). 7661 +/ 7662 @property static Date min() @safe pure nothrow @nogc 7663 { 7664 auto date = Date.init; 7665 date._year = short.min; 7666 date._month = Month.jan; 7667 date._day = 1; 7668 7669 return date; 7670 } 7671 7672 @safe unittest 7673 { 7674 assert(Date.min.year < 0); 7675 assert(Date.min < Date.max); 7676 } 7677 7678 7679 /++ 7680 Returns the $(LREF Date) farthest in the future which is representable 7681 by $(LREF Date). 7682 +/ 7683 @property static Date max() @safe pure nothrow @nogc 7684 { 7685 auto date = Date.init; 7686 date._year = short.max; 7687 date._month = Month.dec; 7688 date._day = 31; 7689 7690 return date; 7691 } 7692 7693 @safe unittest 7694 { 7695 assert(Date.max.year > 0); 7696 assert(Date.max > Date.min); 7697 } 7698 7699 7700 private: 7701 7702 /+ 7703 Whether the given values form a valid date. 7704 7705 Params: 7706 year = The year to test. 7707 month = The month of the Gregorian Calendar to test. 7708 day = The day of the month to test. 7709 +/ 7710 static bool _valid(int year, int month, int day) @safe pure nothrow @nogc 7711 { 7712 if (!valid!"months"(month)) 7713 return false; 7714 return valid!"days"(year, month, day); 7715 } 7716 7717 7718 package: 7719 7720 /+ 7721 Adds the given number of days to this $(LREF Date). A negative number 7722 will subtract. 7723 7724 The month will be adjusted along with the day if the number of days 7725 added (or subtracted) would overflow (or underflow) the current month. 7726 The year will be adjusted along with the month if the increase (or 7727 decrease) to the month would cause it to overflow (or underflow) the 7728 current year. 7729 7730 $(D _addDays(numDays)) is effectively equivalent to 7731 $(D date.dayOfGregorianCal = date.dayOfGregorianCal + days). 7732 7733 Params: 7734 days = The number of days to add to this Date. 7735 +/ 7736 ref Date _addDays(long days) return @safe pure nothrow @nogc 7737 { 7738 dayOfGregorianCal = cast(int)(dayOfGregorianCal + days); 7739 return this; 7740 } 7741 7742 @safe unittest 7743 { 7744 // Test A.D. 7745 { 7746 auto date = Date(1999, 2, 28); 7747 date._addDays(1); 7748 assert(date == Date(1999, 3, 1)); 7749 date._addDays(-1); 7750 assert(date == Date(1999, 2, 28)); 7751 } 7752 7753 { 7754 auto date = Date(2000, 2, 28); 7755 date._addDays(1); 7756 assert(date == Date(2000, 2, 29)); 7757 date._addDays(1); 7758 assert(date == Date(2000, 3, 1)); 7759 date._addDays(-1); 7760 assert(date == Date(2000, 2, 29)); 7761 } 7762 7763 { 7764 auto date = Date(1999, 6, 30); 7765 date._addDays(1); 7766 assert(date == Date(1999, 7, 1)); 7767 date._addDays(-1); 7768 assert(date == Date(1999, 6, 30)); 7769 } 7770 7771 { 7772 auto date = Date(1999, 7, 31); 7773 date._addDays(1); 7774 assert(date == Date(1999, 8, 1)); 7775 date._addDays(-1); 7776 assert(date == Date(1999, 7, 31)); 7777 } 7778 7779 { 7780 auto date = Date(1999, 1, 1); 7781 date._addDays(-1); 7782 assert(date == Date(1998, 12, 31)); 7783 date._addDays(1); 7784 assert(date == Date(1999, 1, 1)); 7785 } 7786 7787 { 7788 auto date = Date(1999, 7, 6); 7789 date._addDays(9); 7790 assert(date == Date(1999, 7, 15)); 7791 date._addDays(-11); 7792 assert(date == Date(1999, 7, 4)); 7793 date._addDays(30); 7794 assert(date == Date(1999, 8, 3)); 7795 date._addDays(-3); 7796 assert(date == Date(1999, 7, 31)); 7797 } 7798 7799 { 7800 auto date = Date(1999, 7, 6); 7801 date._addDays(365); 7802 assert(date == Date(2000, 7, 5)); 7803 date._addDays(-365); 7804 assert(date == Date(1999, 7, 6)); 7805 date._addDays(366); 7806 assert(date == Date(2000, 7, 6)); 7807 date._addDays(730); 7808 assert(date == Date(2002, 7, 6)); 7809 date._addDays(-1096); 7810 assert(date == Date(1999, 7, 6)); 7811 } 7812 7813 // Test B.C. 7814 { 7815 auto date = Date(-1999, 2, 28); 7816 date._addDays(1); 7817 assert(date == Date(-1999, 3, 1)); 7818 date._addDays(-1); 7819 assert(date == Date(-1999, 2, 28)); 7820 } 7821 7822 { 7823 auto date = Date(-2000, 2, 28); 7824 date._addDays(1); 7825 assert(date == Date(-2000, 2, 29)); 7826 date._addDays(1); 7827 assert(date == Date(-2000, 3, 1)); 7828 date._addDays(-1); 7829 assert(date == Date(-2000, 2, 29)); 7830 } 7831 7832 { 7833 auto date = Date(-1999, 6, 30); 7834 date._addDays(1); 7835 assert(date == Date(-1999, 7, 1)); 7836 date._addDays(-1); 7837 assert(date == Date(-1999, 6, 30)); 7838 } 7839 7840 { 7841 auto date = Date(-1999, 7, 31); 7842 date._addDays(1); 7843 assert(date == Date(-1999, 8, 1)); 7844 date._addDays(-1); 7845 assert(date == Date(-1999, 7, 31)); 7846 } 7847 7848 { 7849 auto date = Date(-1999, 1, 1); 7850 date._addDays(-1); 7851 assert(date == Date(-2000, 12, 31)); 7852 date._addDays(1); 7853 assert(date == Date(-1999, 1, 1)); 7854 } 7855 7856 { 7857 auto date = Date(-1999, 7, 6); 7858 date._addDays(9); 7859 assert(date == Date(-1999, 7, 15)); 7860 date._addDays(-11); 7861 assert(date == Date(-1999, 7, 4)); 7862 date._addDays(30); 7863 assert(date == Date(-1999, 8, 3)); 7864 date._addDays(-3); 7865 } 7866 7867 { 7868 auto date = Date(-1999, 7, 6); 7869 date._addDays(365); 7870 assert(date == Date(-1998, 7, 6)); 7871 date._addDays(-365); 7872 assert(date == Date(-1999, 7, 6)); 7873 date._addDays(366); 7874 assert(date == Date(-1998, 7, 7)); 7875 date._addDays(730); 7876 assert(date == Date(-1996, 7, 6)); 7877 date._addDays(-1096); 7878 assert(date == Date(-1999, 7, 6)); 7879 } 7880 7881 // Test Both 7882 { 7883 auto date = Date(1, 7, 6); 7884 date._addDays(-365); 7885 assert(date == Date(0, 7, 6)); 7886 date._addDays(365); 7887 assert(date == Date(1, 7, 6)); 7888 date._addDays(-731); 7889 assert(date == Date(-1, 7, 6)); 7890 date._addDays(730); 7891 assert(date == Date(1, 7, 5)); 7892 } 7893 7894 const cdate = Date(1999, 7, 6); 7895 immutable idate = Date(1999, 7, 6); 7896 static assert(!__traits(compiles, cdate._addDays(12))); 7897 static assert(!__traits(compiles, idate._addDays(12))); 7898 } 7899 7900 7901 @safe pure invariant() 7902 { 7903 import std.format : format; 7904 assert(valid!"months"(_month), 7905 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 7906 assert(valid!"days"(_year, _month, _day), 7907 format("Invariant Failure: year [%s] month [%s] day [%s]", _year, _month, _day)); 7908 } 7909 7910 short _year = 1; 7911 Month _month = Month.jan; 7912 ubyte _day = 1; 7913 } 7914 7915 7916 /++ 7917 Represents a time of day with hours, minutes, and seconds. It uses 24 hour 7918 time. 7919 +/ 7920 struct TimeOfDay 7921 { 7922 public: 7923 7924 /++ 7925 Params: 7926 hour = Hour of the day [0 - 24$(RPAREN). 7927 minute = Minute of the hour [0 - 60$(RPAREN). 7928 second = Second of the minute [0 - 60$(RPAREN). 7929 7930 Throws: 7931 $(REF DateTimeException,std,datetime,date) if the resulting 7932 $(LREF TimeOfDay) would be not be valid. 7933 +/ 7934 this(int hour, int minute, int second = 0) @safe pure 7935 { 7936 enforceValid!"hours"(hour); 7937 enforceValid!"minutes"(minute); 7938 enforceValid!"seconds"(second); 7939 7940 _hour = cast(ubyte) hour; 7941 _minute = cast(ubyte) minute; 7942 _second = cast(ubyte) second; 7943 } 7944 7945 @safe unittest 7946 { 7947 assert(TimeOfDay(0, 0) == TimeOfDay.init); 7948 7949 { 7950 auto tod = TimeOfDay(0, 0); 7951 assert(tod._hour == 0); 7952 assert(tod._minute == 0); 7953 assert(tod._second == 0); 7954 } 7955 7956 { 7957 auto tod = TimeOfDay(12, 30, 33); 7958 assert(tod._hour == 12); 7959 assert(tod._minute == 30); 7960 assert(tod._second == 33); 7961 } 7962 7963 { 7964 auto tod = TimeOfDay(23, 59, 59); 7965 assert(tod._hour == 23); 7966 assert(tod._minute == 59); 7967 assert(tod._second == 59); 7968 } 7969 7970 assertThrown!DateTimeException(TimeOfDay(24, 0, 0)); 7971 assertThrown!DateTimeException(TimeOfDay(0, 60, 0)); 7972 assertThrown!DateTimeException(TimeOfDay(0, 0, 60)); 7973 } 7974 7975 7976 /++ 7977 Compares this $(LREF TimeOfDay) with the given $(LREF TimeOfDay). 7978 7979 Returns: 7980 $(BOOKTABLE, 7981 $(TR $(TD this < rhs) $(TD < 0)) 7982 $(TR $(TD this == rhs) $(TD 0)) 7983 $(TR $(TD this > rhs) $(TD > 0)) 7984 ) 7985 +/ 7986 int opCmp(in TimeOfDay rhs) const @safe pure nothrow @nogc 7987 { 7988 if (_hour < rhs._hour) 7989 return -1; 7990 if (_hour > rhs._hour) 7991 return 1; 7992 7993 if (_minute < rhs._minute) 7994 return -1; 7995 if (_minute > rhs._minute) 7996 return 1; 7997 7998 if (_second < rhs._second) 7999 return -1; 8000 if (_second > rhs._second) 8001 return 1; 8002 8003 return 0; 8004 } 8005 8006 @safe unittest 8007 { 8008 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay.init) == 0); 8009 8010 assert(TimeOfDay(0, 0, 0).opCmp(TimeOfDay(0, 0, 0)) == 0); 8011 assert(TimeOfDay(12, 0, 0).opCmp(TimeOfDay(12, 0, 0)) == 0); 8012 assert(TimeOfDay(0, 30, 0).opCmp(TimeOfDay(0, 30, 0)) == 0); 8013 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8014 8015 assert(TimeOfDay(12, 30, 0).opCmp(TimeOfDay(12, 30, 0)) == 0); 8016 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 33)) == 0); 8017 8018 assert(TimeOfDay(0, 30, 33).opCmp(TimeOfDay(0, 30, 33)) == 0); 8019 assert(TimeOfDay(0, 0, 33).opCmp(TimeOfDay(0, 0, 33)) == 0); 8020 8021 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8022 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8023 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 31, 33)) < 0); 8024 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 33)) > 0); 8025 assert(TimeOfDay(12, 30, 33).opCmp(TimeOfDay(12, 30, 34)) < 0); 8026 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 30, 33)) > 0); 8027 8028 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8029 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(13, 30, 33)) < 0); 8030 assert(TimeOfDay(13, 30, 33).opCmp(TimeOfDay(12, 31, 33)) > 0); 8031 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(13, 30, 33)) < 0); 8032 8033 assert(TimeOfDay(12, 31, 33).opCmp(TimeOfDay(12, 30, 34)) > 0); 8034 assert(TimeOfDay(12, 30, 34).opCmp(TimeOfDay(12, 31, 33)) < 0); 8035 8036 const ctod = TimeOfDay(12, 30, 33); 8037 immutable itod = TimeOfDay(12, 30, 33); 8038 assert(ctod.opCmp(itod) == 0); 8039 assert(itod.opCmp(ctod) == 0); 8040 } 8041 8042 8043 /++ 8044 Hours past midnight. 8045 +/ 8046 @property ubyte hour() const @safe pure nothrow @nogc 8047 { 8048 return _hour; 8049 } 8050 8051 @safe unittest 8052 { 8053 assert(TimeOfDay.init.hour == 0); 8054 assert(TimeOfDay(12, 0, 0).hour == 12); 8055 8056 const ctod = TimeOfDay(12, 0, 0); 8057 immutable itod = TimeOfDay(12, 0, 0); 8058 assert(ctod.hour == 12); 8059 assert(itod.hour == 12); 8060 } 8061 8062 8063 /++ 8064 Hours past midnight. 8065 8066 Params: 8067 hour = The hour of the day to set this $(LREF TimeOfDay)'s hour to. 8068 8069 Throws: 8070 $(REF DateTimeException,std,datetime,date) if the given hour would 8071 result in an invalid $(LREF TimeOfDay). 8072 +/ 8073 @property void hour(int hour) @safe pure 8074 { 8075 enforceValid!"hours"(hour); 8076 _hour = cast(ubyte) hour; 8077 } 8078 8079 @safe unittest 8080 { 8081 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).hour = 24;}()); 8082 8083 auto tod = TimeOfDay(0, 0, 0); 8084 tod.hour = 12; 8085 assert(tod == TimeOfDay(12, 0, 0)); 8086 8087 const ctod = TimeOfDay(0, 0, 0); 8088 immutable itod = TimeOfDay(0, 0, 0); 8089 static assert(!__traits(compiles, ctod.hour = 12)); 8090 static assert(!__traits(compiles, itod.hour = 12)); 8091 } 8092 8093 8094 /++ 8095 Minutes past the hour. 8096 +/ 8097 @property ubyte minute() const @safe pure nothrow @nogc 8098 { 8099 return _minute; 8100 } 8101 8102 @safe unittest 8103 { 8104 assert(TimeOfDay.init.minute == 0); 8105 assert(TimeOfDay(0, 30, 0).minute == 30); 8106 8107 const ctod = TimeOfDay(0, 30, 0); 8108 immutable itod = TimeOfDay(0, 30, 0); 8109 assert(ctod.minute == 30); 8110 assert(itod.minute == 30); 8111 } 8112 8113 8114 /++ 8115 Minutes past the hour. 8116 8117 Params: 8118 minute = The minute to set this $(LREF TimeOfDay)'s minute to. 8119 8120 Throws: 8121 $(REF DateTimeException,std,datetime,date) if the given minute 8122 would result in an invalid $(LREF TimeOfDay). 8123 +/ 8124 @property void minute(int minute) @safe pure 8125 { 8126 enforceValid!"minutes"(minute); 8127 _minute = cast(ubyte) minute; 8128 } 8129 8130 @safe unittest 8131 { 8132 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).minute = 60;}()); 8133 8134 auto tod = TimeOfDay(0, 0, 0); 8135 tod.minute = 30; 8136 assert(tod == TimeOfDay(0, 30, 0)); 8137 8138 const ctod = TimeOfDay(0, 0, 0); 8139 immutable itod = TimeOfDay(0, 0, 0); 8140 static assert(!__traits(compiles, ctod.minute = 30)); 8141 static assert(!__traits(compiles, itod.minute = 30)); 8142 } 8143 8144 8145 /++ 8146 Seconds past the minute. 8147 +/ 8148 @property ubyte second() const @safe pure nothrow @nogc 8149 { 8150 return _second; 8151 } 8152 8153 @safe unittest 8154 { 8155 assert(TimeOfDay.init.second == 0); 8156 assert(TimeOfDay(0, 0, 33).second == 33); 8157 8158 const ctod = TimeOfDay(0, 0, 33); 8159 immutable itod = TimeOfDay(0, 0, 33); 8160 assert(ctod.second == 33); 8161 assert(itod.second == 33); 8162 } 8163 8164 8165 /++ 8166 Seconds past the minute. 8167 8168 Params: 8169 second = The second to set this $(LREF TimeOfDay)'s second to. 8170 8171 Throws: 8172 $(REF DateTimeException,std,datetime,date) if the given second 8173 would result in an invalid $(LREF TimeOfDay). 8174 +/ 8175 @property void second(int second) @safe pure 8176 { 8177 enforceValid!"seconds"(second); 8178 _second = cast(ubyte) second; 8179 } 8180 8181 @safe unittest 8182 { 8183 assertThrown!DateTimeException((){TimeOfDay(0, 0, 0).second = 60;}()); 8184 8185 auto tod = TimeOfDay(0, 0, 0); 8186 tod.second = 33; 8187 assert(tod == TimeOfDay(0, 0, 33)); 8188 8189 const ctod = TimeOfDay(0, 0, 0); 8190 immutable itod = TimeOfDay(0, 0, 0); 8191 static assert(!__traits(compiles, ctod.second = 33)); 8192 static assert(!__traits(compiles, itod.second = 33)); 8193 } 8194 8195 8196 /++ 8197 Adds the given number of units to this $(LREF TimeOfDay). A negative 8198 number will subtract. 8199 8200 The difference between rolling and adding is that rolling does not 8201 affect larger units. For instance, rolling a $(LREF TimeOfDay) 8202 one hours's worth of minutes gets the exact same 8203 $(LREF TimeOfDay). 8204 8205 Accepted units are $(D "hours"), $(D "minutes"), and $(D "seconds"). 8206 8207 Params: 8208 units = The units to add. 8209 value = The number of $(D_PARAM units) to add to this 8210 $(LREF TimeOfDay). 8211 +/ 8212 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8213 if (units == "hours") 8214 { 8215 return this += dur!"hours"(value); 8216 } 8217 8218 /// 8219 @safe unittest 8220 { 8221 auto tod1 = TimeOfDay(7, 12, 0); 8222 tod1.roll!"hours"(1); 8223 assert(tod1 == TimeOfDay(8, 12, 0)); 8224 8225 auto tod2 = TimeOfDay(7, 12, 0); 8226 tod2.roll!"hours"(-1); 8227 assert(tod2 == TimeOfDay(6, 12, 0)); 8228 8229 auto tod3 = TimeOfDay(23, 59, 0); 8230 tod3.roll!"minutes"(1); 8231 assert(tod3 == TimeOfDay(23, 0, 0)); 8232 8233 auto tod4 = TimeOfDay(0, 0, 0); 8234 tod4.roll!"minutes"(-1); 8235 assert(tod4 == TimeOfDay(0, 59, 0)); 8236 8237 auto tod5 = TimeOfDay(23, 59, 59); 8238 tod5.roll!"seconds"(1); 8239 assert(tod5 == TimeOfDay(23, 59, 0)); 8240 8241 auto tod6 = TimeOfDay(0, 0, 0); 8242 tod6.roll!"seconds"(-1); 8243 assert(tod6 == TimeOfDay(0, 0, 59)); 8244 } 8245 8246 @safe unittest 8247 { 8248 auto tod = TimeOfDay(12, 27, 2); 8249 tod.roll!"hours"(22).roll!"hours"(-7); 8250 assert(tod == TimeOfDay(3, 27, 2)); 8251 8252 const ctod = TimeOfDay(0, 0, 0); 8253 immutable itod = TimeOfDay(0, 0, 0); 8254 static assert(!__traits(compiles, ctod.roll!"hours"(53))); 8255 static assert(!__traits(compiles, itod.roll!"hours"(53))); 8256 } 8257 8258 8259 // Shares documentation with "hours" version. 8260 ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc 8261 if (units == "minutes" || units == "seconds") 8262 { 8263 import std.format : format; 8264 8265 enum memberVarStr = units[0 .. $ - 1]; 8266 value %= 60; 8267 mixin(format("auto newVal = cast(ubyte)(_%s) + value;", memberVarStr)); 8268 8269 if (value < 0) 8270 { 8271 if (newVal < 0) 8272 newVal += 60; 8273 } 8274 else if (newVal >= 60) 8275 newVal -= 60; 8276 8277 mixin(format("_%s = cast(ubyte) newVal;", memberVarStr)); 8278 return this; 8279 } 8280 8281 // Test roll!"minutes"(). 8282 @safe unittest 8283 { 8284 static void testTOD(TimeOfDay orig, int minutes, in TimeOfDay expected, size_t line = __LINE__) 8285 { 8286 orig.roll!"minutes"(minutes); 8287 assert(orig == expected); 8288 } 8289 8290 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8291 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 31, 33)); 8292 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 32, 33)); 8293 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 33, 33)); 8294 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 34, 33)); 8295 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 35, 33)); 8296 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 40, 33)); 8297 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 45, 33)); 8298 testTOD(TimeOfDay(12, 30, 33), 29, TimeOfDay(12, 59, 33)); 8299 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 0, 33)); 8300 testTOD(TimeOfDay(12, 30, 33), 45, TimeOfDay(12, 15, 33)); 8301 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8302 testTOD(TimeOfDay(12, 30, 33), 75, TimeOfDay(12, 45, 33)); 8303 testTOD(TimeOfDay(12, 30, 33), 90, TimeOfDay(12, 0, 33)); 8304 testTOD(TimeOfDay(12, 30, 33), 100, TimeOfDay(12, 10, 33)); 8305 8306 testTOD(TimeOfDay(12, 30, 33), 689, TimeOfDay(12, 59, 33)); 8307 testTOD(TimeOfDay(12, 30, 33), 690, TimeOfDay(12, 0, 33)); 8308 testTOD(TimeOfDay(12, 30, 33), 691, TimeOfDay(12, 1, 33)); 8309 testTOD(TimeOfDay(12, 30, 33), 960, TimeOfDay(12, 30, 33)); 8310 testTOD(TimeOfDay(12, 30, 33), 1439, TimeOfDay(12, 29, 33)); 8311 testTOD(TimeOfDay(12, 30, 33), 1440, TimeOfDay(12, 30, 33)); 8312 testTOD(TimeOfDay(12, 30, 33), 1441, TimeOfDay(12, 31, 33)); 8313 testTOD(TimeOfDay(12, 30, 33), 2880, TimeOfDay(12, 30, 33)); 8314 8315 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 29, 33)); 8316 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 28, 33)); 8317 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 27, 33)); 8318 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 26, 33)); 8319 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 25, 33)); 8320 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 20, 33)); 8321 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 15, 33)); 8322 testTOD(TimeOfDay(12, 30, 33), -29, TimeOfDay(12, 1, 33)); 8323 testTOD(TimeOfDay(12, 30, 33), -30, TimeOfDay(12, 0, 33)); 8324 testTOD(TimeOfDay(12, 30, 33), -45, TimeOfDay(12, 45, 33)); 8325 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8326 testTOD(TimeOfDay(12, 30, 33), -75, TimeOfDay(12, 15, 33)); 8327 testTOD(TimeOfDay(12, 30, 33), -90, TimeOfDay(12, 0, 33)); 8328 testTOD(TimeOfDay(12, 30, 33), -100, TimeOfDay(12, 50, 33)); 8329 8330 testTOD(TimeOfDay(12, 30, 33), -749, TimeOfDay(12, 1, 33)); 8331 testTOD(TimeOfDay(12, 30, 33), -750, TimeOfDay(12, 0, 33)); 8332 testTOD(TimeOfDay(12, 30, 33), -751, TimeOfDay(12, 59, 33)); 8333 testTOD(TimeOfDay(12, 30, 33), -960, TimeOfDay(12, 30, 33)); 8334 testTOD(TimeOfDay(12, 30, 33), -1439, TimeOfDay(12, 31, 33)); 8335 testTOD(TimeOfDay(12, 30, 33), -1440, TimeOfDay(12, 30, 33)); 8336 testTOD(TimeOfDay(12, 30, 33), -1441, TimeOfDay(12, 29, 33)); 8337 testTOD(TimeOfDay(12, 30, 33), -2880, TimeOfDay(12, 30, 33)); 8338 8339 testTOD(TimeOfDay(12, 0, 33), 1, TimeOfDay(12, 1, 33)); 8340 testTOD(TimeOfDay(12, 0, 33), 0, TimeOfDay(12, 0, 33)); 8341 testTOD(TimeOfDay(12, 0, 33), -1, TimeOfDay(12, 59, 33)); 8342 8343 testTOD(TimeOfDay(11, 59, 33), 1, TimeOfDay(11, 0, 33)); 8344 testTOD(TimeOfDay(11, 59, 33), 0, TimeOfDay(11, 59, 33)); 8345 testTOD(TimeOfDay(11, 59, 33), -1, TimeOfDay(11, 58, 33)); 8346 8347 testTOD(TimeOfDay(0, 0, 33), 1, TimeOfDay(0, 1, 33)); 8348 testTOD(TimeOfDay(0, 0, 33), 0, TimeOfDay(0, 0, 33)); 8349 testTOD(TimeOfDay(0, 0, 33), -1, TimeOfDay(0, 59, 33)); 8350 8351 testTOD(TimeOfDay(23, 59, 33), 1, TimeOfDay(23, 0, 33)); 8352 testTOD(TimeOfDay(23, 59, 33), 0, TimeOfDay(23, 59, 33)); 8353 testTOD(TimeOfDay(23, 59, 33), -1, TimeOfDay(23, 58, 33)); 8354 8355 auto tod = TimeOfDay(12, 27, 2); 8356 tod.roll!"minutes"(97).roll!"minutes"(-102); 8357 assert(tod == TimeOfDay(12, 22, 2)); 8358 8359 const ctod = TimeOfDay(0, 0, 0); 8360 immutable itod = TimeOfDay(0, 0, 0); 8361 static assert(!__traits(compiles, ctod.roll!"minutes"(7))); 8362 static assert(!__traits(compiles, itod.roll!"minutes"(7))); 8363 } 8364 8365 // Test roll!"seconds"(). 8366 @safe unittest 8367 { 8368 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__) 8369 { 8370 orig.roll!"seconds"(seconds); 8371 assert(orig == expected); 8372 } 8373 8374 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 8375 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 8376 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 8377 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 8378 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 8379 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 8380 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 8381 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 8382 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 8383 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 30, 0)); 8384 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 30, 3)); 8385 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 30, 32)); 8386 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 30, 33)); 8387 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 30, 34)); 8388 8389 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 30, 59)); 8390 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(12, 30, 0)); 8391 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(12, 30, 1)); 8392 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(12, 30, 0)); 8393 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(12, 30, 32)); 8394 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(12, 30, 33)); 8395 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(12, 30, 34)); 8396 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(12, 30, 33)); 8397 8398 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 8399 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 8400 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 8401 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 8402 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 8403 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 8404 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 8405 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 8406 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 30, 59)); 8407 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 30, 58)); 8408 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 30, 34)); 8409 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 30, 33)); 8410 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 30, 32)); 8411 8412 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 8413 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 8414 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 30, 59)); 8415 8416 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 8417 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 8418 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(12, 0, 59)); 8419 8420 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 8421 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 8422 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(0, 0, 59)); 8423 8424 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(23, 59, 0)); 8425 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 8426 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 8427 8428 auto tod = TimeOfDay(12, 27, 2); 8429 tod.roll!"seconds"(105).roll!"seconds"(-77); 8430 assert(tod == TimeOfDay(12, 27, 30)); 8431 8432 const ctod = TimeOfDay(0, 0, 0); 8433 immutable itod = TimeOfDay(0, 0, 0); 8434 static assert(!__traits(compiles, ctod.roll!"seconds"(7))); 8435 static assert(!__traits(compiles, itod.roll!"seconds"(7))); 8436 } 8437 8438 8439 /++ 8440 Gives the result of adding or subtracting a $(REF Duration, core,time) 8441 from this $(LREF TimeOfDay). 8442 8443 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8444 are 8445 8446 $(BOOKTABLE, 8447 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8448 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8449 ) 8450 8451 Params: 8452 duration = The $(REF Duration, core,time) to add to or subtract from 8453 this $(LREF TimeOfDay). 8454 +/ 8455 TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc 8456 if (op == "+" || op == "-") 8457 { 8458 TimeOfDay retval = this; 8459 immutable seconds = duration.total!"seconds"; 8460 mixin("return retval._addSeconds(" ~ op ~ "seconds);"); 8461 } 8462 8463 /// 8464 @safe unittest 8465 { 8466 import core.time : hours, minutes, seconds; 8467 8468 assert(TimeOfDay(12, 12, 12) + seconds(1) == TimeOfDay(12, 12, 13)); 8469 assert(TimeOfDay(12, 12, 12) + minutes(1) == TimeOfDay(12, 13, 12)); 8470 assert(TimeOfDay(12, 12, 12) + hours(1) == TimeOfDay(13, 12, 12)); 8471 assert(TimeOfDay(23, 59, 59) + seconds(1) == TimeOfDay(0, 0, 0)); 8472 8473 assert(TimeOfDay(12, 12, 12) - seconds(1) == TimeOfDay(12, 12, 11)); 8474 assert(TimeOfDay(12, 12, 12) - minutes(1) == TimeOfDay(12, 11, 12)); 8475 assert(TimeOfDay(12, 12, 12) - hours(1) == TimeOfDay(11, 12, 12)); 8476 assert(TimeOfDay(0, 0, 0) - seconds(1) == TimeOfDay(23, 59, 59)); 8477 } 8478 8479 @safe unittest 8480 { 8481 auto tod = TimeOfDay(12, 30, 33); 8482 8483 assert(tod + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8484 assert(tod + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8485 assert(tod + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8486 assert(tod + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8487 assert(tod + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8488 assert(tod + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8489 8490 assert(tod + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8491 assert(tod + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8492 assert(tod + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8493 assert(tod + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8494 assert(tod + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8495 assert(tod + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8496 8497 assert(tod - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 8498 assert(tod - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 8499 assert(tod - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 8500 assert(tod - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 8501 assert(tod - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 8502 assert(tod - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 8503 8504 assert(tod - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 8505 assert(tod - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 8506 assert(tod - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 8507 assert(tod - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 8508 assert(tod - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 8509 assert(tod - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 8510 8511 auto duration = dur!"hours"(11); 8512 const ctod = TimeOfDay(12, 30, 33); 8513 immutable itod = TimeOfDay(12, 30, 33); 8514 assert(tod + duration == TimeOfDay(23, 30, 33)); 8515 assert(ctod + duration == TimeOfDay(23, 30, 33)); 8516 assert(itod + duration == TimeOfDay(23, 30, 33)); 8517 8518 assert(tod - duration == TimeOfDay(1, 30, 33)); 8519 assert(ctod - duration == TimeOfDay(1, 30, 33)); 8520 assert(itod - duration == TimeOfDay(1, 30, 33)); 8521 } 8522 8523 8524 /++ 8525 Gives the result of adding or subtracting a $(REF Duration, core,time) 8526 from this $(LREF TimeOfDay), as well as assigning the result to this 8527 $(LREF TimeOfDay). 8528 8529 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8530 are 8531 8532 $(BOOKTABLE, 8533 $(TR $(TD TimeOfDay) $(TD +) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8534 $(TR $(TD TimeOfDay) $(TD -) $(TD Duration) $(TD -->) $(TD TimeOfDay)) 8535 ) 8536 8537 Params: 8538 duration = The $(REF Duration, core,time) to add to or subtract from 8539 this $(LREF TimeOfDay). 8540 +/ 8541 ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc 8542 if (op == "+" || op == "-") 8543 { 8544 immutable seconds = duration.total!"seconds"; 8545 mixin("return _addSeconds(" ~ op ~ "seconds);"); 8546 } 8547 8548 @safe unittest 8549 { 8550 auto duration = dur!"hours"(12); 8551 8552 assert(TimeOfDay(12, 30, 33) + dur!"hours"(7) == TimeOfDay(19, 30, 33)); 8553 assert(TimeOfDay(12, 30, 33) + dur!"hours"(-7) == TimeOfDay(5, 30, 33)); 8554 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(7) == TimeOfDay(12, 37, 33)); 8555 assert(TimeOfDay(12, 30, 33) + dur!"minutes"(-7) == TimeOfDay(12, 23, 33)); 8556 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(7) == TimeOfDay(12, 30, 40)); 8557 assert(TimeOfDay(12, 30, 33) + dur!"seconds"(-7) == TimeOfDay(12, 30, 26)); 8558 8559 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(7000) == TimeOfDay(12, 30, 40)); 8560 assert(TimeOfDay(12, 30, 33) + dur!"msecs"(-7000) == TimeOfDay(12, 30, 26)); 8561 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 40)); 8562 assert(TimeOfDay(12, 30, 33) + dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 26)); 8563 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 40)); 8564 assert(TimeOfDay(12, 30, 33) + dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 26)); 8565 8566 assert(TimeOfDay(12, 30, 33) - dur!"hours"(-7) == TimeOfDay(19, 30, 33)); 8567 assert(TimeOfDay(12, 30, 33) - dur!"hours"(7) == TimeOfDay(5, 30, 33)); 8568 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(-7) == TimeOfDay(12, 37, 33)); 8569 assert(TimeOfDay(12, 30, 33) - dur!"minutes"(7) == TimeOfDay(12, 23, 33)); 8570 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(-7) == TimeOfDay(12, 30, 40)); 8571 assert(TimeOfDay(12, 30, 33) - dur!"seconds"(7) == TimeOfDay(12, 30, 26)); 8572 8573 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(-7000) == TimeOfDay(12, 30, 40)); 8574 assert(TimeOfDay(12, 30, 33) - dur!"msecs"(7000) == TimeOfDay(12, 30, 26)); 8575 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(-7_000_000) == TimeOfDay(12, 30, 40)); 8576 assert(TimeOfDay(12, 30, 33) - dur!"usecs"(7_000_000) == TimeOfDay(12, 30, 26)); 8577 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(-70_000_000) == TimeOfDay(12, 30, 40)); 8578 assert(TimeOfDay(12, 30, 33) - dur!"hnsecs"(70_000_000) == TimeOfDay(12, 30, 26)); 8579 8580 auto tod = TimeOfDay(19, 17, 22); 8581 (tod += dur!"seconds"(9)) += dur!"seconds"(-7292); 8582 assert(tod == TimeOfDay(17, 15, 59)); 8583 8584 const ctod = TimeOfDay(12, 33, 30); 8585 immutable itod = TimeOfDay(12, 33, 30); 8586 static assert(!__traits(compiles, ctod += duration)); 8587 static assert(!__traits(compiles, itod += duration)); 8588 static assert(!__traits(compiles, ctod -= duration)); 8589 static assert(!__traits(compiles, itod -= duration)); 8590 } 8591 8592 8593 /++ 8594 Gives the difference between two $(LREF TimeOfDay)s. 8595 8596 The legal types of arithmetic for $(LREF TimeOfDay) using this operator 8597 are 8598 8599 $(BOOKTABLE, 8600 $(TR $(TD TimeOfDay) $(TD -) $(TD TimeOfDay) $(TD -->) $(TD duration)) 8601 ) 8602 8603 Params: 8604 rhs = The $(LREF TimeOfDay) to subtract from this one. 8605 +/ 8606 Duration opBinary(string op)(in TimeOfDay rhs) const @safe pure nothrow @nogc 8607 if (op == "-") 8608 { 8609 immutable lhsSec = _hour * 3600 + _minute * 60 + _second; 8610 immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second; 8611 8612 return dur!"seconds"(lhsSec - rhsSec); 8613 } 8614 8615 @safe unittest 8616 { 8617 auto tod = TimeOfDay(12, 30, 33); 8618 8619 assert(TimeOfDay(7, 12, 52) - TimeOfDay(12, 30, 33) == dur!"seconds"(-19_061)); 8620 assert(TimeOfDay(12, 30, 33) - TimeOfDay(7, 12, 52) == dur!"seconds"(19_061)); 8621 assert(TimeOfDay(12, 30, 33) - TimeOfDay(14, 30, 33) == dur!"seconds"(-7200)); 8622 assert(TimeOfDay(14, 30, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(7200)); 8623 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 34, 33) == dur!"seconds"(-240)); 8624 assert(TimeOfDay(12, 34, 33) - TimeOfDay(12, 30, 33) == dur!"seconds"(240)); 8625 assert(TimeOfDay(12, 30, 33) - TimeOfDay(12, 30, 34) == dur!"seconds"(-1)); 8626 assert(TimeOfDay(12, 30, 34) - TimeOfDay(12, 30, 33) == dur!"seconds"(1)); 8627 8628 const ctod = TimeOfDay(12, 30, 33); 8629 immutable itod = TimeOfDay(12, 30, 33); 8630 assert(tod - tod == Duration.zero); 8631 assert(ctod - tod == Duration.zero); 8632 assert(itod - tod == Duration.zero); 8633 8634 assert(tod - ctod == Duration.zero); 8635 assert(ctod - ctod == Duration.zero); 8636 assert(itod - ctod == Duration.zero); 8637 8638 assert(tod - itod == Duration.zero); 8639 assert(ctod - itod == Duration.zero); 8640 assert(itod - itod == Duration.zero); 8641 } 8642 8643 8644 /++ 8645 Converts this $(LREF TimeOfDay) to a string with the format HHMMSS. 8646 +/ 8647 string toISOString() const @safe pure nothrow 8648 { 8649 import std.format : format; 8650 try 8651 return format("%02d%02d%02d", _hour, _minute, _second); 8652 catch (Exception e) 8653 assert(0, "format() threw."); 8654 } 8655 8656 /// 8657 @safe unittest 8658 { 8659 assert(TimeOfDay(0, 0, 0).toISOString() == "000000"); 8660 assert(TimeOfDay(12, 30, 33).toISOString() == "123033"); 8661 } 8662 8663 @safe unittest 8664 { 8665 auto tod = TimeOfDay(12, 30, 33); 8666 const ctod = TimeOfDay(12, 30, 33); 8667 immutable itod = TimeOfDay(12, 30, 33); 8668 assert(tod.toISOString() == "123033"); 8669 assert(ctod.toISOString() == "123033"); 8670 assert(itod.toISOString() == "123033"); 8671 } 8672 8673 8674 /++ 8675 Converts this $(LREF TimeOfDay) to a string with the format HH:MM:SS. 8676 +/ 8677 string toISOExtString() const @safe pure nothrow 8678 { 8679 import std.format : format; 8680 try 8681 return format("%02d:%02d:%02d", _hour, _minute, _second); 8682 catch (Exception e) 8683 assert(0, "format() threw."); 8684 } 8685 8686 /// 8687 @safe unittest 8688 { 8689 assert(TimeOfDay(0, 0, 0).toISOExtString() == "00:00:00"); 8690 assert(TimeOfDay(12, 30, 33).toISOExtString() == "12:30:33"); 8691 } 8692 8693 @safe unittest 8694 { 8695 auto tod = TimeOfDay(12, 30, 33); 8696 const ctod = TimeOfDay(12, 30, 33); 8697 immutable itod = TimeOfDay(12, 30, 33); 8698 assert(tod.toISOExtString() == "12:30:33"); 8699 assert(ctod.toISOExtString() == "12:30:33"); 8700 assert(itod.toISOExtString() == "12:30:33"); 8701 } 8702 8703 8704 /++ 8705 Converts this TimeOfDay to a string. 8706 8707 This function exists to make it easy to convert a $(LREF TimeOfDay) to a 8708 string for code that does not care what the exact format is - just that 8709 it presents the information in a clear manner. It also makes it easy to 8710 simply convert a $(LREF TimeOfDay) to a string when using functions such 8711 as `to!string`, `format`, or `writeln` which use toString to convert 8712 user-defined types. So, it is unlikely that much code will call 8713 toString directly. 8714 8715 The format of the string is purposefully unspecified, and code that 8716 cares about the format of the string should use `toISOString`, 8717 `toISOExtString`, or some other custom formatting function that 8718 explicitly generates the format that the code needs. The reason is that 8719 the code is then clear about what format it's using, making it less 8720 error-prone to maintain the code and interact with other software that 8721 consumes the generated strings. It's for this same reason that 8722 $(LREF TimeOfDay) has no `fromString` function, whereas it does have 8723 `fromISOString` and `fromISOExtString`. 8724 8725 The format returned by toString may or may not change in the future. 8726 +/ 8727 string toString() const @safe pure nothrow 8728 { 8729 return toISOExtString(); 8730 } 8731 8732 @safe unittest 8733 { 8734 auto tod = TimeOfDay(12, 30, 33); 8735 const ctod = TimeOfDay(12, 30, 33); 8736 immutable itod = TimeOfDay(12, 30, 33); 8737 assert(tod.toString()); 8738 assert(ctod.toString()); 8739 assert(itod.toString()); 8740 } 8741 8742 8743 /++ 8744 Creates a $(LREF TimeOfDay) from a string with the format HHMMSS. 8745 Whitespace is stripped from the given string. 8746 8747 Params: 8748 isoString = A string formatted in the ISO format for times. 8749 8750 Throws: 8751 $(REF DateTimeException,std,datetime,date) if the given string is 8752 not in the ISO format or if the resulting $(LREF TimeOfDay) would 8753 not be valid. 8754 +/ 8755 static TimeOfDay fromISOString(S)(in S isoString) @safe pure 8756 if (isSomeString!S) 8757 { 8758 import std.conv : to, text, ConvException; 8759 import std.exception : enforce; 8760 import std.string : strip; 8761 8762 int hours, minutes, seconds; 8763 auto str = strip(isoString); 8764 8765 enforce!DateTimeException(str.length == 6, text("Invalid ISO String: ", isoString)); 8766 8767 try 8768 { 8769 // cast to int from uint is used because it checks for 8770 // non digits without extra loops 8771 hours = cast(int) to!uint(str[0 .. 2]); 8772 minutes = cast(int) to!uint(str[2 .. 4]); 8773 seconds = cast(int) to!uint(str[4 .. $]); 8774 } 8775 catch (ConvException) 8776 { 8777 throw new DateTimeException(text("Invalid ISO String: ", isoString)); 8778 } 8779 8780 return TimeOfDay(hours, minutes, seconds); 8781 } 8782 8783 /// 8784 @safe unittest 8785 { 8786 assert(TimeOfDay.fromISOString("000000") == TimeOfDay(0, 0, 0)); 8787 assert(TimeOfDay.fromISOString("123033") == TimeOfDay(12, 30, 33)); 8788 assert(TimeOfDay.fromISOString(" 123033 ") == TimeOfDay(12, 30, 33)); 8789 } 8790 8791 @safe unittest 8792 { 8793 assertThrown!DateTimeException(TimeOfDay.fromISOString("")); 8794 assertThrown!DateTimeException(TimeOfDay.fromISOString("0")); 8795 assertThrown!DateTimeException(TimeOfDay.fromISOString("00")); 8796 assertThrown!DateTimeException(TimeOfDay.fromISOString("000")); 8797 assertThrown!DateTimeException(TimeOfDay.fromISOString("0000")); 8798 assertThrown!DateTimeException(TimeOfDay.fromISOString("00000")); 8799 assertThrown!DateTimeException(TimeOfDay.fromISOString("13033")); 8800 assertThrown!DateTimeException(TimeOfDay.fromISOString("1277")); 8801 assertThrown!DateTimeException(TimeOfDay.fromISOString("12707")); 8802 assertThrown!DateTimeException(TimeOfDay.fromISOString("12070")); 8803 assertThrown!DateTimeException(TimeOfDay.fromISOString("12303a")); 8804 assertThrown!DateTimeException(TimeOfDay.fromISOString("1230a3")); 8805 assertThrown!DateTimeException(TimeOfDay.fromISOString("123a33")); 8806 assertThrown!DateTimeException(TimeOfDay.fromISOString("12a033")); 8807 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a0033")); 8808 assertThrown!DateTimeException(TimeOfDay.fromISOString("a20033")); 8809 assertThrown!DateTimeException(TimeOfDay.fromISOString("1200330")); 8810 assertThrown!DateTimeException(TimeOfDay.fromISOString("0120033")); 8811 assertThrown!DateTimeException(TimeOfDay.fromISOString("-120033")); 8812 assertThrown!DateTimeException(TimeOfDay.fromISOString("+120033")); 8813 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033am")); 8814 assertThrown!DateTimeException(TimeOfDay.fromISOString("120033pm")); 8815 8816 assertThrown!DateTimeException(TimeOfDay.fromISOString("0::")); 8817 assertThrown!DateTimeException(TimeOfDay.fromISOString(":0:")); 8818 assertThrown!DateTimeException(TimeOfDay.fromISOString("::0")); 8819 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:0")); 8820 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:0:00")); 8821 assertThrown!DateTimeException(TimeOfDay.fromISOString("0:00:0")); 8822 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:0")); 8823 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:00:0")); 8824 assertThrown!DateTimeException(TimeOfDay.fromISOString("00:0:00")); 8825 assertThrown!DateTimeException(TimeOfDay.fromISOString("13:0:33")); 8826 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:7")); 8827 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:7:07")); 8828 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:07:0")); 8829 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:3a")); 8830 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:30:a3")); 8831 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:3a:33")); 8832 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:a0:33")); 8833 assertThrown!DateTimeException(TimeOfDay.fromISOString("1a:00:33")); 8834 assertThrown!DateTimeException(TimeOfDay.fromISOString("a2:00:33")); 8835 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:003:30")); 8836 assertThrown!DateTimeException(TimeOfDay.fromISOString("120:03:30")); 8837 assertThrown!DateTimeException(TimeOfDay.fromISOString("012:00:33")); 8838 assertThrown!DateTimeException(TimeOfDay.fromISOString("01:200:33")); 8839 assertThrown!DateTimeException(TimeOfDay.fromISOString("-12:00:33")); 8840 assertThrown!DateTimeException(TimeOfDay.fromISOString("+12:00:33")); 8841 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33am")); 8842 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33pm")); 8843 8844 assertThrown!DateTimeException(TimeOfDay.fromISOString("12:00:33")); 8845 8846 assert(TimeOfDay.fromISOString("011217") == TimeOfDay(1, 12, 17)); 8847 assert(TimeOfDay.fromISOString("001412") == TimeOfDay(0, 14, 12)); 8848 assert(TimeOfDay.fromISOString("000007") == TimeOfDay(0, 0, 7)); 8849 assert(TimeOfDay.fromISOString("011217 ") == TimeOfDay(1, 12, 17)); 8850 assert(TimeOfDay.fromISOString(" 011217") == TimeOfDay(1, 12, 17)); 8851 assert(TimeOfDay.fromISOString(" 011217 ") == TimeOfDay(1, 12, 17)); 8852 } 8853 8854 // bug# 17801 8855 @safe unittest 8856 { 8857 import std.conv : to; 8858 import std.meta : AliasSeq; 8859 foreach (C; AliasSeq!(char, wchar, dchar)) 8860 { 8861 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 8862 assert(TimeOfDay.fromISOString(to!S("141516")) == TimeOfDay(14, 15, 16)); 8863 } 8864 } 8865 8866 8867 /++ 8868 Creates a $(LREF TimeOfDay) from a string with the format HH:MM:SS. 8869 Whitespace is stripped from the given string. 8870 8871 Params: 8872 isoExtString = A string formatted in the ISO Extended format for 8873 times. 8874 8875 Throws: 8876 $(REF DateTimeException,std,datetime,date) if the given string is 8877 not in the ISO Extended format or if the resulting $(LREF TimeOfDay) 8878 would not be valid. 8879 +/ 8880 static TimeOfDay fromISOExtString(S)(in S isoExtString) @safe pure 8881 if (isSomeString!S) 8882 { 8883 import std.algorithm.searching : all; 8884 import std.ascii : isDigit; 8885 import std.conv : to; 8886 import std.exception : enforce; 8887 import std.format : format; 8888 import std.string : strip; 8889 8890 auto dstr = to!dstring(strip(isoExtString)); 8891 8892 enforce(dstr.length == 8, new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8893 8894 auto hours = dstr[0 .. 2]; 8895 auto minutes = dstr[3 .. 5]; 8896 auto seconds = dstr[6 .. $]; 8897 8898 enforce(dstr[2] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8899 enforce(dstr[5] == ':', new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8900 enforce(all!isDigit(hours), 8901 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8902 enforce(all!isDigit(minutes), 8903 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8904 enforce(all!isDigit(seconds), 8905 new DateTimeException(format("Invalid ISO Extended String: %s", isoExtString))); 8906 8907 return TimeOfDay(to!int(hours), to!int(minutes), to!int(seconds)); 8908 } 8909 8910 /// 8911 @safe unittest 8912 { 8913 assert(TimeOfDay.fromISOExtString("00:00:00") == TimeOfDay(0, 0, 0)); 8914 assert(TimeOfDay.fromISOExtString("12:30:33") == TimeOfDay(12, 30, 33)); 8915 assert(TimeOfDay.fromISOExtString(" 12:30:33 ") == TimeOfDay(12, 30, 33)); 8916 } 8917 8918 @safe unittest 8919 { 8920 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("")); 8921 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0")); 8922 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00")); 8923 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("000")); 8924 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0000")); 8925 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00000")); 8926 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13033")); 8927 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1277")); 8928 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12707")); 8929 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12070")); 8930 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12303a")); 8931 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1230a3")); 8932 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("123a33")); 8933 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12a033")); 8934 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a0033")); 8935 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a20033")); 8936 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1200330")); 8937 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0120033")); 8938 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-120033")); 8939 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+120033")); 8940 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033am")); 8941 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033pm")); 8942 8943 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0::")); 8944 assertThrown!DateTimeException(TimeOfDay.fromISOExtString(":0:")); 8945 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("::0")); 8946 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:0")); 8947 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:0:00")); 8948 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("0:00:0")); 8949 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:0")); 8950 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:00:0")); 8951 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("00:0:00")); 8952 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("13:0:33")); 8953 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:7")); 8954 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:7:07")); 8955 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:07:0")); 8956 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:3a")); 8957 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:30:a3")); 8958 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:3a:33")); 8959 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:a0:33")); 8960 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("1a:00:33")); 8961 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("a2:00:33")); 8962 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:003:30")); 8963 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120:03:30")); 8964 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("012:00:33")); 8965 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("01:200:33")); 8966 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("-12:00:33")); 8967 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("+12:00:33")); 8968 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33am")); 8969 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("12:00:33pm")); 8970 8971 assertThrown!DateTimeException(TimeOfDay.fromISOExtString("120033")); 8972 8973 assert(TimeOfDay.fromISOExtString("01:12:17") == TimeOfDay(1, 12, 17)); 8974 assert(TimeOfDay.fromISOExtString("00:14:12") == TimeOfDay(0, 14, 12)); 8975 assert(TimeOfDay.fromISOExtString("00:00:07") == TimeOfDay(0, 0, 7)); 8976 assert(TimeOfDay.fromISOExtString("01:12:17 ") == TimeOfDay(1, 12, 17)); 8977 assert(TimeOfDay.fromISOExtString(" 01:12:17") == TimeOfDay(1, 12, 17)); 8978 assert(TimeOfDay.fromISOExtString(" 01:12:17 ") == TimeOfDay(1, 12, 17)); 8979 } 8980 8981 // bug# 17801 8982 @safe unittest 8983 { 8984 import std.conv : to; 8985 import std.meta : AliasSeq; 8986 foreach (C; AliasSeq!(char, wchar, dchar)) 8987 { 8988 foreach (S; AliasSeq!(C[], const(C)[], immutable(C)[])) 8989 assert(TimeOfDay.fromISOExtString(to!S("14:15:16")) == TimeOfDay(14, 15, 16)); 8990 } 8991 } 8992 8993 8994 /++ 8995 Returns midnight. 8996 +/ 8997 @property static TimeOfDay min() @safe pure nothrow @nogc 8998 { 8999 return TimeOfDay.init; 9000 } 9001 9002 @safe unittest 9003 { 9004 assert(TimeOfDay.min.hour == 0); 9005 assert(TimeOfDay.min.minute == 0); 9006 assert(TimeOfDay.min.second == 0); 9007 assert(TimeOfDay.min < TimeOfDay.max); 9008 } 9009 9010 9011 /++ 9012 Returns one second short of midnight. 9013 +/ 9014 @property static TimeOfDay max() @safe pure nothrow @nogc 9015 { 9016 auto tod = TimeOfDay.init; 9017 tod._hour = maxHour; 9018 tod._minute = maxMinute; 9019 tod._second = maxSecond; 9020 9021 return tod; 9022 } 9023 9024 @safe unittest 9025 { 9026 assert(TimeOfDay.max.hour == 23); 9027 assert(TimeOfDay.max.minute == 59); 9028 assert(TimeOfDay.max.second == 59); 9029 assert(TimeOfDay.max > TimeOfDay.min); 9030 } 9031 9032 9033 private: 9034 9035 /+ 9036 Add seconds to the time of day. Negative values will subtract. If the 9037 number of seconds overflows (or underflows), then the seconds will wrap, 9038 increasing (or decreasing) the number of minutes accordingly. If the 9039 number of minutes overflows (or underflows), then the minutes will wrap. 9040 If the number of minutes overflows(or underflows), then the hour will 9041 wrap. (e.g. adding 90 seconds to 23:59:00 would result in 00:00:30). 9042 9043 Params: 9044 seconds = The number of seconds to add to this TimeOfDay. 9045 +/ 9046 ref TimeOfDay _addSeconds(long seconds) return @safe pure nothrow @nogc 9047 { 9048 long hnsecs = convert!("seconds", "hnsecs")(seconds); 9049 hnsecs += convert!("hours", "hnsecs")(_hour); 9050 hnsecs += convert!("minutes", "hnsecs")(_minute); 9051 hnsecs += convert!("seconds", "hnsecs")(_second); 9052 9053 hnsecs %= convert!("days", "hnsecs")(1); 9054 9055 if (hnsecs < 0) 9056 hnsecs += convert!("days", "hnsecs")(1); 9057 9058 immutable newHours = splitUnitsFromHNSecs!"hours"(hnsecs); 9059 immutable newMinutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 9060 immutable newSeconds = splitUnitsFromHNSecs!"seconds"(hnsecs); 9061 9062 _hour = cast(ubyte) newHours; 9063 _minute = cast(ubyte) newMinutes; 9064 _second = cast(ubyte) newSeconds; 9065 9066 return this; 9067 } 9068 9069 @safe unittest 9070 { 9071 static void testTOD(TimeOfDay orig, int seconds, in TimeOfDay expected, size_t line = __LINE__) 9072 { 9073 orig._addSeconds(seconds); 9074 assert(orig == expected); 9075 } 9076 9077 testTOD(TimeOfDay(12, 30, 33), 0, TimeOfDay(12, 30, 33)); 9078 testTOD(TimeOfDay(12, 30, 33), 1, TimeOfDay(12, 30, 34)); 9079 testTOD(TimeOfDay(12, 30, 33), 2, TimeOfDay(12, 30, 35)); 9080 testTOD(TimeOfDay(12, 30, 33), 3, TimeOfDay(12, 30, 36)); 9081 testTOD(TimeOfDay(12, 30, 33), 4, TimeOfDay(12, 30, 37)); 9082 testTOD(TimeOfDay(12, 30, 33), 5, TimeOfDay(12, 30, 38)); 9083 testTOD(TimeOfDay(12, 30, 33), 10, TimeOfDay(12, 30, 43)); 9084 testTOD(TimeOfDay(12, 30, 33), 15, TimeOfDay(12, 30, 48)); 9085 testTOD(TimeOfDay(12, 30, 33), 26, TimeOfDay(12, 30, 59)); 9086 testTOD(TimeOfDay(12, 30, 33), 27, TimeOfDay(12, 31, 0)); 9087 testTOD(TimeOfDay(12, 30, 33), 30, TimeOfDay(12, 31, 3)); 9088 testTOD(TimeOfDay(12, 30, 33), 59, TimeOfDay(12, 31, 32)); 9089 testTOD(TimeOfDay(12, 30, 33), 60, TimeOfDay(12, 31, 33)); 9090 testTOD(TimeOfDay(12, 30, 33), 61, TimeOfDay(12, 31, 34)); 9091 9092 testTOD(TimeOfDay(12, 30, 33), 1766, TimeOfDay(12, 59, 59)); 9093 testTOD(TimeOfDay(12, 30, 33), 1767, TimeOfDay(13, 0, 0)); 9094 testTOD(TimeOfDay(12, 30, 33), 1768, TimeOfDay(13, 0, 1)); 9095 testTOD(TimeOfDay(12, 30, 33), 2007, TimeOfDay(13, 4, 0)); 9096 testTOD(TimeOfDay(12, 30, 33), 3599, TimeOfDay(13, 30, 32)); 9097 testTOD(TimeOfDay(12, 30, 33), 3600, TimeOfDay(13, 30, 33)); 9098 testTOD(TimeOfDay(12, 30, 33), 3601, TimeOfDay(13, 30, 34)); 9099 testTOD(TimeOfDay(12, 30, 33), 7200, TimeOfDay(14, 30, 33)); 9100 9101 testTOD(TimeOfDay(12, 30, 33), -1, TimeOfDay(12, 30, 32)); 9102 testTOD(TimeOfDay(12, 30, 33), -2, TimeOfDay(12, 30, 31)); 9103 testTOD(TimeOfDay(12, 30, 33), -3, TimeOfDay(12, 30, 30)); 9104 testTOD(TimeOfDay(12, 30, 33), -4, TimeOfDay(12, 30, 29)); 9105 testTOD(TimeOfDay(12, 30, 33), -5, TimeOfDay(12, 30, 28)); 9106 testTOD(TimeOfDay(12, 30, 33), -10, TimeOfDay(12, 30, 23)); 9107 testTOD(TimeOfDay(12, 30, 33), -15, TimeOfDay(12, 30, 18)); 9108 testTOD(TimeOfDay(12, 30, 33), -33, TimeOfDay(12, 30, 0)); 9109 testTOD(TimeOfDay(12, 30, 33), -34, TimeOfDay(12, 29, 59)); 9110 testTOD(TimeOfDay(12, 30, 33), -35, TimeOfDay(12, 29, 58)); 9111 testTOD(TimeOfDay(12, 30, 33), -59, TimeOfDay(12, 29, 34)); 9112 testTOD(TimeOfDay(12, 30, 33), -60, TimeOfDay(12, 29, 33)); 9113 testTOD(TimeOfDay(12, 30, 33), -61, TimeOfDay(12, 29, 32)); 9114 9115 testTOD(TimeOfDay(12, 30, 33), -1833, TimeOfDay(12, 0, 0)); 9116 testTOD(TimeOfDay(12, 30, 33), -1834, TimeOfDay(11, 59, 59)); 9117 testTOD(TimeOfDay(12, 30, 33), -3600, TimeOfDay(11, 30, 33)); 9118 testTOD(TimeOfDay(12, 30, 33), -3601, TimeOfDay(11, 30, 32)); 9119 testTOD(TimeOfDay(12, 30, 33), -5134, TimeOfDay(11, 4, 59)); 9120 testTOD(TimeOfDay(12, 30, 33), -7200, TimeOfDay(10, 30, 33)); 9121 9122 testTOD(TimeOfDay(12, 30, 0), 1, TimeOfDay(12, 30, 1)); 9123 testTOD(TimeOfDay(12, 30, 0), 0, TimeOfDay(12, 30, 0)); 9124 testTOD(TimeOfDay(12, 30, 0), -1, TimeOfDay(12, 29, 59)); 9125 9126 testTOD(TimeOfDay(12, 0, 0), 1, TimeOfDay(12, 0, 1)); 9127 testTOD(TimeOfDay(12, 0, 0), 0, TimeOfDay(12, 0, 0)); 9128 testTOD(TimeOfDay(12, 0, 0), -1, TimeOfDay(11, 59, 59)); 9129 9130 testTOD(TimeOfDay(0, 0, 0), 1, TimeOfDay(0, 0, 1)); 9131 testTOD(TimeOfDay(0, 0, 0), 0, TimeOfDay(0, 0, 0)); 9132 testTOD(TimeOfDay(0, 0, 0), -1, TimeOfDay(23, 59, 59)); 9133 9134 testTOD(TimeOfDay(23, 59, 59), 1, TimeOfDay(0, 0, 0)); 9135 testTOD(TimeOfDay(23, 59, 59), 0, TimeOfDay(23, 59, 59)); 9136 testTOD(TimeOfDay(23, 59, 59), -1, TimeOfDay(23, 59, 58)); 9137 9138 const ctod = TimeOfDay(0, 0, 0); 9139 immutable itod = TimeOfDay(0, 0, 0); 9140 static assert(!__traits(compiles, ctod._addSeconds(7))); 9141 static assert(!__traits(compiles, itod._addSeconds(7))); 9142 } 9143 9144 9145 /+ 9146 Whether the given values form a valid $(LREF TimeOfDay). 9147 +/ 9148 static bool _valid(int hour, int minute, int second) @safe pure nothrow @nogc 9149 { 9150 return valid!"hours"(hour) && valid!"minutes"(minute) && valid!"seconds"(second); 9151 } 9152 9153 9154 @safe pure invariant() 9155 { 9156 import std.format : format; 9157 assert(_valid(_hour, _minute, _second), 9158 format("Invariant Failure: hour [%s] minute [%s] second [%s]", _hour, _minute, _second)); 9159 } 9160 9161 9162 package: 9163 9164 ubyte _hour; 9165 ubyte _minute; 9166 ubyte _second; 9167 9168 enum ubyte maxHour = 24 - 1; 9169 enum ubyte maxMinute = 60 - 1; 9170 enum ubyte maxSecond = 60 - 1; 9171 } 9172 9173 9174 /++ 9175 Returns whether the given value is valid for the given unit type when in a 9176 time point. Naturally, a duration is not held to a particular range, but 9177 the values in a time point are (e.g. a month must be in the range of 9178 1 - 12 inclusive). 9179 9180 Params: 9181 units = The units of time to validate. 9182 value = The number to validate. 9183 +/ 9184 bool valid(string units)(int value) @safe pure nothrow @nogc 9185 if (units == "months" || 9186 units == "hours" || 9187 units == "minutes" || 9188 units == "seconds") 9189 { 9190 static if (units == "months") 9191 return value >= Month.jan && value <= Month.dec; 9192 else static if (units == "hours") 9193 return value >= 0 && value <= 23; 9194 else static if (units == "minutes") 9195 return value >= 0 && value <= 59; 9196 else static if (units == "seconds") 9197 return value >= 0 && value <= 59; 9198 } 9199 9200 /// 9201 @safe unittest 9202 { 9203 assert(valid!"hours"(12)); 9204 assert(!valid!"hours"(32)); 9205 assert(valid!"months"(12)); 9206 assert(!valid!"months"(13)); 9207 } 9208 9209 /++ 9210 Returns whether the given day is valid for the given year and month. 9211 9212 Params: 9213 units = The units of time to validate. 9214 year = The year of the day to validate. 9215 month = The month of the day to validate (January is 1). 9216 day = The day to validate. 9217 +/ 9218 bool valid(string units)(int year, int month, int day) @safe pure nothrow @nogc 9219 if (units == "days") 9220 { 9221 return day > 0 && day <= maxDay(year, month); 9222 } 9223 9224 /// 9225 @safe pure nothrow @nogc unittest 9226 { 9227 assert(valid!"days"(2016, 2, 29)); 9228 assert(!valid!"days"(2016, 2, 30)); 9229 assert(valid!"days"(2017, 2, 20)); 9230 assert(!valid!"days"(2017, 2, 29)); 9231 } 9232 9233 9234 /++ 9235 Params: 9236 units = The units of time to validate. 9237 value = The number to validate. 9238 file = The file that the $(LREF DateTimeException) will list if thrown. 9239 line = The line number that the $(LREF DateTimeException) will list if 9240 thrown. 9241 9242 Throws: 9243 $(LREF DateTimeException) if $(D valid!units(value)) is false. 9244 +/ 9245 void enforceValid(string units)(int value, string file = __FILE__, size_t line = __LINE__) @safe pure 9246 if (units == "months" || 9247 units == "hours" || 9248 units == "minutes" || 9249 units == "seconds") 9250 { 9251 import std.format : format; 9252 9253 static if (units == "months") 9254 { 9255 if (!valid!units(value)) 9256 throw new DateTimeException(format("%s is not a valid month of the year.", value), file, line); 9257 } 9258 else static if (units == "hours") 9259 { 9260 if (!valid!units(value)) 9261 throw new DateTimeException(format("%s is not a valid hour of the day.", value), file, line); 9262 } 9263 else static if (units == "minutes") 9264 { 9265 if (!valid!units(value)) 9266 throw new DateTimeException(format("%s is not a valid minute of an hour.", value), file, line); 9267 } 9268 else static if (units == "seconds") 9269 { 9270 if (!valid!units(value)) 9271 throw new DateTimeException(format("%s is not a valid second of a minute.", value), file, line); 9272 } 9273 } 9274 9275 9276 /++ 9277 Params: 9278 units = The units of time to validate. 9279 year = The year of the day to validate. 9280 month = The month of the day to validate. 9281 day = The day to validate. 9282 file = The file that the $(LREF DateTimeException) will list if thrown. 9283 line = The line number that the $(LREF DateTimeException) will list if 9284 thrown. 9285 9286 Throws: 9287 $(LREF DateTimeException) if $(D valid!"days"(year, month, day)) is false. 9288 +/ 9289 void enforceValid(string units) 9290 (int year, Month month, int day, string file = __FILE__, size_t line = __LINE__) @safe pure 9291 if (units == "days") 9292 { 9293 import std.format : format; 9294 if (!valid!"days"(year, month, day)) 9295 throw new DateTimeException(format("%s is not a valid day in %s in %s", day, month, year), file, line); 9296 } 9297 9298 9299 /++ 9300 Returns the number of days from the current day of the week to the given 9301 day of the week. If they are the same, then the result is 0. 9302 9303 Params: 9304 currDoW = The current day of the week. 9305 dow = The day of the week to get the number of days to. 9306 +/ 9307 int daysToDayOfWeek(DayOfWeek currDoW, DayOfWeek dow) @safe pure nothrow @nogc 9308 { 9309 if (currDoW == dow) 9310 return 0; 9311 if (currDoW < dow) 9312 return dow - currDoW; 9313 return DayOfWeek.sat - currDoW + dow + 1; 9314 } 9315 9316 /// 9317 @safe pure nothrow @nogc unittest 9318 { 9319 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9320 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9321 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9322 } 9323 9324 @safe unittest 9325 { 9326 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sun) == 0); 9327 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.mon) == 1); 9328 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.tue) == 2); 9329 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.wed) == 3); 9330 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.thu) == 4); 9331 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.fri) == 5); 9332 assert(daysToDayOfWeek(DayOfWeek.sun, DayOfWeek.sat) == 6); 9333 9334 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sun) == 6); 9335 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.mon) == 0); 9336 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.tue) == 1); 9337 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.wed) == 2); 9338 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.thu) == 3); 9339 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.fri) == 4); 9340 assert(daysToDayOfWeek(DayOfWeek.mon, DayOfWeek.sat) == 5); 9341 9342 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sun) == 5); 9343 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.mon) == 6); 9344 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.tue) == 0); 9345 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.wed) == 1); 9346 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.thu) == 2); 9347 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.fri) == 3); 9348 assert(daysToDayOfWeek(DayOfWeek.tue, DayOfWeek.sat) == 4); 9349 9350 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sun) == 4); 9351 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.mon) == 5); 9352 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.tue) == 6); 9353 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.wed) == 0); 9354 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.thu) == 1); 9355 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.fri) == 2); 9356 assert(daysToDayOfWeek(DayOfWeek.wed, DayOfWeek.sat) == 3); 9357 9358 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sun) == 3); 9359 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.mon) == 4); 9360 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.tue) == 5); 9361 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.wed) == 6); 9362 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.thu) == 0); 9363 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.fri) == 1); 9364 assert(daysToDayOfWeek(DayOfWeek.thu, DayOfWeek.sat) == 2); 9365 9366 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sun) == 2); 9367 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.mon) == 3); 9368 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.tue) == 4); 9369 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.wed) == 5); 9370 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.thu) == 6); 9371 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.fri) == 0); 9372 assert(daysToDayOfWeek(DayOfWeek.fri, DayOfWeek.sat) == 1); 9373 9374 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sun) == 1); 9375 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.mon) == 2); 9376 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.tue) == 3); 9377 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.wed) == 4); 9378 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.thu) == 5); 9379 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.fri) == 6); 9380 assert(daysToDayOfWeek(DayOfWeek.sat, DayOfWeek.sat) == 0); 9381 } 9382 9383 9384 /++ 9385 Returns the number of months from the current months of the year to the 9386 given month of the year. If they are the same, then the result is 0. 9387 9388 Params: 9389 currMonth = The current month of the year. 9390 month = The month of the year to get the number of months to. 9391 +/ 9392 int monthsToMonth(int currMonth, int month) @safe pure 9393 { 9394 enforceValid!"months"(currMonth); 9395 enforceValid!"months"(month); 9396 9397 if (currMonth == month) 9398 return 0; 9399 if (currMonth < month) 9400 return month - currMonth; 9401 return Month.dec - currMonth + month; 9402 } 9403 9404 /// 9405 @safe pure unittest 9406 { 9407 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9408 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9409 assert(monthsToMonth(Month.jul, Month.oct) == 3); 9410 } 9411 9412 @safe unittest 9413 { 9414 assert(monthsToMonth(Month.jan, Month.jan) == 0); 9415 assert(monthsToMonth(Month.jan, Month.feb) == 1); 9416 assert(monthsToMonth(Month.jan, Month.mar) == 2); 9417 assert(monthsToMonth(Month.jan, Month.apr) == 3); 9418 assert(monthsToMonth(Month.jan, Month.may) == 4); 9419 assert(monthsToMonth(Month.jan, Month.jun) == 5); 9420 assert(monthsToMonth(Month.jan, Month.jul) == 6); 9421 assert(monthsToMonth(Month.jan, Month.aug) == 7); 9422 assert(monthsToMonth(Month.jan, Month.sep) == 8); 9423 assert(monthsToMonth(Month.jan, Month.oct) == 9); 9424 assert(monthsToMonth(Month.jan, Month.nov) == 10); 9425 assert(monthsToMonth(Month.jan, Month.dec) == 11); 9426 9427 assert(monthsToMonth(Month.may, Month.jan) == 8); 9428 assert(monthsToMonth(Month.may, Month.feb) == 9); 9429 assert(monthsToMonth(Month.may, Month.mar) == 10); 9430 assert(monthsToMonth(Month.may, Month.apr) == 11); 9431 assert(monthsToMonth(Month.may, Month.may) == 0); 9432 assert(monthsToMonth(Month.may, Month.jun) == 1); 9433 assert(monthsToMonth(Month.may, Month.jul) == 2); 9434 assert(monthsToMonth(Month.may, Month.aug) == 3); 9435 assert(monthsToMonth(Month.may, Month.sep) == 4); 9436 assert(monthsToMonth(Month.may, Month.oct) == 5); 9437 assert(monthsToMonth(Month.may, Month.nov) == 6); 9438 assert(monthsToMonth(Month.may, Month.dec) == 7); 9439 9440 assert(monthsToMonth(Month.oct, Month.jan) == 3); 9441 assert(monthsToMonth(Month.oct, Month.feb) == 4); 9442 assert(monthsToMonth(Month.oct, Month.mar) == 5); 9443 assert(monthsToMonth(Month.oct, Month.apr) == 6); 9444 assert(monthsToMonth(Month.oct, Month.may) == 7); 9445 assert(monthsToMonth(Month.oct, Month.jun) == 8); 9446 assert(monthsToMonth(Month.oct, Month.jul) == 9); 9447 assert(monthsToMonth(Month.oct, Month.aug) == 10); 9448 assert(monthsToMonth(Month.oct, Month.sep) == 11); 9449 assert(monthsToMonth(Month.oct, Month.oct) == 0); 9450 assert(monthsToMonth(Month.oct, Month.nov) == 1); 9451 assert(monthsToMonth(Month.oct, Month.dec) == 2); 9452 9453 assert(monthsToMonth(Month.dec, Month.jan) == 1); 9454 assert(monthsToMonth(Month.dec, Month.feb) == 2); 9455 assert(monthsToMonth(Month.dec, Month.mar) == 3); 9456 assert(monthsToMonth(Month.dec, Month.apr) == 4); 9457 assert(monthsToMonth(Month.dec, Month.may) == 5); 9458 assert(monthsToMonth(Month.dec, Month.jun) == 6); 9459 assert(monthsToMonth(Month.dec, Month.jul) == 7); 9460 assert(monthsToMonth(Month.dec, Month.aug) == 8); 9461 assert(monthsToMonth(Month.dec, Month.sep) == 9); 9462 assert(monthsToMonth(Month.dec, Month.oct) == 10); 9463 assert(monthsToMonth(Month.dec, Month.nov) == 11); 9464 assert(monthsToMonth(Month.dec, Month.dec) == 0); 9465 } 9466 9467 9468 /++ 9469 Whether the given Gregorian Year is a leap year. 9470 9471 Params: 9472 year = The year to to be tested. 9473 +/ 9474 bool yearIsLeapYear(int year) @safe pure nothrow @nogc 9475 { 9476 if (year % 400 == 0) 9477 return true; 9478 if (year % 100 == 0) 9479 return false; 9480 return year % 4 == 0; 9481 } 9482 9483 /// 9484 @safe unittest 9485 { 9486 foreach (year; [1, 2, 100, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010]) 9487 { 9488 assert(!yearIsLeapYear(year)); 9489 assert(!yearIsLeapYear(-year)); 9490 } 9491 9492 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 9493 { 9494 assert(yearIsLeapYear(year)); 9495 assert(yearIsLeapYear(-year)); 9496 } 9497 } 9498 9499 @safe unittest 9500 { 9501 import std.format : format; 9502 foreach (year; [1, 2, 3, 5, 6, 7, 100, 200, 300, 500, 600, 700, 1998, 1999, 9503 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011]) 9504 { 9505 assert(!yearIsLeapYear(year), format("year: %s.", year)); 9506 assert(!yearIsLeapYear(-year), format("year: %s.", year)); 9507 } 9508 9509 foreach (year; [0, 4, 8, 400, 800, 1600, 1996, 2000, 2004, 2008, 2012]) 9510 { 9511 assert(yearIsLeapYear(year), format("year: %s.", year)); 9512 assert(yearIsLeapYear(-year), format("year: %s.", year)); 9513 } 9514 } 9515 9516 9517 /++ 9518 Whether the given type defines all of the necessary functions for it to 9519 function as a time point. 9520 9521 1. $(D T) must define a static property named $(D min) which is the smallest 9522 value of $(D T) as $(D Unqual!T). 9523 9524 2. $(D T) must define a static property named $(D max) which is the largest 9525 value of $(D T) as $(D Unqual!T). 9526 9527 3. $(D T) must define an $(D opBinary) for addition and subtraction that 9528 accepts $(REF Duration, core,time) and returns $(D Unqual!T). 9529 9530 4. $(D T) must define an $(D opOpAssign) for addition and subtraction that 9531 accepts $(REF Duration, core,time) and returns $(D ref Unqual!T). 9532 9533 5. $(D T) must define a $(D opBinary) for subtraction which accepts $(D T) 9534 and returns returns $(REF Duration, core,time). 9535 +/ 9536 template isTimePoint(T) 9537 { 9538 import core.time : Duration; 9539 import std.traits : FunctionAttribute, functionAttributes, Unqual; 9540 9541 enum isTimePoint = hasMin && 9542 hasMax && 9543 hasOverloadedOpBinaryWithDuration && 9544 hasOverloadedOpAssignWithDuration && 9545 hasOverloadedOpBinaryWithSelf && 9546 !is(U == Duration); 9547 9548 private: 9549 9550 alias U = Unqual!T; 9551 9552 enum hasMin = __traits(hasMember, T, "min") && 9553 is(typeof(T.min) == U) && 9554 is(typeof({static assert(__traits(isStaticFunction, T.min));})); 9555 9556 enum hasMax = __traits(hasMember, T, "max") && 9557 is(typeof(T.max) == U) && 9558 is(typeof({static assert(__traits(isStaticFunction, T.max));})); 9559 9560 enum hasOverloadedOpBinaryWithDuration = is(typeof(T.init + Duration.init) == U) && 9561 is(typeof(T.init - Duration.init) == U); 9562 9563 enum hasOverloadedOpAssignWithDuration = is(typeof(U.init += Duration.init) == U) && 9564 is(typeof(U.init -= Duration.init) == U) && 9565 is(typeof( 9566 { 9567 alias add = U.opOpAssign!"+"; 9568 alias sub = U.opOpAssign!"-"; 9569 alias FA = FunctionAttribute; 9570 static assert((functionAttributes!add & FA.ref_) != 0); 9571 static assert((functionAttributes!sub & FA.ref_) != 0); 9572 })); 9573 9574 enum hasOverloadedOpBinaryWithSelf = is(typeof(T.init - T.init) == Duration); 9575 } 9576 9577 /// 9578 @safe unittest 9579 { 9580 import core.time : Duration; 9581 import std.datetime.interval : Interval; 9582 import std.datetime.systime : SysTime; 9583 9584 static assert(isTimePoint!Date); 9585 static assert(isTimePoint!DateTime); 9586 static assert(isTimePoint!SysTime); 9587 static assert(isTimePoint!TimeOfDay); 9588 9589 static assert(!isTimePoint!int); 9590 static assert(!isTimePoint!Duration); 9591 static assert(!isTimePoint!(Interval!SysTime)); 9592 } 9593 9594 @safe unittest 9595 { 9596 import core.time; 9597 import std.datetime.interval; 9598 import std.datetime.systime; 9599 import std.meta : AliasSeq; 9600 9601 foreach (TP; AliasSeq!(Date, DateTime, SysTime, TimeOfDay)) 9602 { 9603 static assert(isTimePoint!(const TP), TP.stringof); 9604 static assert(isTimePoint!(immutable TP), TP.stringof); 9605 } 9606 9607 foreach (T; AliasSeq!(float, string, Duration, Interval!Date, PosInfInterval!Date, NegInfInterval!Date)) 9608 static assert(!isTimePoint!T, T.stringof); 9609 } 9610 9611 9612 /++ 9613 Whether all of the given strings are valid units of time. 9614 9615 $(D "nsecs") is not considered a valid unit of time. Nothing in std.datetime 9616 can handle precision greater than hnsecs, and the few functions in core.time 9617 which deal with "nsecs" deal with it explicitly. 9618 +/ 9619 bool validTimeUnits(string[] units...) @safe pure nothrow @nogc 9620 { 9621 import std.algorithm.searching : canFind; 9622 foreach (str; units) 9623 { 9624 if (!canFind(timeStrings[], str)) 9625 return false; 9626 } 9627 return true; 9628 } 9629 9630 /// 9631 @safe @nogc nothrow unittest 9632 { 9633 assert(validTimeUnits("msecs", "seconds", "minutes")); 9634 assert(validTimeUnits("days", "weeks", "months")); 9635 assert(!validTimeUnits("ms", "seconds", "minutes")); 9636 } 9637 9638 9639 /++ 9640 Compares two time unit strings. $(D "years") are the largest units and 9641 $(D "hnsecs") are the smallest. 9642 9643 Returns: 9644 $(BOOKTABLE, 9645 $(TR $(TD this < rhs) $(TD < 0)) 9646 $(TR $(TD this == rhs) $(TD 0)) 9647 $(TR $(TD this > rhs) $(TD > 0)) 9648 ) 9649 9650 Throws: 9651 $(LREF DateTimeException) if either of the given strings is not a valid 9652 time unit string. 9653 +/ 9654 int cmpTimeUnits(string lhs, string rhs) @safe pure 9655 { 9656 import std.algorithm.searching : countUntil; 9657 import std.exception : enforce; 9658 import std.format : format; 9659 9660 auto tstrings = timeStrings; 9661 immutable indexOfLHS = countUntil(tstrings, lhs); 9662 immutable indexOfRHS = countUntil(tstrings, rhs); 9663 9664 enforce(indexOfLHS != -1, format("%s is not a valid TimeString", lhs)); 9665 enforce(indexOfRHS != -1, format("%s is not a valid TimeString", rhs)); 9666 9667 if (indexOfLHS < indexOfRHS) 9668 return -1; 9669 if (indexOfLHS > indexOfRHS) 9670 return 1; 9671 9672 return 0; 9673 } 9674 9675 /// 9676 @safe pure unittest 9677 { 9678 assert(cmpTimeUnits("hours", "hours") == 0); 9679 assert(cmpTimeUnits("hours", "weeks") < 0); 9680 assert(cmpTimeUnits("months", "seconds") > 0); 9681 } 9682 9683 @safe unittest 9684 { 9685 foreach (i, outerUnits; timeStrings) 9686 { 9687 assert(cmpTimeUnits(outerUnits, outerUnits) == 0); 9688 9689 // For some reason, $ won't compile. 9690 foreach (innerUnits; timeStrings[i + 1 .. timeStrings.length]) 9691 assert(cmpTimeUnits(outerUnits, innerUnits) == -1); 9692 } 9693 9694 foreach (i, outerUnits; timeStrings) 9695 { 9696 foreach (innerUnits; timeStrings[0 .. i]) 9697 assert(cmpTimeUnits(outerUnits, innerUnits) == 1); 9698 } 9699 } 9700 9701 9702 /++ 9703 Compares two time unit strings at compile time. $(D "years") are the largest 9704 units and $(D "hnsecs") are the smallest. 9705 9706 This template is used instead of $(D cmpTimeUnits) because exceptions 9707 can't be thrown at compile time and $(D cmpTimeUnits) must enforce that 9708 the strings it's given are valid time unit strings. This template uses a 9709 template constraint instead. 9710 9711 Returns: 9712 $(BOOKTABLE, 9713 $(TR $(TD this < rhs) $(TD < 0)) 9714 $(TR $(TD this == rhs) $(TD 0)) 9715 $(TR $(TD this > rhs) $(TD > 0)) 9716 ) 9717 +/ 9718 template CmpTimeUnits(string lhs, string rhs) 9719 if (validTimeUnits(lhs, rhs)) 9720 { 9721 enum CmpTimeUnits = cmpTimeUnitsCTFE(lhs, rhs); 9722 } 9723 9724 9725 // Helper function for CmpTimeUnits. 9726 private int cmpTimeUnitsCTFE(string lhs, string rhs) @safe pure nothrow @nogc 9727 { 9728 import std.algorithm.searching : countUntil; 9729 auto tstrings = timeStrings; 9730 immutable indexOfLHS = countUntil(tstrings, lhs); 9731 immutable indexOfRHS = countUntil(tstrings, rhs); 9732 9733 if (indexOfLHS < indexOfRHS) 9734 return -1; 9735 if (indexOfLHS > indexOfRHS) 9736 return 1; 9737 9738 return 0; 9739 } 9740 9741 @safe unittest 9742 { 9743 import std.format : format; 9744 import std.meta : AliasSeq; 9745 9746 static string genTest(size_t index) 9747 { 9748 auto currUnits = timeStrings[index]; 9749 auto test = format(`assert(CmpTimeUnits!("%s", "%s") == 0);`, currUnits, currUnits); 9750 9751 foreach (units; timeStrings[index + 1 .. $]) 9752 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == -1);`, currUnits, units); 9753 9754 foreach (units; timeStrings[0 .. index]) 9755 test ~= format(`assert(CmpTimeUnits!("%s", "%s") == 1);`, currUnits, units); 9756 9757 return test; 9758 } 9759 9760 static assert(timeStrings.length == 10); 9761 foreach (n; AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) 9762 mixin(genTest(n)); 9763 } 9764 9765 9766 package: 9767 9768 9769 /+ 9770 Array of the short (three letter) names of each month. 9771 +/ 9772 immutable string[12] _monthNames = ["Jan", 9773 "Feb", 9774 "Mar", 9775 "Apr", 9776 "May", 9777 "Jun", 9778 "Jul", 9779 "Aug", 9780 "Sep", 9781 "Oct", 9782 "Nov", 9783 "Dec"]; 9784 9785 /+ 9786 The maximum valid Day in the given month in the given year. 9787 9788 Params: 9789 year = The year to get the day for. 9790 month = The month of the Gregorian Calendar to get the day for. 9791 +/ 9792 ubyte maxDay(int year, int month) @safe pure nothrow @nogc 9793 in 9794 { 9795 assert(valid!"months"(month)); 9796 } 9797 body 9798 { 9799 switch (month) 9800 { 9801 case Month.jan, Month.mar, Month.may, Month.jul, Month.aug, Month.oct, Month.dec: 9802 return 31; 9803 case Month.feb: 9804 return yearIsLeapYear(year) ? 29 : 28; 9805 case Month.apr, Month.jun, Month.sep, Month.nov: 9806 return 30; 9807 default: 9808 assert(0, "Invalid month."); 9809 } 9810 } 9811 9812 @safe unittest 9813 { 9814 // Test A.D. 9815 assert(maxDay(1999, 1) == 31); 9816 assert(maxDay(1999, 2) == 28); 9817 assert(maxDay(1999, 3) == 31); 9818 assert(maxDay(1999, 4) == 30); 9819 assert(maxDay(1999, 5) == 31); 9820 assert(maxDay(1999, 6) == 30); 9821 assert(maxDay(1999, 7) == 31); 9822 assert(maxDay(1999, 8) == 31); 9823 assert(maxDay(1999, 9) == 30); 9824 assert(maxDay(1999, 10) == 31); 9825 assert(maxDay(1999, 11) == 30); 9826 assert(maxDay(1999, 12) == 31); 9827 9828 assert(maxDay(2000, 1) == 31); 9829 assert(maxDay(2000, 2) == 29); 9830 assert(maxDay(2000, 3) == 31); 9831 assert(maxDay(2000, 4) == 30); 9832 assert(maxDay(2000, 5) == 31); 9833 assert(maxDay(2000, 6) == 30); 9834 assert(maxDay(2000, 7) == 31); 9835 assert(maxDay(2000, 8) == 31); 9836 assert(maxDay(2000, 9) == 30); 9837 assert(maxDay(2000, 10) == 31); 9838 assert(maxDay(2000, 11) == 30); 9839 assert(maxDay(2000, 12) == 31); 9840 9841 // Test B.C. 9842 assert(maxDay(-1999, 1) == 31); 9843 assert(maxDay(-1999, 2) == 28); 9844 assert(maxDay(-1999, 3) == 31); 9845 assert(maxDay(-1999, 4) == 30); 9846 assert(maxDay(-1999, 5) == 31); 9847 assert(maxDay(-1999, 6) == 30); 9848 assert(maxDay(-1999, 7) == 31); 9849 assert(maxDay(-1999, 8) == 31); 9850 assert(maxDay(-1999, 9) == 30); 9851 assert(maxDay(-1999, 10) == 31); 9852 assert(maxDay(-1999, 11) == 30); 9853 assert(maxDay(-1999, 12) == 31); 9854 9855 assert(maxDay(-2000, 1) == 31); 9856 assert(maxDay(-2000, 2) == 29); 9857 assert(maxDay(-2000, 3) == 31); 9858 assert(maxDay(-2000, 4) == 30); 9859 assert(maxDay(-2000, 5) == 31); 9860 assert(maxDay(-2000, 6) == 30); 9861 assert(maxDay(-2000, 7) == 31); 9862 assert(maxDay(-2000, 8) == 31); 9863 assert(maxDay(-2000, 9) == 30); 9864 assert(maxDay(-2000, 10) == 31); 9865 assert(maxDay(-2000, 11) == 30); 9866 assert(maxDay(-2000, 12) == 31); 9867 } 9868 9869 /+ 9870 Splits out a particular unit from hnsecs and gives the value for that 9871 unit and the remaining hnsecs. It really shouldn't be used unless unless 9872 all units larger than the given units have already been split out. 9873 9874 Params: 9875 units = The units to split out. 9876 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left 9877 after splitting out the given units. 9878 9879 Returns: 9880 The number of the given units from converting hnsecs to those units. 9881 +/ 9882 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc 9883 if (validTimeUnits(units) && CmpTimeUnits!(units, "months") < 0) 9884 { 9885 import core.time : convert; 9886 immutable value = convert!("hnsecs", units)(hnsecs); 9887 hnsecs -= convert!(units, "hnsecs")(value); 9888 return value; 9889 } 9890 9891 @safe unittest 9892 { 9893 auto hnsecs = 2595000000007L; 9894 immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 9895 assert(days == 3); 9896 assert(hnsecs == 3000000007); 9897 9898 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 9899 assert(minutes == 5); 9900 assert(hnsecs == 7); 9901 } 9902 9903 9904 /+ 9905 Returns the day of the week for the given day of the Gregorian Calendar. 9906 9907 Params: 9908 day = The day of the Gregorian Calendar for which to get the day of 9909 the week. 9910 +/ 9911 DayOfWeek getDayOfWeek(int day) @safe pure nothrow @nogc 9912 { 9913 // January 1st, 1 A.D. was a Monday 9914 if (day >= 0) 9915 return cast(DayOfWeek)(day % 7); 9916 else 9917 { 9918 immutable dow = cast(DayOfWeek)((day % 7) + 7); 9919 9920 if (dow == 7) 9921 return DayOfWeek.sun; 9922 else 9923 return dow; 9924 } 9925 } 9926 9927 @safe unittest 9928 { 9929 import std.datetime.systime : SysTime; 9930 9931 // Test A.D. 9932 assert(getDayOfWeek(SysTime(Date(1, 1, 1)).dayOfGregorianCal) == DayOfWeek.mon); 9933 assert(getDayOfWeek(SysTime(Date(1, 1, 2)).dayOfGregorianCal) == DayOfWeek.tue); 9934 assert(getDayOfWeek(SysTime(Date(1, 1, 3)).dayOfGregorianCal) == DayOfWeek.wed); 9935 assert(getDayOfWeek(SysTime(Date(1, 1, 4)).dayOfGregorianCal) == DayOfWeek.thu); 9936 assert(getDayOfWeek(SysTime(Date(1, 1, 5)).dayOfGregorianCal) == DayOfWeek.fri); 9937 assert(getDayOfWeek(SysTime(Date(1, 1, 6)).dayOfGregorianCal) == DayOfWeek.sat); 9938 assert(getDayOfWeek(SysTime(Date(1, 1, 7)).dayOfGregorianCal) == DayOfWeek.sun); 9939 assert(getDayOfWeek(SysTime(Date(1, 1, 8)).dayOfGregorianCal) == DayOfWeek.mon); 9940 assert(getDayOfWeek(SysTime(Date(1, 1, 9)).dayOfGregorianCal) == DayOfWeek.tue); 9941 assert(getDayOfWeek(SysTime(Date(2, 1, 1)).dayOfGregorianCal) == DayOfWeek.tue); 9942 assert(getDayOfWeek(SysTime(Date(3, 1, 1)).dayOfGregorianCal) == DayOfWeek.wed); 9943 assert(getDayOfWeek(SysTime(Date(4, 1, 1)).dayOfGregorianCal) == DayOfWeek.thu); 9944 assert(getDayOfWeek(SysTime(Date(5, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 9945 assert(getDayOfWeek(SysTime(Date(2000, 1, 1)).dayOfGregorianCal) == DayOfWeek.sat); 9946 assert(getDayOfWeek(SysTime(Date(2010, 8, 22)).dayOfGregorianCal) == DayOfWeek.sun); 9947 assert(getDayOfWeek(SysTime(Date(2010, 8, 23)).dayOfGregorianCal) == DayOfWeek.mon); 9948 assert(getDayOfWeek(SysTime(Date(2010, 8, 24)).dayOfGregorianCal) == DayOfWeek.tue); 9949 assert(getDayOfWeek(SysTime(Date(2010, 8, 25)).dayOfGregorianCal) == DayOfWeek.wed); 9950 assert(getDayOfWeek(SysTime(Date(2010, 8, 26)).dayOfGregorianCal) == DayOfWeek.thu); 9951 assert(getDayOfWeek(SysTime(Date(2010, 8, 27)).dayOfGregorianCal) == DayOfWeek.fri); 9952 assert(getDayOfWeek(SysTime(Date(2010, 8, 28)).dayOfGregorianCal) == DayOfWeek.sat); 9953 assert(getDayOfWeek(SysTime(Date(2010, 8, 29)).dayOfGregorianCal) == DayOfWeek.sun); 9954 9955 // Test B.C. 9956 assert(getDayOfWeek(SysTime(Date(0, 12, 31)).dayOfGregorianCal) == DayOfWeek.sun); 9957 assert(getDayOfWeek(SysTime(Date(0, 12, 30)).dayOfGregorianCal) == DayOfWeek.sat); 9958 assert(getDayOfWeek(SysTime(Date(0, 12, 29)).dayOfGregorianCal) == DayOfWeek.fri); 9959 assert(getDayOfWeek(SysTime(Date(0, 12, 28)).dayOfGregorianCal) == DayOfWeek.thu); 9960 assert(getDayOfWeek(SysTime(Date(0, 12, 27)).dayOfGregorianCal) == DayOfWeek.wed); 9961 assert(getDayOfWeek(SysTime(Date(0, 12, 26)).dayOfGregorianCal) == DayOfWeek.tue); 9962 assert(getDayOfWeek(SysTime(Date(0, 12, 25)).dayOfGregorianCal) == DayOfWeek.mon); 9963 assert(getDayOfWeek(SysTime(Date(0, 12, 24)).dayOfGregorianCal) == DayOfWeek.sun); 9964 assert(getDayOfWeek(SysTime(Date(0, 12, 23)).dayOfGregorianCal) == DayOfWeek.sat); 9965 } 9966 9967 9968 private: 9969 9970 enum daysInYear = 365; // The number of days in a non-leap year. 9971 enum daysInLeapYear = 366; // The numbef or days in a leap year. 9972 enum daysIn4Years = daysInYear * 3 + daysInLeapYear; // Number of days in 4 years. 9973 enum daysIn100Years = daysIn4Years * 25 - 1; // The number of days in 100 years. 9974 enum daysIn400Years = daysIn100Years * 4 + 1; // The number of days in 400 years. 9975 9976 /+ 9977 Array of integers representing the last days of each month in a year. 9978 +/ 9979 immutable int[13] lastDayNonLeap = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; 9980 9981 /+ 9982 Array of integers representing the last days of each month in a leap year. 9983 +/ 9984 immutable int[13] lastDayLeap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; 9985 9986 9987 /+ 9988 Returns the string representation of the given month. 9989 +/ 9990 string monthToString(Month month) @safe pure 9991 { 9992 import std.format : format; 9993 assert(month >= Month.jan && month <= Month.dec, format("Invalid month: %s", month)); 9994 return _monthNames[month - Month.jan]; 9995 } 9996 9997 @safe unittest 9998 { 9999 assert(monthToString(Month.jan) == "Jan"); 10000 assert(monthToString(Month.feb) == "Feb"); 10001 assert(monthToString(Month.mar) == "Mar"); 10002 assert(monthToString(Month.apr) == "Apr"); 10003 assert(monthToString(Month.may) == "May"); 10004 assert(monthToString(Month.jun) == "Jun"); 10005 assert(monthToString(Month.jul) == "Jul"); 10006 assert(monthToString(Month.aug) == "Aug"); 10007 assert(monthToString(Month.sep) == "Sep"); 10008 assert(monthToString(Month.oct) == "Oct"); 10009 assert(monthToString(Month.nov) == "Nov"); 10010 assert(monthToString(Month.dec) == "Dec"); 10011 } 10012 10013 10014 /+ 10015 Returns the Month corresponding to the given string. 10016 10017 Params: 10018 monthStr = The string representation of the month to get the Month for. 10019 10020 Throws: 10021 $(REF DateTimeException,std,datetime,date) if the given month is not a 10022 valid month string. 10023 +/ 10024 Month monthFromString(string monthStr) @safe pure 10025 { 10026 import std.format : format; 10027 switch (monthStr) 10028 { 10029 case "Jan": 10030 return Month.jan; 10031 case "Feb": 10032 return Month.feb; 10033 case "Mar": 10034 return Month.mar; 10035 case "Apr": 10036 return Month.apr; 10037 case "May": 10038 return Month.may; 10039 case "Jun": 10040 return Month.jun; 10041 case "Jul": 10042 return Month.jul; 10043 case "Aug": 10044 return Month.aug; 10045 case "Sep": 10046 return Month.sep; 10047 case "Oct": 10048 return Month.oct; 10049 case "Nov": 10050 return Month.nov; 10051 case "Dec": 10052 return Month.dec; 10053 default: 10054 throw new DateTimeException(format("Invalid month %s", monthStr)); 10055 } 10056 } 10057 10058 @safe unittest 10059 { 10060 import std.stdio : writeln; 10061 import std.traits : EnumMembers; 10062 foreach (badStr; ["Ja", "Janu", "Januar", "Januarys", "JJanuary", "JANUARY", 10063 "JAN", "january", "jaNuary", "jaN", "jaNuaRy", "jAn"]) 10064 { 10065 scope(failure) writeln(badStr); 10066 assertThrown!DateTimeException(monthFromString(badStr)); 10067 } 10068 10069 foreach (month; EnumMembers!Month) 10070 { 10071 scope(failure) writeln(month); 10072 assert(monthFromString(monthToString(month)) == month); 10073 } 10074 } 10075 10076 10077 version (unittest) 10078 { 10079 // All of these helper arrays are sorted in ascending order. 10080 auto testYearsBC = [-1999, -1200, -600, -4, -1, 0]; 10081 auto testYearsAD = [1, 4, 1000, 1999, 2000, 2012]; 10082 10083 // I'd use a Tuple, but I get forward reference errors if I try. 10084 struct MonthDay 10085 { 10086 Month month; 10087 short day; 10088 10089 this(int m, short d) 10090 { 10091 month = cast(Month) m; 10092 day = d; 10093 } 10094 } 10095 10096 MonthDay[] testMonthDays = [MonthDay(1, 1), 10097 MonthDay(1, 2), 10098 MonthDay(3, 17), 10099 MonthDay(7, 4), 10100 MonthDay(10, 27), 10101 MonthDay(12, 30), 10102 MonthDay(12, 31)]; 10103 10104 auto testDays = [1, 2, 9, 10, 16, 20, 25, 28, 29, 30, 31]; 10105 10106 auto testTODs = [TimeOfDay(0, 0, 0), 10107 TimeOfDay(0, 0, 1), 10108 TimeOfDay(0, 1, 0), 10109 TimeOfDay(1, 0, 0), 10110 TimeOfDay(13, 13, 13), 10111 TimeOfDay(23, 59, 59)]; 10112 10113 auto testHours = [0, 1, 12, 22, 23]; 10114 auto testMinSecs = [0, 1, 30, 58, 59]; 10115 10116 // Throwing exceptions is incredibly expensive, so we want to use a smaller 10117 // set of values for tests using assertThrown. 10118 auto testTODsThrown = [TimeOfDay(0, 0, 0), 10119 TimeOfDay(13, 13, 13), 10120 TimeOfDay(23, 59, 59)]; 10121 10122 Date[] testDatesBC; 10123 Date[] testDatesAD; 10124 10125 DateTime[] testDateTimesBC; 10126 DateTime[] testDateTimesAD; 10127 10128 // I'd use a Tuple, but I get forward reference errors if I try. 10129 struct GregDay { int day; Date date; } 10130 auto testGregDaysBC = [GregDay(-1_373_427, Date(-3760, 9, 7)), // Start of the Hebrew Calendar 10131 GregDay(-735_233, Date(-2012, 1, 1)), 10132 GregDay(-735_202, Date(-2012, 2, 1)), 10133 GregDay(-735_175, Date(-2012, 2, 28)), 10134 GregDay(-735_174, Date(-2012, 2, 29)), 10135 GregDay(-735_173, Date(-2012, 3, 1)), 10136 GregDay(-734_502, Date(-2010, 1, 1)), 10137 GregDay(-734_472, Date(-2010, 1, 31)), 10138 GregDay(-734_471, Date(-2010, 2, 1)), 10139 GregDay(-734_444, Date(-2010, 2, 28)), 10140 GregDay(-734_443, Date(-2010, 3, 1)), 10141 GregDay(-734_413, Date(-2010, 3, 31)), 10142 GregDay(-734_412, Date(-2010, 4, 1)), 10143 GregDay(-734_383, Date(-2010, 4, 30)), 10144 GregDay(-734_382, Date(-2010, 5, 1)), 10145 GregDay(-734_352, Date(-2010, 5, 31)), 10146 GregDay(-734_351, Date(-2010, 6, 1)), 10147 GregDay(-734_322, Date(-2010, 6, 30)), 10148 GregDay(-734_321, Date(-2010, 7, 1)), 10149 GregDay(-734_291, Date(-2010, 7, 31)), 10150 GregDay(-734_290, Date(-2010, 8, 1)), 10151 GregDay(-734_260, Date(-2010, 8, 31)), 10152 GregDay(-734_259, Date(-2010, 9, 1)), 10153 GregDay(-734_230, Date(-2010, 9, 30)), 10154 GregDay(-734_229, Date(-2010, 10, 1)), 10155 GregDay(-734_199, Date(-2010, 10, 31)), 10156 GregDay(-734_198, Date(-2010, 11, 1)), 10157 GregDay(-734_169, Date(-2010, 11, 30)), 10158 GregDay(-734_168, Date(-2010, 12, 1)), 10159 GregDay(-734_139, Date(-2010, 12, 30)), 10160 GregDay(-734_138, Date(-2010, 12, 31)), 10161 GregDay(-731_215, Date(-2001, 1, 1)), 10162 GregDay(-730_850, Date(-2000, 1, 1)), 10163 GregDay(-730_849, Date(-2000, 1, 2)), 10164 GregDay(-730_486, Date(-2000, 12, 30)), 10165 GregDay(-730_485, Date(-2000, 12, 31)), 10166 GregDay(-730_484, Date(-1999, 1, 1)), 10167 GregDay(-694_690, Date(-1901, 1, 1)), 10168 GregDay(-694_325, Date(-1900, 1, 1)), 10169 GregDay(-585_118, Date(-1601, 1, 1)), 10170 GregDay(-584_753, Date(-1600, 1, 1)), 10171 GregDay(-584_388, Date(-1600, 12, 31)), 10172 GregDay(-584_387, Date(-1599, 1, 1)), 10173 GregDay(-365_972, Date(-1001, 1, 1)), 10174 GregDay(-365_607, Date(-1000, 1, 1)), 10175 GregDay(-183_351, Date(-501, 1, 1)), 10176 GregDay(-182_986, Date(-500, 1, 1)), 10177 GregDay(-182_621, Date(-499, 1, 1)), 10178 GregDay(-146_827, Date(-401, 1, 1)), 10179 GregDay(-146_462, Date(-400, 1, 1)), 10180 GregDay(-146_097, Date(-400, 12, 31)), 10181 GregDay(-110_302, Date(-301, 1, 1)), 10182 GregDay(-109_937, Date(-300, 1, 1)), 10183 GregDay(-73_778, Date(-201, 1, 1)), 10184 GregDay(-73_413, Date(-200, 1, 1)), 10185 GregDay(-38_715, Date(-105, 1, 1)), 10186 GregDay(-37_254, Date(-101, 1, 1)), 10187 GregDay(-36_889, Date(-100, 1, 1)), 10188 GregDay(-36_524, Date(-99, 1, 1)), 10189 GregDay(-36_160, Date(-99, 12, 31)), 10190 GregDay(-35_794, Date(-97, 1, 1)), 10191 GregDay(-18_627, Date(-50, 1, 1)), 10192 GregDay(-18_262, Date(-49, 1, 1)), 10193 GregDay(-3652, Date(-9, 1, 1)), 10194 GregDay(-2191, Date(-5, 1, 1)), 10195 GregDay(-1827, Date(-5, 12, 31)), 10196 GregDay(-1826, Date(-4, 1, 1)), 10197 GregDay(-1825, Date(-4, 1, 2)), 10198 GregDay(-1462, Date(-4, 12, 30)), 10199 GregDay(-1461, Date(-4, 12, 31)), 10200 GregDay(-1460, Date(-3, 1, 1)), 10201 GregDay(-1096, Date(-3, 12, 31)), 10202 GregDay(-1095, Date(-2, 1, 1)), 10203 GregDay(-731, Date(-2, 12, 31)), 10204 GregDay(-730, Date(-1, 1, 1)), 10205 GregDay(-367, Date(-1, 12, 30)), 10206 GregDay(-366, Date(-1, 12, 31)), 10207 GregDay(-365, Date(0, 1, 1)), 10208 GregDay(-31, Date(0, 11, 30)), 10209 GregDay(-30, Date(0, 12, 1)), 10210 GregDay(-1, Date(0, 12, 30)), 10211 GregDay(0, Date(0, 12, 31))]; 10212 10213 auto testGregDaysAD = [GregDay(1, Date(1, 1, 1)), 10214 GregDay(2, Date(1, 1, 2)), 10215 GregDay(32, Date(1, 2, 1)), 10216 GregDay(365, Date(1, 12, 31)), 10217 GregDay(366, Date(2, 1, 1)), 10218 GregDay(731, Date(3, 1, 1)), 10219 GregDay(1096, Date(4, 1, 1)), 10220 GregDay(1097, Date(4, 1, 2)), 10221 GregDay(1460, Date(4, 12, 30)), 10222 GregDay(1461, Date(4, 12, 31)), 10223 GregDay(1462, Date(5, 1, 1)), 10224 GregDay(17_898, Date(50, 1, 1)), 10225 GregDay(35_065, Date(97, 1, 1)), 10226 GregDay(36_160, Date(100, 1, 1)), 10227 GregDay(36_525, Date(101, 1, 1)), 10228 GregDay(37_986, Date(105, 1, 1)), 10229 GregDay(72_684, Date(200, 1, 1)), 10230 GregDay(73_049, Date(201, 1, 1)), 10231 GregDay(109_208, Date(300, 1, 1)), 10232 GregDay(109_573, Date(301, 1, 1)), 10233 GregDay(145_732, Date(400, 1, 1)), 10234 GregDay(146_098, Date(401, 1, 1)), 10235 GregDay(182_257, Date(500, 1, 1)), 10236 GregDay(182_622, Date(501, 1, 1)), 10237 GregDay(364_878, Date(1000, 1, 1)), 10238 GregDay(365_243, Date(1001, 1, 1)), 10239 GregDay(584_023, Date(1600, 1, 1)), 10240 GregDay(584_389, Date(1601, 1, 1)), 10241 GregDay(693_596, Date(1900, 1, 1)), 10242 GregDay(693_961, Date(1901, 1, 1)), 10243 GregDay(729_755, Date(1999, 1, 1)), 10244 GregDay(730_120, Date(2000, 1, 1)), 10245 GregDay(730_121, Date(2000, 1, 2)), 10246 GregDay(730_484, Date(2000, 12, 30)), 10247 GregDay(730_485, Date(2000, 12, 31)), 10248 GregDay(730_486, Date(2001, 1, 1)), 10249 GregDay(733_773, Date(2010, 1, 1)), 10250 GregDay(733_774, Date(2010, 1, 2)), 10251 GregDay(733_803, Date(2010, 1, 31)), 10252 GregDay(733_804, Date(2010, 2, 1)), 10253 GregDay(733_831, Date(2010, 2, 28)), 10254 GregDay(733_832, Date(2010, 3, 1)), 10255 GregDay(733_862, Date(2010, 3, 31)), 10256 GregDay(733_863, Date(2010, 4, 1)), 10257 GregDay(733_892, Date(2010, 4, 30)), 10258 GregDay(733_893, Date(2010, 5, 1)), 10259 GregDay(733_923, Date(2010, 5, 31)), 10260 GregDay(733_924, Date(2010, 6, 1)), 10261 GregDay(733_953, Date(2010, 6, 30)), 10262 GregDay(733_954, Date(2010, 7, 1)), 10263 GregDay(733_984, Date(2010, 7, 31)), 10264 GregDay(733_985, Date(2010, 8, 1)), 10265 GregDay(734_015, Date(2010, 8, 31)), 10266 GregDay(734_016, Date(2010, 9, 1)), 10267 GregDay(734_045, Date(2010, 9, 30)), 10268 GregDay(734_046, Date(2010, 10, 1)), 10269 GregDay(734_076, Date(2010, 10, 31)), 10270 GregDay(734_077, Date(2010, 11, 1)), 10271 GregDay(734_106, Date(2010, 11, 30)), 10272 GregDay(734_107, Date(2010, 12, 1)), 10273 GregDay(734_136, Date(2010, 12, 30)), 10274 GregDay(734_137, Date(2010, 12, 31)), 10275 GregDay(734_503, Date(2012, 1, 1)), 10276 GregDay(734_534, Date(2012, 2, 1)), 10277 GregDay(734_561, Date(2012, 2, 28)), 10278 GregDay(734_562, Date(2012, 2, 29)), 10279 GregDay(734_563, Date(2012, 3, 1)), 10280 GregDay(734_858, Date(2012, 12, 21))]; 10281 10282 // I'd use a Tuple, but I get forward reference errors if I try. 10283 struct DayOfYear { int day; MonthDay md; } 10284 auto testDaysOfYear = [DayOfYear(1, MonthDay(1, 1)), 10285 DayOfYear(2, MonthDay(1, 2)), 10286 DayOfYear(3, MonthDay(1, 3)), 10287 DayOfYear(31, MonthDay(1, 31)), 10288 DayOfYear(32, MonthDay(2, 1)), 10289 DayOfYear(59, MonthDay(2, 28)), 10290 DayOfYear(60, MonthDay(3, 1)), 10291 DayOfYear(90, MonthDay(3, 31)), 10292 DayOfYear(91, MonthDay(4, 1)), 10293 DayOfYear(120, MonthDay(4, 30)), 10294 DayOfYear(121, MonthDay(5, 1)), 10295 DayOfYear(151, MonthDay(5, 31)), 10296 DayOfYear(152, MonthDay(6, 1)), 10297 DayOfYear(181, MonthDay(6, 30)), 10298 DayOfYear(182, MonthDay(7, 1)), 10299 DayOfYear(212, MonthDay(7, 31)), 10300 DayOfYear(213, MonthDay(8, 1)), 10301 DayOfYear(243, MonthDay(8, 31)), 10302 DayOfYear(244, MonthDay(9, 1)), 10303 DayOfYear(273, MonthDay(9, 30)), 10304 DayOfYear(274, MonthDay(10, 1)), 10305 DayOfYear(304, MonthDay(10, 31)), 10306 DayOfYear(305, MonthDay(11, 1)), 10307 DayOfYear(334, MonthDay(11, 30)), 10308 DayOfYear(335, MonthDay(12, 1)), 10309 DayOfYear(363, MonthDay(12, 29)), 10310 DayOfYear(364, MonthDay(12, 30)), 10311 DayOfYear(365, MonthDay(12, 31))]; 10312 10313 auto testDaysOfLeapYear = [DayOfYear(1, MonthDay(1, 1)), 10314 DayOfYear(2, MonthDay(1, 2)), 10315 DayOfYear(3, MonthDay(1, 3)), 10316 DayOfYear(31, MonthDay(1, 31)), 10317 DayOfYear(32, MonthDay(2, 1)), 10318 DayOfYear(59, MonthDay(2, 28)), 10319 DayOfYear(60, MonthDay(2, 29)), 10320 DayOfYear(61, MonthDay(3, 1)), 10321 DayOfYear(91, MonthDay(3, 31)), 10322 DayOfYear(92, MonthDay(4, 1)), 10323 DayOfYear(121, MonthDay(4, 30)), 10324 DayOfYear(122, MonthDay(5, 1)), 10325 DayOfYear(152, MonthDay(5, 31)), 10326 DayOfYear(153, MonthDay(6, 1)), 10327 DayOfYear(182, MonthDay(6, 30)), 10328 DayOfYear(183, MonthDay(7, 1)), 10329 DayOfYear(213, MonthDay(7, 31)), 10330 DayOfYear(214, MonthDay(8, 1)), 10331 DayOfYear(244, MonthDay(8, 31)), 10332 DayOfYear(245, MonthDay(9, 1)), 10333 DayOfYear(274, MonthDay(9, 30)), 10334 DayOfYear(275, MonthDay(10, 1)), 10335 DayOfYear(305, MonthDay(10, 31)), 10336 DayOfYear(306, MonthDay(11, 1)), 10337 DayOfYear(335, MonthDay(11, 30)), 10338 DayOfYear(336, MonthDay(12, 1)), 10339 DayOfYear(364, MonthDay(12, 29)), 10340 DayOfYear(365, MonthDay(12, 30)), 10341 DayOfYear(366, MonthDay(12, 31))]; 10342 10343 void initializeTests() @safe 10344 { 10345 foreach (year; testYearsBC) 10346 { 10347 foreach (md; testMonthDays) 10348 testDatesBC ~= Date(year, md.month, md.day); 10349 } 10350 10351 foreach (year; testYearsAD) 10352 { 10353 foreach (md; testMonthDays) 10354 testDatesAD ~= Date(year, md.month, md.day); 10355 } 10356 10357 foreach (dt; testDatesBC) 10358 { 10359 foreach (tod; testTODs) 10360 testDateTimesBC ~= DateTime(dt, tod); 10361 } 10362 10363 foreach (dt; testDatesAD) 10364 { 10365 foreach (tod; testTODs) 10366 testDateTimesAD ~= DateTime(dt, tod); 10367 } 10368 } 10369 } 10370