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