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 public bool opEquals (in TimeSpan t) const scope 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 scope 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 public TimeSpan opBinary (string op) (in TimeSpan t) const scope 178 if (op == "+" || op == "-") 179 { 180 mixin("return TimeSpan(this.duration_ " ~ op ~ " t.duration_);"); 181 } 182 183 unittest 184 { 185 TimeSpan time_span; 186 time_span.duration_ = 5.hnsecs; 187 188 TimeSpan test_span; 189 test_span.duration_ = 10.hnsecs; 190 191 auto res = time_span + test_span; 192 test!("==")(res.ticks(), 15); 193 194 test_span.duration_ = 3.hnsecs; 195 196 res = time_span - test_span; 197 test!("==")(res.ticks(), 2); 198 } 199 200 /** 201 * Add or subtract the specified TimeSpan to this TimeSpan, assigning 202 * the result to this instance. 203 * 204 * Params: op = operation to perform 205 * t = A TimeSpan value to add or subtract 206 * Returns: a copy of this instance after adding or subtracting t. 207 */ 208 209 TimeSpan opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-") 210 { 211 mixin("duration_ " ~ op ~ "= t.duration_;"); 212 return this; 213 } 214 215 unittest 216 { 217 TimeSpan time_span; 218 time_span.duration_ = 5.hnsecs; 219 220 TimeSpan test_span; 221 test_span.duration_ = 10.hnsecs; 222 223 time_span += test_span; 224 test!("==")(time_span.ticks(), 15); 225 226 test_span.duration_ = 3.hnsecs; 227 228 time_span -= test_span; 229 test!("==")(time_span.ticks(), 12); 230 } 231 232 /** 233 * Scale the TimeSpan by the specified amount. This should not be 234 * used to convert to a different unit. Use the unit accessors 235 * instead. This should only be used as a scaling mechanism. For 236 * example, if you have a timeout and you want to sleep for twice the 237 * timeout, you would use timeout * 2. Returns a new TimeSpan. 238 * 239 * Params: op = operation to perform 240 * v = A multiplier or divisor to use for scaling this time span. 241 * Returns: A new TimeSpan that is scaled by v 242 */ 243 public TimeSpan opBinary (string op) (long v) const scope 244 if (op == "*" || op == "/") 245 { 246 mixin("return TimeSpan(duration_ " ~ op ~ " v);"); 247 } 248 249 unittest 250 { 251 TimeSpan time_span; 252 time_span.duration_ = 5.hnsecs; 253 254 auto res = time_span * 10; 255 test!("==")(res.ticks(), 50); 256 257 res = time_span / 5; 258 test!("==")(res.ticks(), 1); 259 } 260 261 /** 262 * Scales this TimeSpan and assigns the result to this instance. 263 * 264 * Params: op = operation to perform 265 * v = A multipler or divisor to use for scaling 266 * Returns: A copy of this instance after scaling 267 */ 268 TimeSpan opOpAssign (string op) (long v) if (op == "*" || op == "/") 269 { 270 mixin("duration_ " ~ op ~ "= v;"); 271 return this; 272 } 273 274 unittest 275 { 276 TimeSpan time_span; 277 time_span.duration_ = 5.hnsecs; 278 279 time_span *= 10; 280 test!("==")(time_span.ticks(), 50); 281 282 time_span /= 5; 283 test!("==")(time_span.ticks(), 10); 284 } 285 286 /** 287 * Perform integer division with the given time span. 288 * 289 * Params: op = operation to perform 290 * t = A divisor used for dividing 291 * Returns: The result of integer division between this instance and 292 * t. 293 */ 294 long opBinary (string op) (in TimeSpan t) const scope if (op == "/") 295 { 296 return duration_ / t.duration_; 297 } 298 299 unittest 300 { 301 TimeSpan time_span; 302 time_span.duration_ = 10.hnsecs; 303 304 TimeSpan test_span; 305 test_span.duration_ = 5.hnsecs; 306 307 test!("==")(time_span / test_span, 2); 308 } 309 310 /** 311 * Negate a time span. Returns a new TimeSpan. 312 * 313 * Params: op = operation to perform 314 * Returns: The negative equivalent to this time span 315 */ 316 TimeSpan opUnary (string op) () if (op == "-") 317 { 318 return TimeSpan(-duration_); 319 } 320 321 unittest 322 { 323 TimeSpan time_span; 324 time_span.duration_ = 10.hnsecs; 325 326 auto res = (-time_span); 327 328 test!("==")(res.ticks(), -10); 329 } 330 331 /** 332 * Convert to nanoseconds 333 * 334 * Note: this may incur loss of data because nanoseconds cannot 335 * represent the range of data a TimeSpan can represent. 336 * 337 * Returns: The number of nanoseconds that this TimeSpan represents. 338 */ 339 long nanos() 340 { 341 return duration_.total!"nsecs"; 342 } 343 344 /** 345 * Convert to microseconds 346 * 347 * Returns: The number of microseconds that this TimeSpan represents. 348 */ 349 long micros() 350 { 351 return duration_.total!"usecs"; 352 } 353 354 /** 355 * Convert to milliseconds 356 * 357 * Returns: The number of milliseconds that this TimeSpan represents. 358 */ 359 long millis() 360 { 361 return duration_.total!"msecs"; 362 } 363 364 /** 365 * Convert to seconds 366 * 367 * Returns: The number of seconds that this TimeSpan represents. 368 */ 369 long seconds() 370 { 371 return duration_.total!"seconds"; 372 } 373 374 /** 375 * Convert to minutes 376 * 377 * Returns: The number of minutes that this TimeSpan represents. 378 */ 379 long minutes() 380 { 381 return duration_.total!"minutes"; 382 } 383 384 /** 385 * Convert to hours 386 * 387 * Returns: The number of hours that this TimeSpan represents. 388 */ 389 long hours() 390 { 391 return duration_.total!"hours"; 392 } 393 394 /** 395 * Convert to days 396 * 397 * Returns: The number of days that this TimeSpan represents. 398 */ 399 long days() 400 { 401 return duration_.total!"days"; 402 } 403 404 /** 405 * Convert to a floating point interval representing seconds. 406 * 407 * Note: This may cause a loss of precision as a double cannot exactly 408 * represent some fractional values. 409 * 410 * Returns: An interval representing the seconds and fractional 411 * seconds that this TimeSpan represents. 412 */ 413 double interval() 414 { 415 return (cast(double) duration_.total!"hnsecs") / TicksPerSecond; 416 } 417 418 /** 419 * Convert to TimeOfDay 420 * 421 * Returns: the TimeOfDay this TimeSpan represents. 422 */ 423 TimeOfDay time() 424 { 425 return TimeOfDay(duration_); 426 } 427 428 /** 429 * Construct a TimeSpan from the given number of nanoseconds 430 * 431 * Note: This may cause a loss of data since a TimeSpan's resolution 432 * is in 100ns increments. 433 * 434 * Params: value = The number of nanoseconds. 435 * Returns: A TimeSpan representing the given number of nanoseconds. 436 */ 437 static TimeSpan fromNanos(long value) 438 { 439 return TimeSpan(value.dur!"nsecs"); 440 } 441 442 /** 443 * Construct a TimeSpan from the given number of microseconds 444 * 445 * Params: value = The number of microseconds. 446 * Returns: A TimeSpan representing the given number of microseconds. 447 */ 448 static TimeSpan fromMicros(long value) 449 { 450 return TimeSpan(value.dur!"usecs"); 451 } 452 453 /** 454 * Construct a TimeSpan from the given number of milliseconds 455 * 456 * Params: value = The number of milliseconds. 457 * Returns: A TimeSpan representing the given number of milliseconds. 458 */ 459 static TimeSpan fromMillis(long value) 460 { 461 return TimeSpan(value.dur!"msecs"); 462 } 463 464 /** 465 * Construct a TimeSpan from the given number of seconds 466 * 467 * Params: value = The number of seconds. 468 * Returns: A TimeSpan representing the given number of seconds. 469 */ 470 static TimeSpan fromSeconds(long value) 471 { 472 return TimeSpan(value.dur!"seconds"); 473 } 474 475 /** 476 * Construct a TimeSpan from the given number of minutes 477 * 478 * Params: value = The number of minutes. 479 * Returns: A TimeSpan representing the given number of minutes. 480 */ 481 static TimeSpan fromMinutes(long value) 482 { 483 return TimeSpan(value.dur!"minutes"); 484 } 485 486 /** 487 * Construct a TimeSpan from the given number of hours 488 * 489 * Params: value = The number of hours. 490 * Returns: A TimeSpan representing the given number of hours. 491 */ 492 static TimeSpan fromHours(long value) 493 { 494 return TimeSpan(value.dur!"hours"); 495 } 496 497 /** 498 * Construct a TimeSpan from the given number of days 499 * 500 * Params: value = The number of days. 501 * Returns: A TimeSpan representing the given number of days. 502 */ 503 static TimeSpan fromDays(long value) 504 { 505 return TimeSpan(value.dur!"days"); 506 } 507 508 /** 509 * Construct a TimeSpan from the given interval. The interval 510 * represents seconds as a double. This allows both whole and 511 * fractional seconds to be passed in. 512 * 513 * Params: sec = The interval to convert in seconds. 514 * Returns: A TimeSpan representing the given interval. 515 */ 516 static TimeSpan fromInterval(double sec) 517 { 518 return TimeSpan((cast(long)(sec * TicksPerSecond + .1)).dur!"hnsecs"); 519 } 520 } 521 522 523 /****************************************************************************** 524 525 Represents a point in time. 526 527 Remarks: Time represents dates and times between 12:00:00 528 midnight on January 1, 10000 BC and 11:59:59 PM on December 31, 529 9999 AD. 530 531 Time values are measured in 100-nanosecond intervals, or ticks. 532 A date value is the number of ticks that have elapsed since 533 12:00:00 midnight on January 1, 0001 AD in the Gregorian 534 calendar. 535 536 Negative Time values are offsets from that same reference point, 537 but backwards in history. Time values are not specific to any 538 calendar, but for an example, the beginning of December 31, 1 BC 539 in the Gregorian calendar is Time.epoch - TimeSpan.days(1). 540 541 ******************************************************************************/ 542 543 struct Time 544 { 545 private long ticks_; 546 547 private enum : long 548 { 549 maximum = (TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1, 550 minimum = -((TimeSpan.DaysPer400Years * 25 - 366) * TimeSpan.TicksPerDay - 1), 551 } 552 553 /// Represents the smallest and largest Time value. 554 enum Time min = {minimum}, 555 max = {maximum}; 556 557 /// Represents the epoch (1/1/0001) 558 enum Time epoch = {0}; 559 560 /// Represents the epoch of 1/1/1601 (Commonly used in Windows systems) 561 enum Time epoch1601 = {TimeSpan.Epoch1601}; 562 563 /// Represents the epoch of 1/1/1970 (Commonly used in Unix systems) 564 enum Time epoch1970 = {TimeSpan.Epoch1970}; 565 566 /********************************************************************** 567 568 $(I Property.) Retrieves the number of ticks for this Time. 569 This value can be used to construct another Time struct by 570 writing: 571 572 --------- 573 long ticks = myTime.ticks; 574 Time copyOfMyTime = Time(ticks); 575 --------- 576 577 578 Returns: A long represented by the time of this 579 instance. 580 581 **********************************************************************/ 582 583 long ticks () 584 { 585 return ticks_; 586 } 587 588 /********************************************************************** 589 590 Determines whether two Time values are equal. 591 592 Params: t = A Time _value. 593 Returns: true if both instances are equal; otherwise, false 594 595 **********************************************************************/ 596 597 public bool opEquals (in Time t) const scope 598 { 599 return this.ticks_ is t.ticks_; 600 } 601 602 /********************************************************************** 603 604 Compares two Time values. 605 606 **********************************************************************/ 607 608 public int opCmp (Time t) const scope 609 { 610 if (this.ticks_ < t.ticks_) 611 return -1; 612 613 if (this.ticks_ > t.ticks_) 614 return 1; 615 616 return 0; 617 } 618 619 /********************************************************************** 620 621 Adds or subtracts the specified time span to the time, 622 returning a new time. 623 624 Params: op = operation to perform 625 t = A TimeSpan value. 626 Returns: A Time that is the sum or difference of this instance 627 and t. 628 629 **********************************************************************/ 630 631 Time opBinary (string op) (in TimeSpan t) const scope 632 if (op == "+" || op == "-") 633 { 634 mixin("return Time(ticks_ " ~ op ~ " t.duration_.total!`hnsecs`);"); 635 } 636 637 unittest 638 { 639 Time time_span; 640 time_span.ticks_ = 5; 641 642 TimeSpan test_span; 643 test_span.duration_ = 10.dur!"hnsecs"; 644 645 auto res = time_span + test_span; 646 test!("==")(res.ticks(), 15); 647 648 test_span.duration_ = 3.dur!"hnsecs"; 649 650 res = time_span - test_span; 651 test!("==")(res.ticks(), 2); 652 } 653 654 /********************************************************************** 655 656 Adds or subtracts the specified time span to the time, assigning 657 the result to this instance. 658 659 Params: op = operation to perform 660 t = A TimeSpan value. 661 Returns: The current Time instance, with t added or subtracted 662 to the time. 663 664 **********************************************************************/ 665 666 Time opOpAssign (string op) (TimeSpan t) if (op == "+" || op == "-") 667 { 668 mixin("ticks_ " ~ op ~ "= t.duration_.total!`hnsecs`;"); 669 return this; 670 } 671 672 unittest 673 { 674 Time time_span; 675 time_span.ticks_ = 5; 676 677 TimeSpan test_span; 678 test_span.duration_ = 10.dur!"hnsecs"; 679 680 time_span += test_span; 681 test!("==")(time_span.ticks(), 15); 682 683 test_span.duration_ = 3.dur!"hnsecs"; 684 685 time_span -= test_span; 686 test!("==")(time_span.ticks(), 12); 687 } 688 689 /********************************************************************** 690 691 Returns a time span which represents the difference in time 692 between this and the given Time. 693 694 Params: op = operation to perform 695 t = A Time value. 696 Returns: A TimeSpan which represents the difference between 697 this and t. 698 699 **********************************************************************/ 700 701 public TimeSpan opBinary (string op) (in Time t) const scope 702 if (op == "-") 703 { 704 return TimeSpan((ticks_ - t.ticks_).dur!"hnsecs"); 705 } 706 707 unittest 708 { 709 Time time_span; 710 time_span.ticks_ = 5; 711 712 TimeSpan test_span; 713 test_span.duration_ = 3.dur!"hnsecs"; 714 715 auto res = time_span - test_span; 716 test!("==")(res.ticks(), 2); 717 } 718 719 /********************************************************************** 720 721 $(I Property.) Retrieves the date component. 722 723 Returns: A new Time instance with the same date as 724 this instance, but with the time truncated. 725 726 **********************************************************************/ 727 728 Time date () 729 { 730 return this - TimeOfDay.modulo24(ticks_); 731 } 732 733 /********************************************************************** 734 735 $(I Property.) Retrieves the time of day. 736 737 Returns: A TimeOfDay representing the fraction of the day 738 elapsed since midnight. 739 740 **********************************************************************/ 741 742 TimeOfDay time () 743 { 744 return TimeOfDay (ticks_); 745 } 746 747 /********************************************************************** 748 749 $(I Property.) Retrieves the equivalent TimeSpan. 750 751 Returns: A TimeSpan representing this Time. 752 753 **********************************************************************/ 754 755 TimeSpan span () 756 { 757 return TimeSpan (ticks_); 758 } 759 760 /********************************************************************** 761 762 $(I Property.) Retrieves a TimeSpan that corresponds to Unix 763 time (time since 1/1/1970). Use the TimeSpan accessors to get 764 the time in seconds, milliseconds, etc. 765 766 Returns: A TimeSpan representing this Time as Unix time. 767 768 ------------------------------------- 769 auto unixTime = Clock.now.unix.seconds; 770 auto javaTime = Clock.now.unix.millis; 771 ------------------------------------- 772 773 **********************************************************************/ 774 775 TimeSpan unix() 776 { 777 return TimeSpan(ticks_ - epoch1970.ticks_); 778 } 779 780 /********************************************************************** 781 782 Constructs a Time instance from the Unix time (time since 1/1/1970). 783 784 Params: 785 unix_time = number of seconds since 1/1/1970 786 787 Returns: 788 Time instance corresponding the given unix time. 789 790 ***********************************************************************/ 791 792 static Time fromUnixTime (time_t unix_time) 793 { 794 return Time(epoch1970.ticks_ + unix_time * TimeSpan.TicksPerSecond); 795 } 796 } 797 798 799 /****************************************************************************** 800 801 Represents a time of day. This is different from TimeSpan in that 802 each component is represented within the limits of everyday time, 803 rather than from the start of the Epoch. Effectively, the TimeOfDay 804 epoch is the first second of each day. 805 806 This is handy for dealing strictly with a 24-hour clock instead of 807 potentially thousands of years. For example: 808 --- 809 auto time = Clock.now.time; 810 assert (time.millis < 1000); 811 assert (time.seconds < 60); 812 assert (time.minutes < 60); 813 assert (time.hours < 24); 814 --- 815 816 You can create a TimeOfDay from an existing Time or TimeSpan instance 817 via the respective time() method. To convert back to a TimeSpan, use 818 the span() method 819 820 ******************************************************************************/ 821 822 struct TimeOfDay 823 { 824 /** 825 * hours component of the time of day. This should be between 0 and 826 * 23, inclusive. 827 */ 828 public uint hours; 829 830 /** 831 * minutes component of the time of day. This should be between 0 and 832 * 59, inclusive. 833 */ 834 public uint minutes; 835 836 /** 837 * seconds component of the time of day. This should be between 0 and 838 * 59, inclusive. 839 */ 840 public uint seconds; 841 842 /** 843 * milliseconds component of the time of day. This should be between 844 * 0 and 999, inclusive. 845 */ 846 public uint millis; 847 848 /** 849 * constructor. 850 * Params: hours = number of hours since midnight 851 * minutes = number of minutes into the hour 852 * seconds = number of seconds into the minute 853 * millis = number of milliseconds into the second 854 * 855 * Returns: a TimeOfDay representing the given time fields. 856 * 857 * Note: There is no verification of the range of values, or 858 * normalization made. So if you pass in larger values than the 859 * maximum value for that field, they will be stored as that value. 860 * 861 * example: 862 * -------------- 863 * auto tod = TimeOfDay(100, 100, 100, 10000); 864 * assert(tod.hours == 100); 865 * assert(tod.minutes == 100); 866 * assert(tod.seconds == 100); 867 * assert(tod.millis == 10000); 868 * -------------- 869 */ 870 static TimeOfDay opCall (uint hours, uint minutes, uint seconds, uint millis=0) 871 { 872 TimeOfDay t = void; 873 t.hours = hours; 874 t.minutes = minutes; 875 t.seconds = seconds; 876 t.millis = millis; 877 return t; 878 } 879 880 /** 881 * constructor. 882 * Params: ticks = ticks representing a Time value. This is normalized 883 * so that it represent a time of day (modulo-24 etc) 884 * 885 * Returns: a TimeOfDay value that corresponds to the time of day of 886 * the given number of ticks. 887 */ 888 static TimeOfDay opCall (long ticks) 889 { 890 return TimeOfDay(modulo24(ticks)); 891 } 892 893 /// Ditto 894 static TimeOfDay opCall (Duration dur) 895 { 896 // Note: Since this represents a time of day, hours needs to be 897 // 0 <= hours < 24. Using `days` ensures that, even if we don't 898 // use the value. 899 auto splitted = dur.split!("days", "hours", "minutes", "seconds", "msecs"); 900 return TimeOfDay(cast(uint)splitted.hours, cast(uint)splitted.minutes, 901 cast(uint)splitted.seconds, cast(uint)splitted.msecs); 902 } 903 904 /** 905 * construct a TimeSpan from the current fields 906 * 907 * Returns: a TimeOfDay representing the field values. 908 * 909 * Note: that fields are not checked against a valid range, so 910 * setting 60 for minutes is allowed, and will just add 1 to the hour 911 * component, and set the minute component to 0. The result is 912 * normalized, so the hours wrap. If you pass in 25 hours, the 913 * resulting TimeOfDay will have a hour component of 1. 914 */ 915 TimeSpan span () 916 { 917 return TimeSpan.fromHours(hours) + 918 TimeSpan.fromMinutes(minutes) + 919 TimeSpan.fromSeconds(seconds) + 920 TimeSpan.fromMillis(millis); 921 } 922 923 /** 924 * internal routine to adjust ticks by one day. Also adjusts for 925 * offsets in the BC era 926 */ 927 package static TimeSpan modulo24 (long ticks) 928 { 929 ticks %= TimeSpan.TicksPerDay; 930 if (ticks < 0) 931 ticks += TimeSpan.TicksPerDay; 932 return TimeSpan (ticks); 933 } 934 } 935 936 /****************************************************************************** 937 938 Generic Date representation 939 940 ******************************************************************************/ 941 942 struct Date 943 { 944 public uint era, /// AD, BC 945 day, /// 1 .. 31 946 year, /// 0 to 9999 947 month, /// 1 .. 12 948 dow, /// 0 .. 6 949 doy; /// 1 .. 366 950 } 951 952 953 /****************************************************************************** 954 955 Combination of a Date and a TimeOfDay 956 957 ******************************************************************************/ 958 959 struct DateTime 960 { 961 public Date date; /// date representation 962 public TimeOfDay time; /// time representation 963 } 964 965 unittest 966 { 967 auto unix = time(null); 968 969 test!("==")((Time.fromUnixTime(unix) - Time.epoch1970).seconds, unix); 970 }