1 /****************************************************************************** 2 3 Copyright: 4 Copyright (c) 2007 Tango contributors. 5 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH. 6 All rights reserved. 7 8 License: 9 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0. 10 See LICENSE_TANGO.txt for details. 11 12 Version: 13 mid 2005: Initial release 14 Apr 2007: heavily reshaped 15 Dec 2007: moved to ocean.time 16 17 Authors: John Chapman, Kris, scheivguy 18 19 ******************************************************************************/ 20 21 module ocean.time.Time; 22 23 import core.time; 24 import core.stdc.time: time_t; 25 import ocean.meta.types.Qualifiers; 26 27 version (unittest) 28 { 29 import core.stdc.time; 30 import ocean.core.Test; 31 } 32 33 /****************************************************************************** 34 35 This struct represents a length of time. The underlying representation is 36 in units of 100ns. This allows the length of time to span to roughly 37 +/- 10000 years. 38 39 Notably missing from this is a representation of weeks, months and years. 40 This is because weeks, months, and years vary according to local calendars. 41 Use ocean.time.chrono.* to deal with these concepts. 42 43 Note: nobody should change this struct without really good reason as it is 44 required to be a part of some interfaces. It should be treated as a 45 builtin type. Also note that there is deliberately no opCall constructor 46 here, since it tends to produce too much overhead. If you wish to build 47 a TimeSpan struct from a ticks value, use D's builtin ability to create a 48 struct with given member values (See the description of ticks() for an 49 example of how to do this). 50 51 Example: 52 ------------------- 53 Time start = Clock.now; 54 Thread.sleep(0.150); 55 Stdout.formatln("slept for {} ms", (Clock.now-start).millis); 56 ------------------- 57 58 See_Also: ocean.core.Thread, ocean.time.Clock 59 60 ******************************************************************************/ 61 62 struct TimeSpan 63 { 64 // this is the only member of the struct. 65 package Duration duration_; 66 67 /// Convenience function (older compilers don't allow public alias to package) 68 public Duration duration () const { return this.duration_; } 69 /// Allow implicit conversion from `TimeSpan` to `Duration` 70 alias duration this; 71 72 // useful constants. Shouldn't be used in normal code, use the 73 // static TimeSpan members below instead. i.e. instead of 74 // TimeSpan.TicksPerSecond, use TimeSpan.second.ticks 75 // 76 enum : long 77 { 78 /// basic tick values 79 NanosecondsPerTick = 100, 80 TicksPerMicrosecond = 1000 / NanosecondsPerTick, 81 TicksPerMillisecond = 1000 * TicksPerMicrosecond, 82 TicksPerSecond = 1000 * TicksPerMillisecond, 83 TicksPerMinute = 60 * TicksPerSecond, 84 TicksPerHour = 60 * TicksPerMinute, 85 TicksPerDay = 24 * TicksPerHour, 86 87 // millisecond counts 88 MillisPerSecond = 1000, 89 MillisPerMinute = MillisPerSecond * 60, 90 MillisPerHour = MillisPerMinute * 60, 91 MillisPerDay = MillisPerHour * 24, 92 93 /// day counts 94 DaysPerYear = 365, 95 DaysPer4Years = DaysPerYear * 4 + 1, 96 DaysPer100Years = DaysPer4Years * 25 - 1, 97 DaysPer400Years = DaysPer100Years * 4 + 1, 98 99 // epoch counts 100 Epoch1601 = DaysPer400Years * 4 * TicksPerDay, 101 Epoch1970 = Epoch1601 + TicksPerSecond * 11644473600L, 102 } 103 104 /** 105 * Minimum TimeSpan 106 */ 107 enum TimeSpan min = TimeSpan(Duration.min); 108 109 /** 110 * Maximum TimeSpan 111 */ 112 enum TimeSpan max = TimeSpan(Duration.max); 113 114 /** 115 * Zero TimeSpan. Useful for comparisons. 116 */ 117 enum TimeSpan zero = TimeSpan(Duration.zero); 118 119 /// Compatibility constructors 120 public this (long ticks) 121 { 122 this.duration_ = ticks.hnsecs; 123 } 124 125 /// 126 public this (Duration dur) 127 { 128 this.duration_ = dur; 129 } 130 131 /** 132 * Get the number of ticks that this timespan represents. 133 * 134 * A tick correspond to an hecto-nanosecond, or 100ns. 135 * This is the way this struct stores data internally, 136 * which is the representation `core.time : Duration` uses. 137 * 138 * This method can be used to construct another `TimeSpan`: 139 * -------- 140 * long ticks = myTimeSpan.ticks; 141 * TimeSpan copyOfMyTimeSpan = TimeSpan(ticks); 142 * -------- 143 * 144 * See_Also: 145 * https://dlang.org/phobos/core_time.html 146 */ 147 long ticks() 148 { 149 return this.duration_.total!"hnsecs"; 150 } 151 152 /** 153 * Determines whether two TimeSpan values are equal 154 */ 155 equals_t opEquals(TimeSpan t) 156 { 157 return this.duration_ == t.duration_; 158 } 159 160 /** 161 * Compares this object against another TimeSpan value. 162 */ 163 public int opCmp ( const typeof(this) rhs ) const 164 { 165 return this.duration_.opCmp(rhs.duration_); 166 } 167 168 /** 169 * Add or subtract the TimeSpan given to this TimeSpan returning a 170 * new TimeSpan. 171 * 172 * Params: op = operation to perform 173 * t = A TimeSpan value to add or subtract 174 * Returns: A TimeSpan value that is the result of this instance, the 175 * operation, and t. 176 */ 177 TimeSpan opBinary (string op) (TimeSpan t) if (op == "+" || op == "-") 178 { 179 mixin("return TimeSpan(this.duration_ " ~ op ~ " t.duration_);"); 180 } 181 182 unittest 183 { 184 TimeSpan time_span; 185 time_span.duration_ = 5.hnsecs; 186 187 TimeSpan test_span; 188 test_span.duration_ = 10.hnsecs; 189 190 auto res = time_span + test_span; 191 test!("==")(res.ticks(), 15); 192 193 test_span.duration_ = 3.hnsecs; 194 195 res = time_span - test_span; 196 test!("==")(res.ticks(), 2); 197 } 198 199 /** 200 * Add or subtract the specified TimeSpan to this TimeSpan, assigning 201 * the result to this instance. 202 * 203 * Params: op = operation to perform 204 * t = A TimeSpan value to add or subtract 205 * Returns: a copy of this instance after adding or subtracting t. 206 */ 207 208 TimeSpan opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-") 209 { 210 mixin("duration_ " ~ op ~ "= t.duration_;"); 211 return this; 212 } 213 214 unittest 215 { 216 TimeSpan time_span; 217 time_span.duration_ = 5.hnsecs; 218 219 TimeSpan test_span; 220 test_span.duration_ = 10.hnsecs; 221 222 time_span += test_span; 223 test!("==")(time_span.ticks(), 15); 224 225 test_span.duration_ = 3.hnsecs; 226 227 time_span -= test_span; 228 test!("==")(time_span.ticks(), 12); 229 } 230 231 /** 232 * Scale the TimeSpan by the specified amount. This should not be 233 * used to convert to a different unit. Use the unit accessors 234 * instead. This should only be used as a scaling mechanism. For 235 * example, if you have a timeout and you want to sleep for twice the 236 * timeout, you would use timeout * 2. Returns a new TimeSpan. 237 * 238 * Params: op = operation to perform 239 * v = A multiplier or divisor to use for scaling this time span. 240 * Returns: A new TimeSpan that is scaled by v 241 */ 242 TimeSpan opBinary (string op) (long v) if (op == "*" || op == "/") 243 { 244 mixin("return TimeSpan(duration_ " ~ op ~ " v);"); 245 } 246 247 unittest 248 { 249 TimeSpan time_span; 250 time_span.duration_ = 5.hnsecs; 251 252 auto res = time_span * 10; 253 test!("==")(res.ticks(), 50); 254 255 res = time_span / 5; 256 test!("==")(res.ticks(), 1); 257 } 258 259 /** 260 * Scales this TimeSpan and assigns the result to this instance. 261 * 262 * Params: op = operation to perform 263 * v = A multipler or divisor to use for scaling 264 * Returns: A copy of this instance after scaling 265 */ 266 TimeSpan opOpAssign (string op) (long v) if (op == "*" || op == "/") 267 { 268 mixin("duration_ " ~ op ~ "= v;"); 269 return this; 270 } 271 272 unittest 273 { 274 TimeSpan time_span; 275 time_span.duration_ = 5.hnsecs; 276 277 time_span *= 10; 278 test!("==")(time_span.ticks(), 50); 279 280 time_span /= 5; 281 test!("==")(time_span.ticks(), 10); 282 } 283 284 /** 285 * Perform integer division with the given time span. 286 * 287 * Params: op = operation to perform 288 * t = A divisor used for dividing 289 * Returns: The result of integer division between this instance and 290 * t. 291 */ 292 long opBinary (string op) (TimeSpan t) if (op == "/") 293 { 294 return duration_ / t.duration_; 295 } 296 297 unittest 298 { 299 TimeSpan time_span; 300 time_span.duration_ = 10.hnsecs; 301 302 TimeSpan test_span; 303 test_span.duration_ = 5.hnsecs; 304 305 test!("==")(time_span / test_span, 2); 306 } 307 308 /** 309 * Negate a time span. Returns a new TimeSpan. 310 * 311 * Params: op = operation to perform 312 * Returns: The negative equivalent to this time span 313 */ 314 TimeSpan opUnary (string op) () if (op == "-") 315 { 316 return TimeSpan(-duration_); 317 } 318 319 unittest 320 { 321 TimeSpan time_span; 322 time_span.duration_ = 10.hnsecs; 323 324 auto res = (-time_span); 325 326 test!("==")(res.ticks(), -10); 327 } 328 329 /** 330 * Convert to nanoseconds 331 * 332 * Note: this may incur loss of data because nanoseconds cannot 333 * represent the range of data a TimeSpan can represent. 334 * 335 * Returns: The number of nanoseconds that this TimeSpan represents. 336 */ 337 long nanos() 338 { 339 return duration_.total!"nsecs"; 340 } 341 342 /** 343 * Convert to microseconds 344 * 345 * Returns: The number of microseconds that this TimeSpan represents. 346 */ 347 long micros() 348 { 349 return duration_.total!"usecs"; 350 } 351 352 /** 353 * Convert to milliseconds 354 * 355 * Returns: The number of milliseconds that this TimeSpan represents. 356 */ 357 long millis() 358 { 359 return duration_.total!"msecs"; 360 } 361 362 /** 363 * Convert to seconds 364 * 365 * Returns: The number of seconds that this TimeSpan represents. 366 */ 367 long seconds() 368 { 369 return duration_.total!"seconds"; 370 } 371 372 /** 373 * Convert to minutes 374 * 375 * Returns: The number of minutes that this TimeSpan represents. 376 */ 377 long minutes() 378 { 379 return duration_.total!"minutes"; 380 } 381 382 /** 383 * Convert to hours 384 * 385 * Returns: The number of hours that this TimeSpan represents. 386 */ 387 long hours() 388 { 389 return duration_.total!"hours"; 390 } 391 392 /** 393 * Convert to days 394 * 395 * Returns: The number of days that this TimeSpan represents. 396 */ 397 long days() 398 { 399 return duration_.total!"days"; 400 } 401 402 /** 403 * Convert to a floating point interval representing seconds. 404 * 405 * Note: This may cause a loss of precision as a double cannot exactly 406 * represent some fractional values. 407 * 408 * Returns: An interval representing the seconds and fractional 409 * seconds that this TimeSpan represents. 410 */ 411 double interval() 412 { 413 return (cast(double) duration_.total!"hnsecs") / TicksPerSecond; 414 } 415 416 /** 417 * Convert to TimeOfDay 418 * 419 * Returns: the TimeOfDay this TimeSpan represents. 420 */ 421 TimeOfDay time() 422 { 423 return TimeOfDay(duration_); 424 } 425 426 /** 427 * Construct a TimeSpan from the given number of nanoseconds 428 * 429 * Note: This may cause a loss of data since a TimeSpan's resolution 430 * is in 100ns increments. 431 * 432 * Params: value = The number of nanoseconds. 433 * Returns: A TimeSpan representing the given number of nanoseconds. 434 */ 435 static TimeSpan fromNanos(long value) 436 { 437 return TimeSpan(value.dur!"nsecs"); 438 } 439 440 /** 441 * Construct a TimeSpan from the given number of microseconds 442 * 443 * Params: value = The number of microseconds. 444 * Returns: A TimeSpan representing the given number of microseconds. 445 */ 446 static TimeSpan fromMicros(long value) 447 { 448 return TimeSpan(value.dur!"usecs"); 449 } 450 451 /** 452 * Construct a TimeSpan from the given number of milliseconds 453 * 454 * Params: value = The number of milliseconds. 455 * Returns: A TimeSpan representing the given number of milliseconds. 456 */ 457 static TimeSpan fromMillis(long value) 458 { 459 return TimeSpan(value.dur!"msecs"); 460 } 461 462 /** 463 * Construct a TimeSpan from the given number of seconds 464 * 465 * Params: value = The number of seconds. 466 * Returns: A TimeSpan representing the given number of seconds. 467 */ 468 static TimeSpan fromSeconds(long value) 469 { 470 return TimeSpan(value.dur!"seconds"); 471 } 472 473 /** 474 * Construct a TimeSpan from the given number of minutes 475 * 476 * Params: value = The number of minutes. 477 * Returns: A TimeSpan representing the given number of minutes. 478 */ 479 static TimeSpan fromMinutes(long value) 480 { 481 return TimeSpan(value.dur!"minutes"); 482 } 483 484 /** 485 * Construct a TimeSpan from the given number of hours 486 * 487 * Params: value = The number of hours. 488 * Returns: A TimeSpan representing the given number of hours. 489 */ 490 static TimeSpan fromHours(long value) 491 { 492 return TimeSpan(value.dur!"hours"); 493 } 494 495 /** 496 * Construct a TimeSpan from the given number of days 497 * 498 * Params: value = The number of days. 499 * Returns: A TimeSpan representing the given number of days. 500 */ 501 static TimeSpan fromDays(long value) 502 { 503 return TimeSpan(value.dur!"days"); 504 } 505 506 /** 507 * Construct a TimeSpan from the given interval. The interval 508 * represents seconds as a double. This allows both whole and 509 * fractional seconds to be passed in. 510 * 511 * Params: sec = The interval to convert in seconds. 512 * Returns: A TimeSpan representing the given interval. 513 */ 514 static TimeSpan fromInterval(double sec) 515 { 516 return TimeSpan((cast(long)(sec * TicksPerSecond + .1)).dur!"hnsecs"); 517 } 518 } 519 520 521 /****************************************************************************** 522 523 Represents a point in time. 524 525 Remarks: Time represents dates and times between 12:00:00 526 midnight on January 1, 10000 BC and 11:59:59 PM on December 31, 527 9999 AD. 528 529 Time values are measured in 100-nanosecond intervals, or ticks. 530 A date value is the number of ticks that have elapsed since 531 12:00:00 midnight on January 1, 0001 AD in the Gregorian 532 calendar. 533 534 Negative Time values are offsets from that same reference point, 535 but backwards in history. Time values are not specific to any 536 calendar, but for an example, the beginning of December 31, 1 BC 537 in the Gregorian calendar is Time.epoch - TimeSpan.days(1). 538 539 ******************************************************************************/ 540 541 struct Time 542 { 543 private long ticks_; 544 545 private enum : long 546 { 547 maximum = (TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1, 548 minimum = -((TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1), 549 } 550 551 /// Represents the smallest and largest Time value. 552 enum Time min = {minimum}, 553 max = {maximum}; 554 555 /// Represents the epoch (1/1/0001) 556 enum Time epoch = {0}; 557 558 /// Represents the epoch of 1/1/1601 (Commonly used in Windows systems) 559 enum Time epoch1601 = {TimeSpan.Epoch1601}; 560 561 /// Represents the epoch of 1/1/1970 (Commonly used in Unix systems) 562 enum Time epoch1970 = {TimeSpan.Epoch1970}; 563 564 /********************************************************************** 565 566 $(I Property.) Retrieves the number of ticks for this Time. 567 This value can be used to construct another Time struct by 568 writing: 569 570 --------- 571 long ticks = myTime.ticks; 572 Time copyOfMyTime = Time(ticks); 573 --------- 574 575 576 Returns: A long represented by the time of this 577 instance. 578 579 **********************************************************************/ 580 581 long ticks () 582 { 583 return ticks_; 584 } 585 586 /********************************************************************** 587 588 Determines whether two Time values are equal. 589 590 Params: t = A Time _value. 591 Returns: true if both instances are equal; otherwise, false 592 593 **********************************************************************/ 594 595 int opEquals (Time t) 596 { 597 return ticks_ is t.ticks_; 598 } 599 600 /********************************************************************** 601 602 Compares two Time values. 603 604 **********************************************************************/ 605 606 int opCmp (Time t) 607 { 608 if (ticks_ < t.ticks_) 609 return -1; 610 611 if (ticks_ > t.ticks_) 612 return 1; 613 614 return 0; 615 } 616 617 /********************************************************************** 618 619 Adds or subtracts the specified time span to the time, 620 returning a new time. 621 622 Params: op = operation to perform 623 t = A TimeSpan value. 624 Returns: A Time that is the sum or difference of this instance 625 and t. 626 627 **********************************************************************/ 628 629 Time opBinary (string op) (TimeSpan t) if (op == "+" || op == "-") 630 { 631 mixin("return Time(ticks_ " ~ op ~ " t.duration_.total!`hnsecs`);"); 632 } 633 634 unittest 635 { 636 Time time_span; 637 time_span.ticks_ = 5; 638 639 TimeSpan test_span; 640 test_span.duration_ = 10.dur!"hnsecs"; 641 642 auto res = time_span + test_span; 643 test!("==")(res.ticks(), 15); 644 645 test_span.duration_ = 3.dur!"hnsecs"; 646 647 res = time_span - test_span; 648 test!("==")(res.ticks(), 2); 649 } 650 651 /********************************************************************** 652 653 Adds or subtracts the specified time span to the time, assigning 654 the result to this instance. 655 656 Params: op = operation to perform 657 t = A TimeSpan value. 658 Returns: The current Time instance, with t added or subtracted 659 to the time. 660 661 **********************************************************************/ 662 663 Time opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-") 664 { 665 mixin("ticks_ " ~ op ~ "= t.duration_.total!`hnsecs`;"); 666 return this; 667 } 668 669 unittest 670 { 671 Time time_span; 672 time_span.ticks_ = 5; 673 674 TimeSpan test_span; 675 test_span.duration_ = 10.dur!"hnsecs"; 676 677 time_span += test_span; 678 test!("==")(time_span.ticks(), 15); 679 680 test_span.duration_ = 3.dur!"hnsecs"; 681 682 time_span -= test_span; 683 test!("==")(time_span.ticks(), 12); 684 } 685 686 /********************************************************************** 687 688 Returns a time span which represents the difference in time 689 between this and the given Time. 690 691 Params: op = operation to perform 692 t = A Time value. 693 Returns: A TimeSpan which represents the difference between 694 this and t. 695 696 **********************************************************************/ 697 698 TimeSpan opBinary (string op) (Time t) if (op == "-") 699 { 700 return TimeSpan((ticks - t.ticks_).dur!"hnsecs"); 701 } 702 703 unittest 704 { 705 Time time_span; 706 time_span.ticks_ = 5; 707 708 TimeSpan test_span; 709 test_span.duration_ = 3.dur!"hnsecs"; 710 711 auto res = time_span - test_span; 712 test!("==")(res.ticks(), 2); 713 } 714 715 /********************************************************************** 716 717 $(I Property.) Retrieves the date component. 718 719 Returns: A new Time instance with the same date as 720 this instance, but with the time truncated. 721 722 **********************************************************************/ 723 724 Time date () 725 { 726 return this - TimeOfDay.modulo24(ticks_); 727 } 728 729 /********************************************************************** 730 731 $(I Property.) Retrieves the time of day. 732 733 Returns: A TimeOfDay representing the fraction of the day 734 elapsed since midnight. 735 736 **********************************************************************/ 737 738 TimeOfDay time () 739 { 740 return TimeOfDay (ticks_); 741 } 742 743 /********************************************************************** 744 745 $(I Property.) Retrieves the equivalent TimeSpan. 746 747 Returns: A TimeSpan representing this Time. 748 749 **********************************************************************/ 750 751 TimeSpan span () 752 { 753 return TimeSpan (ticks_); 754 } 755 756 /********************************************************************** 757 758 $(I Property.) Retrieves a TimeSpan that corresponds to Unix 759 time (time since 1/1/1970). Use the TimeSpan accessors to get 760 the time in seconds, milliseconds, etc. 761 762 Returns: A TimeSpan representing this Time as Unix time. 763 764 ------------------------------------- 765 auto unixTime = Clock.now.unix.seconds; 766 auto javaTime = Clock.now.unix.millis; 767 ------------------------------------- 768 769 **********************************************************************/ 770 771 TimeSpan unix() 772 { 773 return TimeSpan(ticks_ - epoch1970.ticks_); 774 } 775 776 /********************************************************************** 777 778 Constructs a Time instance from the Unix time (time since 1/1/1970). 779 780 Params: 781 unix_time = number of seconds since 1/1/1970 782 783 Returns: 784 Time instance corresponding the given unix time. 785 786 ***********************************************************************/ 787 788 static Time fromUnixTime (time_t unix_time) 789 { 790 return Time(epoch1970.ticks_ + unix_time * TimeSpan.TicksPerSecond); 791 } 792 } 793 794 795 /****************************************************************************** 796 797 Represents a time of day. This is different from TimeSpan in that 798 each component is represented within the limits of everyday time, 799 rather than from the start of the Epoch. Effectively, the TimeOfDay 800 epoch is the first second of each day. 801 802 This is handy for dealing strictly with a 24-hour clock instead of 803 potentially thousands of years. For example: 804 --- 805 auto time = Clock.now.time; 806 assert (time.millis < 1000); 807 assert (time.seconds < 60); 808 assert (time.minutes < 60); 809 assert (time.hours < 24); 810 --- 811 812 You can create a TimeOfDay from an existing Time or TimeSpan instance 813 via the respective time() method. To convert back to a TimeSpan, use 814 the span() method 815 816 ******************************************************************************/ 817 818 struct TimeOfDay 819 { 820 /** 821 * hours component of the time of day. This should be between 0 and 822 * 23, inclusive. 823 */ 824 public uint hours; 825 826 /** 827 * minutes component of the time of day. This should be between 0 and 828 * 59, inclusive. 829 */ 830 public uint minutes; 831 832 /** 833 * seconds component of the time of day. This should be between 0 and 834 * 59, inclusive. 835 */ 836 public uint seconds; 837 838 /** 839 * milliseconds component of the time of day. This should be between 840 * 0 and 999, inclusive. 841 */ 842 public uint millis; 843 844 /** 845 * constructor. 846 * Params: hours = number of hours since midnight 847 * minutes = number of minutes into the hour 848 * seconds = number of seconds into the minute 849 * millis = number of milliseconds into the second 850 * 851 * Returns: a TimeOfDay representing the given time fields. 852 * 853 * Note: There is no verification of the range of values, or 854 * normalization made. So if you pass in larger values than the 855 * maximum value for that field, they will be stored as that value. 856 * 857 * example: 858 * -------------- 859 * auto tod = TimeOfDay(100, 100, 100, 10000); 860 * assert(tod.hours == 100); 861 * assert(tod.minutes == 100); 862 * assert(tod.seconds == 100); 863 * assert(tod.millis == 10000); 864 * -------------- 865 */ 866 static TimeOfDay opCall (uint hours, uint minutes, uint seconds, uint millis=0) 867 { 868 TimeOfDay t = void; 869 t.hours = hours; 870 t.minutes = minutes; 871 t.seconds = seconds; 872 t.millis = millis; 873 return t; 874 } 875 876 /** 877 * constructor. 878 * Params: ticks = ticks representing a Time value. This is normalized 879 * so that it represent a time of day (modulo-24 etc) 880 * 881 * Returns: a TimeOfDay value that corresponds to the time of day of 882 * the given number of ticks. 883 */ 884 static TimeOfDay opCall (long ticks) 885 { 886 return TimeOfDay(modulo24(ticks)); 887 } 888 889 /// Ditto 890 static TimeOfDay opCall (Duration dur) 891 { 892 // Note: Since this represents a time of day, hours needs to be 893 // 0 <= hours < 24. Using `days` ensures that, even if we don't 894 // use the value. 895 auto splitted = dur.split!("days", "hours", "minutes", "seconds", "msecs"); 896 return TimeOfDay(cast(uint)splitted.hours, cast(uint)splitted.minutes, 897 cast(uint)splitted.seconds, cast(uint)splitted.msecs); 898 } 899 900 /** 901 * construct a TimeSpan from the current fields 902 * 903 * Returns: a TimeOfDay representing the field values. 904 * 905 * Note: that fields are not checked against a valid range, so 906 * setting 60 for minutes is allowed, and will just add 1 to the hour 907 * component, and set the minute component to 0. The result is 908 * normalized, so the hours wrap. If you pass in 25 hours, the 909 * resulting TimeOfDay will have a hour component of 1. 910 */ 911 TimeSpan span () 912 { 913 return TimeSpan.fromHours(hours) + 914 TimeSpan.fromMinutes(minutes) + 915 TimeSpan.fromSeconds(seconds) + 916 TimeSpan.fromMillis(millis); 917 } 918 919 /** 920 * internal routine to adjust ticks by one day. Also adjusts for 921 * offsets in the BC era 922 */ 923 package static TimeSpan modulo24 (long ticks) 924 { 925 ticks %= TimeSpan.TicksPerDay; 926 if (ticks < 0) 927 ticks += TimeSpan.TicksPerDay; 928 return TimeSpan (ticks); 929 } 930 } 931 932 /****************************************************************************** 933 934 Generic Date representation 935 936 ******************************************************************************/ 937 938 struct Date 939 { 940 public uint era, /// AD, BC 941 day, /// 1 .. 31 942 year, /// 0 to 9999 943 month, /// 1 .. 12 944 dow, /// 0 .. 6 945 doy; /// 1 .. 366 946 } 947 948 949 /****************************************************************************** 950 951 Combination of a Date and a TimeOfDay 952 953 ******************************************************************************/ 954 955 struct DateTime 956 { 957 public Date date; /// date representation 958 public TimeOfDay time; /// time representation 959 } 960 961 unittest 962 { 963 auto unix = time(null); 964 965 test!("==")((Time.fromUnixTime(unix) - Time.epoch1970).seconds, unix); 966 }