1 //Written in the D programming language 2 3 /++ 4 Module containing core time functionality, such as $(LREF Duration) (which 5 represents a duration of time) or $(LREF MonoTime) (which represents a 6 timestamp of the system's monotonic clock). 7 8 Various functions take a string (or strings) to represent a unit of time 9 (e.g. $(D convert!("days", "hours")(numDays))). The valid strings to use 10 with such functions are "years", "months", "weeks", "days", "hours", 11 "minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds), 12 "hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There 13 are a few functions that also allow "nsecs", but very little actually 14 has precision greater than hnsecs. 15 16 $(BOOKTABLE Cheat Sheet, 17 $(TR $(TH Symbol) $(TH Description)) 18 $(LEADINGROW Types) 19 $(TR $(TDNW $(LREF Duration)) $(TD Represents a duration of time of weeks 20 or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds).)) 21 $(TR $(TDNW $(LREF TickDuration)) $(TD $(RED DEPRECATED) Represents a duration of time in 22 system clock ticks, using the highest precision that the system provides.)) 23 $(TR $(TDNW $(LREF MonoTime)) $(TD Represents a monotonic timestamp in 24 system clock ticks, using the highest precision that the system provides.)) 25 $(LEADINGROW Functions) 26 $(TR $(TDNW $(LREF convert)) $(TD Generic way of converting between two time 27 units.)) 28 $(TR $(TDNW $(LREF dur)) $(TD Allows constructing a $(LREF Duration) from 29 the given time units with the given length.)) 30 $(TR $(TDNW $(LREF weeks)$(NBSP)$(LREF days)$(NBSP)$(LREF hours)$(BR) 31 $(LREF minutes)$(NBSP)$(LREF seconds)$(NBSP)$(LREF msecs)$(BR) 32 $(LREF usecs)$(NBSP)$(LREF hnsecs)$(NBSP)$(LREF nsecs)) 33 $(TD Convenience aliases for $(LREF dur).)) 34 $(TR $(TDNW $(LREF abs)) $(TD Returns the absolute value of a duration.)) 35 ) 36 37 $(BOOKTABLE Conversions, 38 $(TR $(TH ) 39 $(TH From $(LREF Duration)) 40 $(TH From $(LREF TickDuration)) 41 $(TH From units) 42 ) 43 $(TR $(TD $(B To $(LREF Duration))) 44 $(TD -) 45 $(TD $(D tickDuration.)$(REF_SHORT to, std,conv)$(D !Duration())) 46 $(TD $(D dur!"msecs"(5)) or $(D 5.msecs())) 47 ) 48 $(TR $(TD $(B To $(LREF TickDuration))) 49 $(TD $(D duration.)$(REF_SHORT to, std,conv)$(D !TickDuration())) 50 $(TD -) 51 $(TD $(D TickDuration.from!"msecs"(msecs))) 52 ) 53 $(TR $(TD $(B To units)) 54 $(TD $(D duration.total!"days")) 55 $(TD $(D tickDuration.msecs)) 56 $(TD $(D convert!("days", "msecs")(msecs))) 57 )) 58 59 Copyright: Copyright 2010 - 2012 60 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 61 Authors: $(HTTP jmdavisprog.com, Jonathan M Davis) and Kato Shoichi 62 Source: $(DRUNTIMESRC core/_time.d) 63 Macros: 64 NBSP= 65 +/ 66 module core.time; 67 68 import core.exception; 69 import core.stdc.time; 70 import core.stdc.stdio; 71 import core.internal.string; 72 73 version (Windows) 74 { 75 import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/; 76 } 77 else version (Posix) 78 { 79 import core.sys.posix.time; 80 import core.sys.posix.sys.time; 81 } else version (WASI) 82 { 83 import core.sys.wasi.time; 84 } 85 86 version (OSX) 87 version = Darwin; 88 else version (iOS) 89 version = Darwin; 90 else version (TVOS) 91 version = Darwin; 92 else version (WatchOS) 93 version = Darwin; 94 95 //This probably should be moved somewhere else in druntime which 96 //is Darwin-specific. 97 version (Darwin) 98 { 99 100 public import core.sys.darwin.mach.kern_return; 101 102 extern(C) nothrow @nogc 103 { 104 105 struct mach_timebase_info_data_t 106 { 107 uint numer; 108 uint denom; 109 } 110 111 alias mach_timebase_info_data_t* mach_timebase_info_t; 112 113 kern_return_t mach_timebase_info(mach_timebase_info_t); 114 115 ulong mach_absolute_time(); 116 117 } 118 119 } 120 121 /++ 122 What type of clock to use with $(LREF MonoTime) / $(LREF MonoTimeImpl) or 123 $(D std.datetime.Clock.currTime). They default to $(D ClockType.normal), 124 and most programs do not need to ever deal with the others. 125 126 The other $(D ClockType)s are provided so that other clocks provided by the 127 underlying C, system calls can be used with $(LREF MonoTimeImpl) or 128 $(D std.datetime.Clock.currTime) without having to use the C API directly. 129 130 In the case of the monotonic time, $(LREF MonoTimeImpl) is templatized on 131 $(D ClockType), whereas with $(D std.datetime.Clock.currTime), its a runtime 132 argument, since in the case of the monotonic time, the type of the clock 133 affects the resolution of a $(LREF MonoTimeImpl) object, whereas with 134 $(REF SysTime, std,datetime), its resolution is always hecto-nanoseconds 135 regardless of the source of the time. 136 137 $(D ClockType.normal), $(D ClockType.coarse), and $(D ClockType.precise) 138 work with both $(D Clock.currTime) and $(LREF MonoTimeImpl). 139 $(D ClockType.second) only works with $(D Clock.currTime). The others only 140 work with $(LREF MonoTimeImpl). 141 +/ 142 version (CoreDdoc) enum ClockType 143 { 144 /++ 145 Use the normal clock. 146 +/ 147 normal = 0, 148 149 /++ 150 $(BLUE Linux,OpenBSD-Only) 151 152 Uses $(D CLOCK_BOOTTIME). 153 +/ 154 bootTime = 1, 155 156 /++ 157 Use the coarse clock, not the normal one (e.g. on Linux, that would be 158 $(D CLOCK_REALTIME_COARSE) instead of $(D CLOCK_REALTIME) for 159 $(D clock_gettime) if a function is using the realtime clock). It's 160 generally faster to get the time with the coarse clock than the normal 161 clock, but it's less precise (e.g. 1 msec instead of 1 usec or 1 nsec). 162 Howeover, it $(I is) guaranteed to still have sub-second precision 163 (just not as high as with $(D ClockType.normal)). 164 165 On systems which do not support a coarser clock, 166 $(D MonoTimeImpl!(ClockType.coarse)) will internally use the same clock 167 as $(D MonoTime) does, and $(D Clock.currTime!(ClockType.coarse)) will 168 use the same clock as $(D Clock.currTime). This is because the coarse 169 clock is doing the same thing as the normal clock (just at lower 170 precision), whereas some of the other clock types 171 (e.g. $(D ClockType.processCPUTime)) mean something fundamentally 172 different. So, treating those as $(D ClockType.normal) on systems where 173 they weren't natively supported would give misleading results. 174 175 Most programs should not use the coarse clock, exactly because it's 176 less precise, and most programs don't need to get the time often 177 enough to care, but for those rare programs that need to get the time 178 extremely frequently (e.g. hundreds of thousands of times a second) but 179 don't care about high precision, the coarse clock might be appropriate. 180 181 Currently, only Linux and FreeBSD/DragonFlyBSD support a coarser clock, and on other 182 platforms, it's treated as $(D ClockType.normal). 183 +/ 184 coarse = 2, 185 186 /++ 187 Uses a more precise clock than the normal one (which is already very 188 precise), but it takes longer to get the time. Similarly to 189 $(D ClockType.coarse), if it's used on a system that does not support a 190 more precise clock than the normal one, it's treated as equivalent to 191 $(D ClockType.normal). 192 193 Currently, only FreeBSD/DragonFlyBSD supports a more precise clock, where it uses 194 $(D CLOCK_MONOTONIC_PRECISE) for the monotonic time and 195 $(D CLOCK_REALTIME_PRECISE) for the wall clock time. 196 +/ 197 precise = 3, 198 199 /++ 200 $(BLUE Linux,OpenBSD,Solaris-Only) 201 202 Uses $(D CLOCK_PROCESS_CPUTIME_ID). 203 +/ 204 processCPUTime = 4, 205 206 /++ 207 $(BLUE Linux-Only) 208 209 Uses $(D CLOCK_MONOTONIC_RAW). 210 +/ 211 raw = 5, 212 213 /++ 214 Uses a clock that has a precision of one second (contrast to the coarse 215 clock, which has sub-second precision like the normal clock does). 216 217 FreeBSD/DragonFlyBSD are the only systems which specifically have a clock set up for 218 this (it has $(D CLOCK_SECOND) to use with $(D clock_gettime) which 219 takes advantage of an in-kernel cached value), but on other systems, the 220 fastest function available will be used, and the resulting $(D SysTime) 221 will be rounded down to the second if the clock that was used gave the 222 time at a more precise resolution. So, it's guaranteed that the time 223 will be given at a precision of one second and it's likely the case that 224 will be faster than $(D ClockType.normal), since there tend to be 225 several options on a system to get the time at low resolutions, and they 226 tend to be faster than getting the time at high resolutions. 227 228 So, the primary difference between $(D ClockType.coarse) and 229 $(D ClockType.second) is that $(D ClockType.coarse) sacrifices some 230 precision in order to get speed but is still fairly precise, whereas 231 $(D ClockType.second) tries to be as fast as possible at the expense of 232 all sub-second precision. 233 +/ 234 second = 6, 235 236 /++ 237 $(BLUE Linux,OpenBSD,Solaris-Only) 238 239 Uses $(D CLOCK_THREAD_CPUTIME_ID). 240 +/ 241 threadCPUTime = 7, 242 243 /++ 244 $(BLUE DragonFlyBSD,FreeBSD,OpenBSD-Only) 245 246 Uses $(D CLOCK_UPTIME). 247 +/ 248 uptime = 8, 249 250 /++ 251 $(BLUE FreeBSD-Only) 252 253 Uses $(D CLOCK_UPTIME_FAST). 254 +/ 255 uptimeCoarse = 9, 256 257 /++ 258 $(BLUE FreeBSD-Only) 259 260 Uses $(D CLOCK_UPTIME_PRECISE). 261 +/ 262 uptimePrecise = 10, 263 } 264 else version (Windows) enum ClockType 265 { 266 normal = 0, 267 coarse = 2, 268 precise = 3, 269 second = 6, 270 } 271 else version (Darwin) enum ClockType 272 { 273 normal = 0, 274 coarse = 2, 275 precise = 3, 276 second = 6, 277 } 278 else version (linux) enum ClockType 279 { 280 normal = 0, 281 bootTime = 1, 282 coarse = 2, 283 precise = 3, 284 processCPUTime = 4, 285 raw = 5, 286 second = 6, 287 threadCPUTime = 7, 288 } 289 else version (FreeBSD) enum ClockType 290 { 291 normal = 0, 292 coarse = 2, 293 precise = 3, 294 second = 6, 295 uptime = 8, 296 uptimeCoarse = 9, 297 uptimePrecise = 10, 298 } 299 else version (NetBSD) enum ClockType 300 { 301 normal = 0, 302 coarse = 2, 303 precise = 3, 304 second = 6, 305 } 306 else version (OpenBSD) enum ClockType 307 { 308 normal = 0, 309 bootTime = 1, 310 coarse = 2, 311 precise = 3, 312 processCPUTime = 4, 313 second = 6, 314 threadCPUTime = 7, 315 uptime = 8, 316 } 317 else version (DragonFlyBSD) enum ClockType 318 { 319 normal = 0, 320 coarse = 2, 321 precise = 3, 322 second = 6, 323 uptime = 8, 324 uptimeCoarse = 9, 325 uptimePrecise = 10, 326 } 327 else version (Solaris) enum ClockType 328 { 329 normal = 0, 330 coarse = 2, 331 precise = 3, 332 processCPUTime = 4, 333 second = 6, 334 threadCPUTime = 7, 335 } else version (WASI) enum ClockType 336 { 337 normal = 0, 338 raw = 1, 339 processCPUTime = 2, 340 threadCPUTime = 3 341 } 342 else 343 { 344 // It needs to be decided (and implemented in an appropriate version branch 345 // here) which clock types new platforms are going to support. At minimum, 346 // the ones _not_ marked with $(D Blue Foo-Only) should be supported. 347 static assert(0, "What are the clock types supported by this system?"); 348 } 349 350 // private, used to translate clock type to proper argument to clock_xxx 351 // functions on posix systems 352 version (CoreDdoc) 353 private int _posixClock(ClockType clockType) { return 0; } 354 else 355 version (Posix) 356 { 357 private auto _posixClock(ClockType clockType) 358 { 359 version (linux) 360 { 361 import core.sys.linux.time; 362 with(ClockType) final switch (clockType) 363 { 364 case bootTime: return CLOCK_BOOTTIME; 365 case coarse: return CLOCK_MONOTONIC_COARSE; 366 case normal: return CLOCK_MONOTONIC; 367 case precise: return CLOCK_MONOTONIC; 368 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID; 369 case raw: return CLOCK_MONOTONIC_RAW; 370 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID; 371 case second: assert(0); 372 } 373 } 374 else version (FreeBSD) 375 { 376 import core.sys.freebsd.time; 377 with(ClockType) final switch (clockType) 378 { 379 case coarse: return CLOCK_MONOTONIC_FAST; 380 case normal: return CLOCK_MONOTONIC; 381 case precise: return CLOCK_MONOTONIC_PRECISE; 382 case uptime: return CLOCK_UPTIME; 383 case uptimeCoarse: return CLOCK_UPTIME_FAST; 384 case uptimePrecise: return CLOCK_UPTIME_PRECISE; 385 case second: assert(0); 386 } 387 } 388 else version (NetBSD) 389 { 390 import core.sys.netbsd.time; 391 with(ClockType) final switch (clockType) 392 { 393 case coarse: return CLOCK_MONOTONIC; 394 case normal: return CLOCK_MONOTONIC; 395 case precise: return CLOCK_MONOTONIC; 396 case second: assert(0); 397 } 398 } 399 else version (OpenBSD) 400 { 401 import core.sys.openbsd.time; 402 with(ClockType) final switch (clockType) 403 { 404 case bootTime: return CLOCK_BOOTTIME; 405 case coarse: return CLOCK_MONOTONIC; 406 case normal: return CLOCK_MONOTONIC; 407 case precise: return CLOCK_MONOTONIC; 408 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID; 409 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID; 410 case uptime: return CLOCK_UPTIME; 411 case second: assert(0); 412 } 413 } 414 else version (DragonFlyBSD) 415 { 416 import core.sys.dragonflybsd.time; 417 with(ClockType) final switch (clockType) 418 { 419 case coarse: return CLOCK_MONOTONIC_FAST; 420 case normal: return CLOCK_MONOTONIC; 421 case precise: return CLOCK_MONOTONIC_PRECISE; 422 case uptime: return CLOCK_UPTIME; 423 case uptimeCoarse: return CLOCK_UPTIME_FAST; 424 case uptimePrecise: return CLOCK_UPTIME_PRECISE; 425 case second: assert(0); 426 } 427 } 428 else version (Solaris) 429 { 430 import core.sys.solaris.time; 431 with(ClockType) final switch (clockType) 432 { 433 case coarse: return CLOCK_MONOTONIC; 434 case normal: return CLOCK_MONOTONIC; 435 case precise: return CLOCK_MONOTONIC; 436 case processCPUTime: return CLOCK_PROCESS_CPUTIME_ID; 437 case threadCPUTime: return CLOCK_THREAD_CPUTIME_ID; 438 case second: assert(0); 439 } 440 } 441 else 442 // It needs to be decided (and implemented in an appropriate 443 // version branch here) which clock types new platforms are going 444 // to support. Also, ClockType's documentation should be updated to 445 // mention it if a new platform uses anything that's not supported 446 // on all platforms.. 447 assert(0, "What are the monotonic clock types supported by this system?"); 448 } 449 } 450 451 unittest 452 { 453 // Make sure that the values are the same across platforms. 454 static if (is(typeof(ClockType.normal))) static assert(ClockType.normal == 0); 455 static if (is(typeof(ClockType.bootTime))) static assert(ClockType.bootTime == 1); 456 static if (is(typeof(ClockType.coarse))) static assert(ClockType.coarse == 2); 457 static if (is(typeof(ClockType.precise))) static assert(ClockType.precise == 3); 458 static if (is(typeof(ClockType.processCPUTime))) static assert(ClockType.processCPUTime == 4); 459 static if (is(typeof(ClockType.raw))) static assert(ClockType.raw == 5); 460 static if (is(typeof(ClockType.second))) static assert(ClockType.second == 6); 461 static if (is(typeof(ClockType.threadCPUTime))) static assert(ClockType.threadCPUTime == 7); 462 static if (is(typeof(ClockType.uptime))) static assert(ClockType.uptime == 8); 463 static if (is(typeof(ClockType.uptimeCoarse))) static assert(ClockType.uptimeCoarse == 9); 464 static if (is(typeof(ClockType.uptimePrecise))) static assert(ClockType.uptimePrecise == 10); 465 } 466 467 468 /++ 469 Represents a duration of time of weeks or less (kept internally as hnsecs). 470 (e.g. 22 days or 700 seconds). 471 472 It is used when representing a duration of time - such as how long to 473 sleep with $(REF Thread.sleep, core,thread). 474 475 In std.datetime, it is also used as the result of various arithmetic 476 operations on time points. 477 478 Use the $(LREF dur) function or one of its non-generic aliases to create 479 $(D Duration)s. 480 481 It's not possible to create a Duration of months or years, because the 482 variable number of days in a month or year makes it impossible to convert 483 between months or years and smaller units without a specific date. So, 484 nothing uses $(D Duration)s when dealing with months or years. Rather, 485 functions specific to months and years are defined. For instance, 486 $(REF Date, std,datetime) has $(D add!"years") and $(D add!"months") for adding 487 years and months rather than creating a Duration of years or months and 488 adding that to a $(REF Date, std,datetime). But Duration is used when dealing 489 with weeks or smaller. 490 491 Examples: 492 -------------------- 493 import std.datetime; 494 495 assert(dur!"days"(12) == dur!"hnsecs"(10_368_000_000_000L)); 496 assert(dur!"hnsecs"(27) == dur!"hnsecs"(27)); 497 assert(std.datetime.Date(2010, 9, 7) + dur!"days"(5) == 498 std.datetime.Date(2010, 9, 12)); 499 500 assert(days(-12) == dur!"hnsecs"(-10_368_000_000_000L)); 501 assert(hnsecs(-27) == dur!"hnsecs"(-27)); 502 assert(std.datetime.Date(2010, 9, 7) - std.datetime.Date(2010, 10, 3) == 503 days(-26)); 504 -------------------- 505 +/ 506 struct Duration 507 { 508 /++ 509 Converts this `Duration` to a `string`. 510 511 The string is meant to be human readable, not machine parseable (e.g. 512 whether there is an `'s'` on the end of the unit name usually depends on 513 whether it's plural or not, and empty units are not included unless the 514 Duration is `zero`). Any code needing a specific string format should 515 use `total` or `split` to get the units needed to create the desired 516 string format and create the string itself. 517 518 The format returned by toString may or may not change in the future. 519 520 Params: 521 sink = A sink object, expected to be a delegate or aggregate 522 implementing `opCall` that accepts a `scope const(char)[]` 523 as argument. 524 +/ 525 void toString (SinkT) (scope SinkT sink) const scope 526 { 527 static immutable units = [ 528 "weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs" 529 ]; 530 531 static void appListSep(SinkT sink, uint pos, bool last) 532 { 533 if (pos == 0) 534 return; 535 if (!last) 536 sink(", "); 537 else 538 sink(pos == 1 ? " and " : ", and "); 539 } 540 541 static void appUnitVal(string units)(SinkT sink, long val) 542 { 543 immutable plural = val != 1; 544 string unit; 545 static if (units == "seconds") 546 unit = plural ? "secs" : "sec"; 547 else static if (units == "msecs") 548 unit = "ms"; 549 else static if (units == "usecs") 550 unit = "μs"; 551 else 552 unit = plural ? units : units[0 .. $-1]; 553 sink(signedToTempString(val)); 554 sink(" "); 555 sink(unit); 556 } 557 558 if (_hnsecs == 0) 559 { 560 sink("0 hnsecs"); 561 return; 562 } 563 564 long hnsecs = _hnsecs; 565 uint pos; 566 static foreach (unit; units) 567 { 568 if (auto val = splitUnitsFromHNSecs!unit(hnsecs)) 569 { 570 appListSep(sink, pos++, hnsecs == 0); 571 appUnitVal!unit(sink, val); 572 } 573 if (hnsecs == 0) 574 return; 575 } 576 if (hnsecs != 0) 577 { 578 appListSep(sink, pos++, true); 579 appUnitVal!"hnsecs"(sink, hnsecs); 580 } 581 } 582 583 @safe pure: 584 585 public: 586 587 /++ 588 A $(D Duration) of $(D 0). It's shorter than doing something like 589 $(D dur!"seconds"(0)) and more explicit than $(D Duration.init). 590 +/ 591 static @property nothrow @nogc Duration zero() { return Duration(0); } 592 593 /++ 594 Largest $(D Duration) possible. 595 +/ 596 static @property nothrow @nogc Duration max() { return Duration(long.max); } 597 598 /++ 599 Most negative $(D Duration) possible. 600 +/ 601 static @property nothrow @nogc Duration min() { return Duration(long.min); } 602 603 version (CoreUnittest) unittest 604 { 605 assert(zero == dur!"seconds"(0)); 606 assert(Duration.max == Duration(long.max)); 607 assert(Duration.min == Duration(long.min)); 608 assert(Duration.min < Duration.zero); 609 assert(Duration.zero < Duration.max); 610 assert(Duration.min < Duration.max); 611 assert(Duration.min - dur!"hnsecs"(1) == Duration.max); 612 assert(Duration.max + dur!"hnsecs"(1) == Duration.min); 613 } 614 615 616 /++ 617 Compares this $(D Duration) with the given $(D Duration). 618 619 Returns: 620 $(TABLE 621 $(TR $(TD this < rhs) $(TD < 0)) 622 $(TR $(TD this == rhs) $(TD 0)) 623 $(TR $(TD this > rhs) $(TD > 0)) 624 ) 625 +/ 626 int opCmp(Duration rhs) const nothrow @nogc 627 { 628 return (_hnsecs > rhs._hnsecs) - (_hnsecs < rhs._hnsecs); 629 } 630 631 version (CoreUnittest) unittest 632 { 633 import core.internal.traits : rvalueOf; 634 foreach (T; AliasSeq!(Duration, const Duration, immutable Duration)) 635 { 636 foreach (U; AliasSeq!(Duration, const Duration, immutable Duration)) 637 { 638 T t = 42; 639 // workaround https://issues.dlang.org/show_bug.cgi?id=18296 640 version (D_Coverage) 641 U u = T(t._hnsecs); 642 else 643 U u = t; 644 assert(t == u); 645 assert(rvalueOf(t) == u); 646 assert(t == rvalueOf(u)); 647 } 648 } 649 650 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 651 { 652 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration)) 653 { 654 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0); 655 assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0); 656 657 assert((cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0); 658 assert((cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0); 659 660 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0); 661 assert((cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0); 662 663 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(12)) == 0); 664 assert(rvalueOf(cast(D)Duration(-12)).opCmp(cast(E)Duration(-12)) == 0); 665 666 assert(rvalueOf(cast(D)Duration(10)).opCmp(cast(E)Duration(12)) < 0); 667 assert(rvalueOf(cast(D)Duration(-12)).opCmp(cast(E)Duration(12)) < 0); 668 669 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(10)) > 0); 670 assert(rvalueOf(cast(D)Duration(12)).opCmp(cast(E)Duration(-12)) > 0); 671 672 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(12))) == 0); 673 assert((cast(D)Duration(-12)).opCmp(rvalueOf(cast(E)Duration(-12))) == 0); 674 675 assert((cast(D)Duration(10)).opCmp(rvalueOf(cast(E)Duration(12))) < 0); 676 assert((cast(D)Duration(-12)).opCmp(rvalueOf(cast(E)Duration(12))) < 0); 677 678 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(10))) > 0); 679 assert((cast(D)Duration(12)).opCmp(rvalueOf(cast(E)Duration(-12))) > 0); 680 } 681 } 682 } 683 684 685 /++ 686 Adds, subtracts or calculates the modulo of two durations. 687 688 The legal types of arithmetic for $(D Duration) using this operator are 689 690 $(TABLE 691 $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) 692 $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) 693 $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration)) 694 ) 695 696 Params: 697 rhs = The duration to add to or subtract from this $(D Duration). 698 +/ 699 Duration opBinary(string op)(const Duration rhs) const nothrow @nogc 700 if (op == "+" || op == "-" || op == "%") 701 { 702 return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs")); 703 } 704 705 deprecated Duration opBinary(string op)(const TickDuration rhs) const nothrow @nogc 706 if (op == "+" || op == "-") 707 { 708 return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs")); 709 } 710 711 version (CoreUnittest) unittest 712 { 713 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 714 { 715 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration)) 716 { 717 assert((cast(D)Duration(5)) + (cast(E)Duration(7)) == Duration(12)); 718 assert((cast(D)Duration(5)) - (cast(E)Duration(7)) == Duration(-2)); 719 assert((cast(D)Duration(5)) % (cast(E)Duration(7)) == Duration(5)); 720 assert((cast(D)Duration(7)) + (cast(E)Duration(5)) == Duration(12)); 721 assert((cast(D)Duration(7)) - (cast(E)Duration(5)) == Duration(2)); 722 assert((cast(D)Duration(7)) % (cast(E)Duration(5)) == Duration(2)); 723 724 assert((cast(D)Duration(5)) + (cast(E)Duration(-7)) == Duration(-2)); 725 assert((cast(D)Duration(5)) - (cast(E)Duration(-7)) == Duration(12)); 726 assert((cast(D)Duration(5)) % (cast(E)Duration(-7)) == Duration(5)); 727 assert((cast(D)Duration(7)) + (cast(E)Duration(-5)) == Duration(2)); 728 assert((cast(D)Duration(7)) - (cast(E)Duration(-5)) == Duration(12)); 729 assert((cast(D)Duration(7)) % (cast(E)Duration(-5)) == Duration(2)); 730 731 assert((cast(D)Duration(-5)) + (cast(E)Duration(7)) == Duration(2)); 732 assert((cast(D)Duration(-5)) - (cast(E)Duration(7)) == Duration(-12)); 733 assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5)); 734 assert((cast(D)Duration(-7)) + (cast(E)Duration(5)) == Duration(-2)); 735 assert((cast(D)Duration(-7)) - (cast(E)Duration(5)) == Duration(-12)); 736 assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2)); 737 738 assert((cast(D)Duration(-5)) + (cast(E)Duration(-7)) == Duration(-12)); 739 assert((cast(D)Duration(-5)) - (cast(E)Duration(-7)) == Duration(2)); 740 assert((cast(D)Duration(-5)) % (cast(E)Duration(7)) == Duration(-5)); 741 assert((cast(D)Duration(-7)) + (cast(E)Duration(-5)) == Duration(-12)); 742 assert((cast(D)Duration(-7)) - (cast(E)Duration(-5)) == Duration(-2)); 743 assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2)); 744 } 745 } 746 } 747 748 version (CoreUnittest) deprecated unittest 749 { 750 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 751 { 752 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 753 { 754 assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80)); 755 assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60)); 756 assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62)); 757 assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38)); 758 759 assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60)); 760 assertApprox((cast(D)Duration(5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80)); 761 assertApprox((cast(D)Duration(7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38)); 762 assertApprox((cast(D)Duration(7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62)); 763 764 assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70)); 765 assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70)); 766 assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48)); 767 assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52)); 768 769 assertApprox((cast(D)Duration(-5)) + cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70)); 770 assertApprox((cast(D)Duration(-5)) - cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70)); 771 assertApprox((cast(D)Duration(-7)) + cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52)); 772 assertApprox((cast(D)Duration(-7)) - cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48)); 773 } 774 } 775 } 776 777 778 /++ 779 $(RED TickDuration is Deprecated) 780 781 Adds or subtracts two durations. 782 783 The legal types of arithmetic for $(D Duration) using this operator are 784 785 $(TABLE 786 $(TR $(TD TickDuration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) 787 $(TR $(TD TickDuration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) 788 ) 789 790 Params: 791 lhs = The $(D TickDuration) to add to this $(D Duration) or to 792 subtract this $(D Duration) from. 793 +/ 794 deprecated Duration opBinaryRight(string op, D)(D lhs) const nothrow @nogc 795 if ((op == "+" || op == "-") && 796 is(immutable D == immutable TickDuration)) 797 { 798 return Duration(mixin("lhs.hnsecs " ~ op ~ " _hnsecs")); 799 } 800 801 version (CoreUnittest) deprecated unittest 802 { 803 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 804 { 805 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 806 { 807 assertApprox((cast(T)TickDuration.from!"usecs"(7)) + cast(D)Duration(5), Duration(70), Duration(80)); 808 assertApprox((cast(T)TickDuration.from!"usecs"(7)) - cast(D)Duration(5), Duration(60), Duration(70)); 809 assertApprox((cast(T)TickDuration.from!"usecs"(5)) + cast(D)Duration(7), Duration(52), Duration(62)); 810 assertApprox((cast(T)TickDuration.from!"usecs"(5)) - cast(D)Duration(7), Duration(38), Duration(48)); 811 812 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(5), Duration(-70), Duration(-60)); 813 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(5), Duration(-80), Duration(-70)); 814 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(7), Duration(-48), Duration(-38)); 815 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(7), Duration(-62), Duration(-52)); 816 817 assertApprox((cast(T)TickDuration.from!"usecs"(7)) + (cast(D)Duration(-5)), Duration(60), Duration(70)); 818 assertApprox((cast(T)TickDuration.from!"usecs"(7)) - (cast(D)Duration(-5)), Duration(70), Duration(80)); 819 assertApprox((cast(T)TickDuration.from!"usecs"(5)) + (cast(D)Duration(-7)), Duration(38), Duration(48)); 820 assertApprox((cast(T)TickDuration.from!"usecs"(5)) - (cast(D)Duration(-7)), Duration(52), Duration(62)); 821 822 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) + cast(D)Duration(-5), Duration(-80), Duration(-70)); 823 assertApprox((cast(T)TickDuration.from!"usecs"(-7)) - cast(D)Duration(-5), Duration(-70), Duration(-60)); 824 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) + cast(D)Duration(-7), Duration(-62), Duration(-52)); 825 assertApprox((cast(T)TickDuration.from!"usecs"(-5)) - cast(D)Duration(-7), Duration(-48), Duration(-38)); 826 } 827 } 828 } 829 830 831 /++ 832 Adds, subtracts or calculates the modulo of two durations as well as 833 assigning the result to this $(D Duration). 834 835 The legal types of arithmetic for $(D Duration) using this operator are 836 837 $(TABLE 838 $(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration)) 839 $(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration)) 840 $(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration)) 841 ) 842 843 Params: 844 rhs = The duration to add to or subtract from this $(D Duration). 845 +/ 846 ref Duration opOpAssign(string op)(const Duration rhs) nothrow @nogc 847 if (op == "+" || op == "-" || op == "%") 848 { 849 mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;"); 850 return this; 851 } 852 853 deprecated ref Duration opOpAssign(string op)(const TickDuration rhs) nothrow @nogc 854 if (op == "+" || op == "-") 855 { 856 mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;"); 857 return this; 858 } 859 860 version (CoreUnittest) unittest 861 { 862 static void test1(string op, E)(Duration actual, in E rhs, Duration expected, size_t line = __LINE__) 863 { 864 if (mixin("actual " ~ op ~ " rhs") != expected) 865 throw new AssertError("op failed", __FILE__, line); 866 867 if (actual != expected) 868 throw new AssertError("op assign failed", __FILE__, line); 869 } 870 871 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration)) 872 { 873 test1!"+="(Duration(5), (cast(E)Duration(7)), Duration(12)); 874 test1!"-="(Duration(5), (cast(E)Duration(7)), Duration(-2)); 875 test1!"%="(Duration(5), (cast(E)Duration(7)), Duration(5)); 876 test1!"+="(Duration(7), (cast(E)Duration(5)), Duration(12)); 877 test1!"-="(Duration(7), (cast(E)Duration(5)), Duration(2)); 878 test1!"%="(Duration(7), (cast(E)Duration(5)), Duration(2)); 879 880 test1!"+="(Duration(5), (cast(E)Duration(-7)), Duration(-2)); 881 test1!"-="(Duration(5), (cast(E)Duration(-7)), Duration(12)); 882 test1!"%="(Duration(5), (cast(E)Duration(-7)), Duration(5)); 883 test1!"+="(Duration(7), (cast(E)Duration(-5)), Duration(2)); 884 test1!"-="(Duration(7), (cast(E)Duration(-5)), Duration(12)); 885 test1!"%="(Duration(7), (cast(E)Duration(-5)), Duration(2)); 886 887 test1!"+="(Duration(-5), (cast(E)Duration(7)), Duration(2)); 888 test1!"-="(Duration(-5), (cast(E)Duration(7)), Duration(-12)); 889 test1!"%="(Duration(-5), (cast(E)Duration(7)), Duration(-5)); 890 test1!"+="(Duration(-7), (cast(E)Duration(5)), Duration(-2)); 891 test1!"-="(Duration(-7), (cast(E)Duration(5)), Duration(-12)); 892 test1!"%="(Duration(-7), (cast(E)Duration(5)), Duration(-2)); 893 894 test1!"+="(Duration(-5), (cast(E)Duration(-7)), Duration(-12)); 895 test1!"-="(Duration(-5), (cast(E)Duration(-7)), Duration(2)); 896 test1!"%="(Duration(-5), (cast(E)Duration(-7)), Duration(-5)); 897 test1!"+="(Duration(-7), (cast(E)Duration(-5)), Duration(-12)); 898 test1!"-="(Duration(-7), (cast(E)Duration(-5)), Duration(-2)); 899 test1!"%="(Duration(-7), (cast(E)Duration(-5)), Duration(-2)); 900 } 901 902 foreach (D; AliasSeq!(const Duration, immutable Duration)) 903 { 904 foreach (E; AliasSeq!(Duration, const Duration, immutable Duration)) 905 { 906 D lhs = D(120); 907 E rhs = E(120); 908 static assert(!__traits(compiles, lhs += rhs), D.stringof ~ " " ~ E.stringof); 909 } 910 } 911 } 912 913 version (CoreUnittest) deprecated unittest 914 { 915 static void test2(string op, E) 916 (Duration actual, in E rhs, Duration lower, Duration upper, size_t line = __LINE__) 917 { 918 assertApprox(mixin("actual " ~ op ~ " rhs"), lower, upper, "op failed", line); 919 assertApprox(actual, lower, upper, "op assign failed", line); 920 } 921 922 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 923 { 924 test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80)); 925 test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(-70), Duration(-60)); 926 test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(52), Duration(62)); 927 test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(5), Duration(-48), Duration(-38)); 928 929 test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(-70), Duration(-60)); 930 test2!"-="(Duration(5), cast(T)TickDuration.from!"usecs"(-7), Duration(70), Duration(80)); 931 test2!"+="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(-48), Duration(-38)); 932 test2!"-="(Duration(7), cast(T)TickDuration.from!"usecs"(-5), Duration(52), Duration(62)); 933 934 test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(60), Duration(70)); 935 test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(7), Duration(-80), Duration(-70)); 936 test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(38), Duration(48)); 937 test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(5), Duration(-62), Duration(-52)); 938 939 test2!"+="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(-80), Duration(-70)); 940 test2!"-="(Duration(-5), cast(T)TickDuration.from!"usecs"(-7), Duration(60), Duration(70)); 941 test2!"+="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(-62), Duration(-52)); 942 test2!"-="(Duration(-7), cast(T)TickDuration.from!"usecs"(-5), Duration(38), Duration(48)); 943 } 944 945 foreach (D; AliasSeq!(const Duration, immutable Duration)) 946 { 947 foreach (E; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 948 { 949 D lhs = D(120); 950 E rhs = E(120); 951 static assert(!__traits(compiles, lhs += rhs), D.stringof ~ " " ~ E.stringof); 952 } 953 } 954 } 955 956 957 /++ 958 Multiplies or divides the duration by an integer value. 959 960 The legal types of arithmetic for $(D Duration) using this operator 961 overload are 962 963 $(TABLE 964 $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) 965 $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) 966 ) 967 968 Params: 969 value = The value to multiply this $(D Duration) by. 970 +/ 971 Duration opBinary(string op)(long value) const nothrow @nogc 972 if (op == "*" || op == "/") 973 { 974 mixin("return Duration(_hnsecs " ~ op ~ " value);"); 975 } 976 977 version (CoreUnittest) unittest 978 { 979 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 980 { 981 assert((cast(D)Duration(5)) * 7 == Duration(35)); 982 assert((cast(D)Duration(7)) * 5 == Duration(35)); 983 984 assert((cast(D)Duration(5)) * -7 == Duration(-35)); 985 assert((cast(D)Duration(7)) * -5 == Duration(-35)); 986 987 assert((cast(D)Duration(-5)) * 7 == Duration(-35)); 988 assert((cast(D)Duration(-7)) * 5 == Duration(-35)); 989 990 assert((cast(D)Duration(-5)) * -7 == Duration(35)); 991 assert((cast(D)Duration(-7)) * -5 == Duration(35)); 992 993 assert((cast(D)Duration(5)) * 0 == Duration(0)); 994 assert((cast(D)Duration(-5)) * 0 == Duration(0)); 995 } 996 } 997 998 version (CoreUnittest) unittest 999 { 1000 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1001 { 1002 assert((cast(D)Duration(5)) / 7 == Duration(0)); 1003 assert((cast(D)Duration(7)) / 5 == Duration(1)); 1004 1005 assert((cast(D)Duration(5)) / -7 == Duration(0)); 1006 assert((cast(D)Duration(7)) / -5 == Duration(-1)); 1007 1008 assert((cast(D)Duration(-5)) / 7 == Duration(0)); 1009 assert((cast(D)Duration(-7)) / 5 == Duration(-1)); 1010 1011 assert((cast(D)Duration(-5)) / -7 == Duration(0)); 1012 assert((cast(D)Duration(-7)) / -5 == Duration(1)); 1013 } 1014 } 1015 1016 1017 /++ 1018 Multiplies/Divides the duration by an integer value as well as 1019 assigning the result to this $(D Duration). 1020 1021 The legal types of arithmetic for $(D Duration) using this operator 1022 overload are 1023 1024 $(TABLE 1025 $(TR $(TD Duration) $(TD *) $(TD long) $(TD -->) $(TD Duration)) 1026 $(TR $(TD Duration) $(TD /) $(TD long) $(TD -->) $(TD Duration)) 1027 ) 1028 1029 Params: 1030 value = The value to multiply/divide this $(D Duration) by. 1031 +/ 1032 ref Duration opOpAssign(string op)(long value) nothrow @nogc 1033 if (op == "*" || op == "/") 1034 { 1035 mixin("_hnsecs " ~ op ~ "= value;"); 1036 return this; 1037 } 1038 1039 version (CoreUnittest) unittest 1040 { 1041 static void test(D)(D actual, long value, Duration expected, size_t line = __LINE__) 1042 { 1043 if ((actual *= value) != expected) 1044 throw new AssertError("op failed", __FILE__, line); 1045 1046 if (actual != expected) 1047 throw new AssertError("op assign failed", __FILE__, line); 1048 } 1049 1050 test(Duration(5), 7, Duration(35)); 1051 test(Duration(7), 5, Duration(35)); 1052 1053 test(Duration(5), -7, Duration(-35)); 1054 test(Duration(7), -5, Duration(-35)); 1055 1056 test(Duration(-5), 7, Duration(-35)); 1057 test(Duration(-7), 5, Duration(-35)); 1058 1059 test(Duration(-5), -7, Duration(35)); 1060 test(Duration(-7), -5, Duration(35)); 1061 1062 test(Duration(5), 0, Duration(0)); 1063 test(Duration(-5), 0, Duration(0)); 1064 1065 const cdur = Duration(12); 1066 immutable idur = Duration(12); 1067 static assert(!__traits(compiles, cdur *= 12)); 1068 static assert(!__traits(compiles, idur *= 12)); 1069 } 1070 1071 version (CoreUnittest) unittest 1072 { 1073 static void test(Duration actual, long value, Duration expected, size_t line = __LINE__) 1074 { 1075 if ((actual /= value) != expected) 1076 throw new AssertError("op failed", __FILE__, line); 1077 1078 if (actual != expected) 1079 throw new AssertError("op assign failed", __FILE__, line); 1080 } 1081 1082 test(Duration(5), 7, Duration(0)); 1083 test(Duration(7), 5, Duration(1)); 1084 1085 test(Duration(5), -7, Duration(0)); 1086 test(Duration(7), -5, Duration(-1)); 1087 1088 test(Duration(-5), 7, Duration(0)); 1089 test(Duration(-7), 5, Duration(-1)); 1090 1091 test(Duration(-5), -7, Duration(0)); 1092 test(Duration(-7), -5, Duration(1)); 1093 1094 const cdur = Duration(12); 1095 immutable idur = Duration(12); 1096 static assert(!__traits(compiles, cdur /= 12)); 1097 static assert(!__traits(compiles, idur /= 12)); 1098 } 1099 1100 1101 /++ 1102 Divides two durations. 1103 1104 The legal types of arithmetic for $(D Duration) using this operator are 1105 1106 $(TABLE 1107 $(TR $(TD Duration) $(TD /) $(TD Duration) $(TD -->) $(TD long)) 1108 ) 1109 1110 Params: 1111 rhs = The duration to divide this $(D Duration) by. 1112 +/ 1113 long opBinary(string op)(Duration rhs) const nothrow @nogc 1114 if (op == "/") 1115 { 1116 return _hnsecs / rhs._hnsecs; 1117 } 1118 1119 version (CoreUnittest) unittest 1120 { 1121 assert(Duration(5) / Duration(7) == 0); 1122 assert(Duration(7) / Duration(5) == 1); 1123 assert(Duration(8) / Duration(4) == 2); 1124 1125 assert(Duration(5) / Duration(-7) == 0); 1126 assert(Duration(7) / Duration(-5) == -1); 1127 assert(Duration(8) / Duration(-4) == -2); 1128 1129 assert(Duration(-5) / Duration(7) == 0); 1130 assert(Duration(-7) / Duration(5) == -1); 1131 assert(Duration(-8) / Duration(4) == -2); 1132 1133 assert(Duration(-5) / Duration(-7) == 0); 1134 assert(Duration(-7) / Duration(-5) == 1); 1135 assert(Duration(-8) / Duration(-4) == 2); 1136 } 1137 1138 1139 /++ 1140 Multiplies an integral value and a $(D Duration). 1141 1142 The legal types of arithmetic for $(D Duration) using this operator 1143 overload are 1144 1145 $(TABLE 1146 $(TR $(TD long) $(TD *) $(TD Duration) $(TD -->) $(TD Duration)) 1147 ) 1148 1149 Params: 1150 value = The number of units to multiply this $(D Duration) by. 1151 +/ 1152 Duration opBinaryRight(string op)(long value) const nothrow @nogc 1153 if (op == "*") 1154 { 1155 return opBinary!op(value); 1156 } 1157 1158 version (CoreUnittest) unittest 1159 { 1160 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1161 { 1162 assert(5 * cast(D)Duration(7) == Duration(35)); 1163 assert(7 * cast(D)Duration(5) == Duration(35)); 1164 1165 assert(5 * cast(D)Duration(-7) == Duration(-35)); 1166 assert(7 * cast(D)Duration(-5) == Duration(-35)); 1167 1168 assert(-5 * cast(D)Duration(7) == Duration(-35)); 1169 assert(-7 * cast(D)Duration(5) == Duration(-35)); 1170 1171 assert(-5 * cast(D)Duration(-7) == Duration(35)); 1172 assert(-7 * cast(D)Duration(-5) == Duration(35)); 1173 1174 assert(0 * cast(D)Duration(-5) == Duration(0)); 1175 assert(0 * cast(D)Duration(5) == Duration(0)); 1176 } 1177 } 1178 1179 1180 /++ 1181 Returns the negation of this $(D Duration). 1182 +/ 1183 Duration opUnary(string op)() const nothrow @nogc 1184 if (op == "-") 1185 { 1186 return Duration(-_hnsecs); 1187 } 1188 1189 version (CoreUnittest) unittest 1190 { 1191 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1192 { 1193 assert(-(cast(D)Duration(7)) == Duration(-7)); 1194 assert(-(cast(D)Duration(5)) == Duration(-5)); 1195 assert(-(cast(D)Duration(-7)) == Duration(7)); 1196 assert(-(cast(D)Duration(-5)) == Duration(5)); 1197 assert(-(cast(D)Duration(0)) == Duration(0)); 1198 } 1199 } 1200 1201 1202 /++ 1203 $(RED TickDuration is Deprecated) 1204 1205 Returns a $(LREF TickDuration) with the same number of hnsecs as this 1206 $(D Duration). 1207 Note that the conventional way to convert between $(D Duration) and 1208 $(D TickDuration) is using $(REF to, std,conv), e.g.: 1209 $(D duration.to!TickDuration()) 1210 +/ 1211 deprecated TickDuration opCast(T)() const nothrow @nogc 1212 if (is(immutable T == immutable TickDuration)) 1213 { 1214 return TickDuration.from!"hnsecs"(_hnsecs); 1215 } 1216 1217 version (CoreUnittest) deprecated unittest 1218 { 1219 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1220 { 1221 foreach (units; AliasSeq!("seconds", "msecs", "usecs", "hnsecs")) 1222 { 1223 enum unitsPerSec = convert!("seconds", units)(1); 1224 1225 if (TickDuration.ticksPerSec >= unitsPerSec) 1226 { 1227 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 1228 { 1229 auto t = TickDuration.from!units(1); 1230 assertApprox(cast(T)cast(D)dur!units(1), t - TickDuration(1), t + TickDuration(1), units); 1231 t = TickDuration.from!units(2); 1232 assertApprox(cast(T)cast(D)dur!units(2), t - TickDuration(1), t + TickDuration(1), units); 1233 } 1234 } 1235 else 1236 { 1237 auto t = TickDuration.from!units(1); 1238 assert(t.to!(units, long)() == 0, units); 1239 t = TickDuration.from!units(1_000_000); 1240 assert(t.to!(units, long)() >= 900_000, units); 1241 assert(t.to!(units, long)() <= 1_100_000, units); 1242 } 1243 } 1244 } 1245 } 1246 1247 /++ 1248 Allow Duration to be used as a boolean. 1249 Returns: `true` if this duration is non-zero. 1250 +/ 1251 bool opCast(T : bool)() const nothrow @nogc 1252 { 1253 return _hnsecs != 0; 1254 } 1255 1256 version (CoreUnittest) unittest 1257 { 1258 auto d = 10.minutes; 1259 assert(d); 1260 assert(!(d - d)); 1261 assert(d + d); 1262 } 1263 1264 //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed. 1265 Duration opCast(T)() const nothrow @nogc 1266 if (is(immutable T == immutable Duration)) 1267 { 1268 return this; 1269 } 1270 1271 1272 /++ 1273 Splits out the Duration into the given units. 1274 1275 split takes the list of time units to split out as template arguments. 1276 The time unit strings must be given in decreasing order. How it returns 1277 the values for those units depends on the overload used. 1278 1279 The overload which accepts function arguments takes integral types in 1280 the order that the time unit strings were given, and those integers are 1281 passed by $(D ref). split assigns the values for the units to each 1282 corresponding integer. Any integral type may be used, but no attempt is 1283 made to prevent integer overflow, so don't use small integral types in 1284 circumstances where the values for those units aren't likely to fit in 1285 an integral type that small. 1286 1287 The overload with no arguments returns the values for the units in a 1288 struct with members whose names are the same as the given time unit 1289 strings. The members are all $(D long)s. This overload will also work 1290 with no time strings being given, in which case $(I all) of the time 1291 units from weeks through hnsecs will be provided (but no nsecs, since it 1292 would always be $(D 0)). 1293 1294 For both overloads, the entire value of the Duration is split among the 1295 units (rather than splitting the Duration across all units and then only 1296 providing the values for the requested units), so if only one unit is 1297 given, the result is equivalent to $(LREF total). 1298 1299 $(D "nsecs") is accepted by split, but $(D "years") and $(D "months") 1300 are not. 1301 1302 For negative durations, all of the split values will be negative. 1303 +/ 1304 template split(units...) 1305 if (allAreAcceptedUnits!("weeks", "days", "hours", "minutes", "seconds", 1306 "msecs", "usecs", "hnsecs", "nsecs")([units]) && 1307 unitsAreInDescendingOrder([units])) 1308 { 1309 /++ Ditto +/ 1310 void split(Args...)(out Args args) const nothrow @nogc 1311 if (units.length != 0 && args.length == units.length && allAreMutableIntegralTypes!Args) 1312 { 1313 long hnsecs = _hnsecs; 1314 foreach (i, unit; units) 1315 { 1316 static if (unit == "nsecs") 1317 args[i] = cast(Args[i])convert!("hnsecs", "nsecs")(hnsecs); 1318 else 1319 args[i] = cast(Args[i])splitUnitsFromHNSecs!unit(hnsecs); 1320 } 1321 } 1322 1323 /++ Ditto +/ 1324 auto split() const nothrow @nogc 1325 { 1326 static if (units.length == 0) 1327 return split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs")(); 1328 else 1329 { 1330 static string genMemberDecls() 1331 { 1332 string retval; 1333 foreach (unit; units) 1334 { 1335 retval ~= "long "; 1336 retval ~= unit; 1337 retval ~= "; "; 1338 } 1339 return retval; 1340 } 1341 1342 static struct SplitUnits 1343 { 1344 mixin(genMemberDecls()); 1345 } 1346 1347 static string genSplitCall() 1348 { 1349 auto retval = "split("; 1350 foreach (i, unit; units) 1351 { 1352 retval ~= "su."; 1353 retval ~= unit; 1354 if (i < units.length - 1) 1355 retval ~= ", "; 1356 else 1357 retval ~= ");"; 1358 } 1359 return retval; 1360 } 1361 1362 SplitUnits su = void; 1363 mixin(genSplitCall()); 1364 return su; 1365 } 1366 } 1367 1368 /+ 1369 Whether all of the given arguments are integral types. 1370 +/ 1371 private template allAreMutableIntegralTypes(Args...) 1372 { 1373 static if (Args.length == 0) 1374 enum allAreMutableIntegralTypes = true; 1375 else static if (!is(Args[0] == long) && 1376 !is(Args[0] == int) && 1377 !is(Args[0] == short) && 1378 !is(Args[0] == byte) && 1379 !is(Args[0] == ulong) && 1380 !is(Args[0] == uint) && 1381 !is(Args[0] == ushort) && 1382 !is(Args[0] == ubyte)) 1383 { 1384 enum allAreMutableIntegralTypes = false; 1385 } 1386 else 1387 enum allAreMutableIntegralTypes = allAreMutableIntegralTypes!(Args[1 .. $]); 1388 } 1389 1390 version (CoreUnittest) unittest 1391 { 1392 foreach (T; AliasSeq!(long, int, short, byte, ulong, uint, ushort, ubyte)) 1393 static assert(allAreMutableIntegralTypes!T); 1394 foreach (T; AliasSeq!(long, int, short, byte, ulong, uint, ushort, ubyte)) 1395 static assert(!allAreMutableIntegralTypes!(const T)); 1396 foreach (T; AliasSeq!(char, wchar, dchar, float, double, real, string)) 1397 static assert(!allAreMutableIntegralTypes!T); 1398 static assert(allAreMutableIntegralTypes!(long, int, short, byte)); 1399 static assert(!allAreMutableIntegralTypes!(long, int, short, char, byte)); 1400 static assert(!allAreMutableIntegralTypes!(long, int*, short)); 1401 } 1402 } 1403 1404 /// 1405 unittest 1406 { 1407 { 1408 auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223); 1409 long days; 1410 int seconds; 1411 short msecs; 1412 d.split!("days", "seconds", "msecs")(days, seconds, msecs); 1413 assert(days == 12); 1414 assert(seconds == 7 * 60); 1415 assert(msecs == 501); 1416 1417 auto splitStruct = d.split!("days", "seconds", "msecs")(); 1418 assert(splitStruct.days == 12); 1419 assert(splitStruct.seconds == 7 * 60); 1420 assert(splitStruct.msecs == 501); 1421 1422 auto fullSplitStruct = d.split(); 1423 assert(fullSplitStruct.weeks == 1); 1424 assert(fullSplitStruct.days == 5); 1425 assert(fullSplitStruct.hours == 0); 1426 assert(fullSplitStruct.minutes == 7); 1427 assert(fullSplitStruct.seconds == 0); 1428 assert(fullSplitStruct.msecs == 501); 1429 assert(fullSplitStruct.usecs == 223); 1430 assert(fullSplitStruct.hnsecs == 0); 1431 1432 assert(d.split!"minutes"().minutes == d.total!"minutes"); 1433 } 1434 1435 { 1436 auto d = dur!"days"(12); 1437 assert(d.split!"weeks"().weeks == 1); 1438 assert(d.split!"days"().days == 12); 1439 1440 assert(d.split().weeks == 1); 1441 assert(d.split().days == 5); 1442 } 1443 1444 { 1445 auto d = dur!"days"(7) + dur!"hnsecs"(42); 1446 assert(d.split!("seconds", "nsecs")().nsecs == 4200); 1447 } 1448 1449 { 1450 auto d = dur!"days"(-7) + dur!"hours"(-9); 1451 auto result = d.split!("days", "hours")(); 1452 assert(result.days == -7); 1453 assert(result.hours == -9); 1454 } 1455 } 1456 1457 version (CoreUnittest) pure nothrow unittest 1458 { 1459 foreach (D; AliasSeq!(const Duration, immutable Duration)) 1460 { 1461 D d = dur!"weeks"(3) + dur!"days"(5) + dur!"hours"(19) + dur!"minutes"(7) + 1462 dur!"seconds"(2) + dur!"hnsecs"(1234567); 1463 byte weeks; 1464 ubyte days; 1465 short hours; 1466 ushort minutes; 1467 int seconds; 1468 uint msecs; 1469 long usecs; 1470 ulong hnsecs; 1471 long nsecs; 1472 1473 d.split!("weeks", "days", "hours", "minutes", "seconds", "msecs", "usecs", "hnsecs", "nsecs") 1474 (weeks, days, hours, minutes, seconds, msecs, usecs, hnsecs, nsecs); 1475 assert(weeks == 3); 1476 assert(days == 5); 1477 assert(hours == 19); 1478 assert(minutes == 7); 1479 assert(seconds == 2); 1480 assert(msecs == 123); 1481 assert(usecs == 456); 1482 assert(hnsecs == 7); 1483 assert(nsecs == 0); 1484 1485 d.split!("weeks", "days", "hours", "seconds", "usecs")(weeks, days, hours, seconds, usecs); 1486 assert(weeks == 3); 1487 assert(days == 5); 1488 assert(hours == 19); 1489 assert(seconds == 422); 1490 assert(usecs == 123456); 1491 1492 d.split!("days", "minutes", "seconds", "nsecs")(days, minutes, seconds, nsecs); 1493 assert(days == 26); 1494 assert(minutes == 1147); 1495 assert(seconds == 2); 1496 assert(nsecs == 123456700); 1497 1498 d.split!("minutes", "msecs", "usecs", "hnsecs")(minutes, msecs, usecs, hnsecs); 1499 assert(minutes == 38587); 1500 assert(msecs == 2123); 1501 assert(usecs == 456); 1502 assert(hnsecs == 7); 1503 1504 { 1505 auto result = d.split!("weeks", "days", "hours", "minutes", "seconds", 1506 "msecs", "usecs", "hnsecs", "nsecs"); 1507 assert(result.weeks == 3); 1508 assert(result.days == 5); 1509 assert(result.hours == 19); 1510 assert(result.minutes == 7); 1511 assert(result.seconds == 2); 1512 assert(result.msecs == 123); 1513 assert(result.usecs == 456); 1514 assert(result.hnsecs == 7); 1515 assert(result.nsecs == 0); 1516 } 1517 1518 { 1519 auto result = d.split!("weeks", "days", "hours", "seconds", "usecs"); 1520 assert(result.weeks == 3); 1521 assert(result.days == 5); 1522 assert(result.hours == 19); 1523 assert(result.seconds == 422); 1524 assert(result.usecs == 123456); 1525 } 1526 1527 { 1528 auto result = d.split!("days", "minutes", "seconds", "nsecs")(); 1529 assert(result.days == 26); 1530 assert(result.minutes == 1147); 1531 assert(result.seconds == 2); 1532 assert(result.nsecs == 123456700); 1533 } 1534 1535 { 1536 auto result = d.split!("minutes", "msecs", "usecs", "hnsecs")(); 1537 assert(result.minutes == 38587); 1538 assert(result.msecs == 2123); 1539 assert(result.usecs == 456); 1540 assert(result.hnsecs == 7); 1541 } 1542 1543 { 1544 auto result = d.split(); 1545 assert(result.weeks == 3); 1546 assert(result.days == 5); 1547 assert(result.hours == 19); 1548 assert(result.minutes == 7); 1549 assert(result.seconds == 2); 1550 assert(result.msecs == 123); 1551 assert(result.usecs == 456); 1552 assert(result.hnsecs == 7); 1553 static assert(!is(typeof(result.nsecs))); 1554 } 1555 1556 static assert(!is(typeof(d.split("seconds", "hnsecs")(seconds)))); 1557 static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")(hnsecs, seconds, minutes)))); 1558 static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")(hnsecs, seconds, msecs)))); 1559 static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")(seconds, hnsecs, msecs)))); 1560 static assert(!is(typeof(d.split("seconds", "msecs", "msecs")(seconds, msecs, msecs)))); 1561 static assert(!is(typeof(d.split("hnsecs", "seconds", "minutes")()))); 1562 static assert(!is(typeof(d.split("hnsecs", "seconds", "msecs")()))); 1563 static assert(!is(typeof(d.split("seconds", "hnecs", "msecs")()))); 1564 static assert(!is(typeof(d.split("seconds", "msecs", "msecs")()))); 1565 alias AliasSeq!("nsecs", "hnsecs", "usecs", "msecs", "seconds", 1566 "minutes", "hours", "days", "weeks") timeStrs; 1567 foreach (i, str; timeStrs[1 .. $]) 1568 static assert(!is(typeof(d.split!(timeStrs[i - 1], str)()))); 1569 1570 D nd = -d; 1571 1572 { 1573 auto result = nd.split(); 1574 assert(result.weeks == -3); 1575 assert(result.days == -5); 1576 assert(result.hours == -19); 1577 assert(result.minutes == -7); 1578 assert(result.seconds == -2); 1579 assert(result.msecs == -123); 1580 assert(result.usecs == -456); 1581 assert(result.hnsecs == -7); 1582 } 1583 1584 { 1585 auto result = nd.split!("weeks", "days", "hours", "minutes", "seconds", "nsecs")(); 1586 assert(result.weeks == -3); 1587 assert(result.days == -5); 1588 assert(result.hours == -19); 1589 assert(result.minutes == -7); 1590 assert(result.seconds == -2); 1591 assert(result.nsecs == -123456700); 1592 } 1593 } 1594 } 1595 1596 1597 /++ 1598 Returns the total number of the given units in this $(D Duration). 1599 So, unlike $(D split), it does not strip out the larger units. 1600 +/ 1601 @property long total(string units)() const nothrow @nogc 1602 if (units == "weeks" || 1603 units == "days" || 1604 units == "hours" || 1605 units == "minutes" || 1606 units == "seconds" || 1607 units == "msecs" || 1608 units == "usecs" || 1609 units == "hnsecs" || 1610 units == "nsecs") 1611 { 1612 return convert!("hnsecs", units)(_hnsecs); 1613 } 1614 1615 /// 1616 unittest 1617 { 1618 assert(dur!"weeks"(12).total!"weeks" == 12); 1619 assert(dur!"weeks"(12).total!"days" == 84); 1620 1621 assert(dur!"days"(13).total!"weeks" == 1); 1622 assert(dur!"days"(13).total!"days" == 13); 1623 1624 assert(dur!"hours"(49).total!"days" == 2); 1625 assert(dur!"hours"(49).total!"hours" == 49); 1626 1627 assert(dur!"nsecs"(2007).total!"hnsecs" == 20); 1628 assert(dur!"nsecs"(2007).total!"nsecs" == 2000); 1629 } 1630 1631 version (CoreUnittest) unittest 1632 { 1633 foreach (D; AliasSeq!(const Duration, immutable Duration)) 1634 { 1635 assert((cast(D)dur!"weeks"(12)).total!"weeks" == 12); 1636 assert((cast(D)dur!"weeks"(12)).total!"days" == 84); 1637 1638 assert((cast(D)dur!"days"(13)).total!"weeks" == 1); 1639 assert((cast(D)dur!"days"(13)).total!"days" == 13); 1640 1641 assert((cast(D)dur!"hours"(49)).total!"days" == 2); 1642 assert((cast(D)dur!"hours"(49)).total!"hours" == 49); 1643 1644 assert((cast(D)dur!"nsecs"(2007)).total!"hnsecs" == 20); 1645 assert((cast(D)dur!"nsecs"(2007)).total!"nsecs" == 2000); 1646 } 1647 } 1648 1649 /// Ditto 1650 string toString() const scope nothrow 1651 { 1652 string result; 1653 this.toString((in char[] data) { result ~= data; }); 1654 return result; 1655 } 1656 1657 /// 1658 unittest 1659 { 1660 assert(Duration.zero.toString() == "0 hnsecs"); 1661 assert(weeks(5).toString() == "5 weeks"); 1662 assert(days(2).toString() == "2 days"); 1663 assert(hours(1).toString() == "1 hour"); 1664 assert(minutes(19).toString() == "19 minutes"); 1665 assert(seconds(42).toString() == "42 secs"); 1666 assert(msecs(42).toString() == "42 ms"); 1667 assert(usecs(27).toString() == "27 μs"); 1668 assert(hnsecs(5).toString() == "5 hnsecs"); 1669 1670 assert(seconds(121).toString() == "2 minutes and 1 sec"); 1671 assert((minutes(5) + seconds(3) + usecs(4)).toString() == 1672 "5 minutes, 3 secs, and 4 μs"); 1673 1674 assert(seconds(-42).toString() == "-42 secs"); 1675 assert(usecs(-5239492).toString() == "-5 secs, -239 ms, and -492 μs"); 1676 } 1677 1678 version (CoreUnittest) unittest 1679 { 1680 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1681 { 1682 assert((cast(D)Duration(0)).toString() == "0 hnsecs"); 1683 assert((cast(D)Duration(1)).toString() == "1 hnsec"); 1684 assert((cast(D)Duration(7)).toString() == "7 hnsecs"); 1685 assert((cast(D)Duration(10)).toString() == "1 μs"); 1686 assert((cast(D)Duration(20)).toString() == "2 μs"); 1687 assert((cast(D)Duration(10_000)).toString() == "1 ms"); 1688 assert((cast(D)Duration(20_000)).toString() == "2 ms"); 1689 assert((cast(D)Duration(10_000_000)).toString() == "1 sec"); 1690 assert((cast(D)Duration(20_000_000)).toString() == "2 secs"); 1691 assert((cast(D)Duration(600_000_000)).toString() == "1 minute"); 1692 assert((cast(D)Duration(1_200_000_000)).toString() == "2 minutes"); 1693 assert((cast(D)Duration(36_000_000_000)).toString() == "1 hour"); 1694 assert((cast(D)Duration(72_000_000_000)).toString() == "2 hours"); 1695 assert((cast(D)Duration(864_000_000_000)).toString() == "1 day"); 1696 assert((cast(D)Duration(1_728_000_000_000)).toString() == "2 days"); 1697 assert((cast(D)Duration(6_048_000_000_000)).toString() == "1 week"); 1698 assert((cast(D)Duration(12_096_000_000_000)).toString() == "2 weeks"); 1699 1700 assert((cast(D)Duration(12)).toString() == "1 μs and 2 hnsecs"); 1701 assert((cast(D)Duration(120_795)).toString() == "12 ms, 79 μs, and 5 hnsecs"); 1702 assert((cast(D)Duration(12_096_020_900_003)).toString() == "2 weeks, 2 secs, 90 ms, and 3 hnsecs"); 1703 1704 assert((cast(D)Duration(-1)).toString() == "-1 hnsecs"); 1705 assert((cast(D)Duration(-7)).toString() == "-7 hnsecs"); 1706 assert((cast(D)Duration(-10)).toString() == "-1 μs"); 1707 assert((cast(D)Duration(-20)).toString() == "-2 μs"); 1708 assert((cast(D)Duration(-10_000)).toString() == "-1 ms"); 1709 assert((cast(D)Duration(-20_000)).toString() == "-2 ms"); 1710 assert((cast(D)Duration(-10_000_000)).toString() == "-1 secs"); 1711 assert((cast(D)Duration(-20_000_000)).toString() == "-2 secs"); 1712 assert((cast(D)Duration(-600_000_000)).toString() == "-1 minutes"); 1713 assert((cast(D)Duration(-1_200_000_000)).toString() == "-2 minutes"); 1714 assert((cast(D)Duration(-36_000_000_000)).toString() == "-1 hours"); 1715 assert((cast(D)Duration(-72_000_000_000)).toString() == "-2 hours"); 1716 assert((cast(D)Duration(-864_000_000_000)).toString() == "-1 days"); 1717 assert((cast(D)Duration(-1_728_000_000_000)).toString() == "-2 days"); 1718 assert((cast(D)Duration(-6_048_000_000_000)).toString() == "-1 weeks"); 1719 assert((cast(D)Duration(-12_096_000_000_000)).toString() == "-2 weeks"); 1720 1721 assert((cast(D)Duration(-12)).toString() == "-1 μs and -2 hnsecs"); 1722 assert((cast(D)Duration(-120_795)).toString() == "-12 ms, -79 μs, and -5 hnsecs"); 1723 assert((cast(D)Duration(-12_096_020_900_003)).toString() == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs"); 1724 } 1725 } 1726 1727 1728 /++ 1729 Returns whether this $(D Duration) is negative. 1730 +/ 1731 @property bool isNegative() const nothrow @nogc 1732 { 1733 return _hnsecs < 0; 1734 } 1735 1736 version (CoreUnittest) unittest 1737 { 1738 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1739 { 1740 assert(!(cast(D)Duration(100)).isNegative); 1741 assert(!(cast(D)Duration(1)).isNegative); 1742 assert(!(cast(D)Duration(0)).isNegative); 1743 assert((cast(D)Duration(-1)).isNegative); 1744 assert((cast(D)Duration(-100)).isNegative); 1745 } 1746 } 1747 1748 1749 private: 1750 1751 /+ 1752 Params: 1753 hnsecs = The total number of hecto-nanoseconds in this $(D Duration). 1754 +/ 1755 this(long hnsecs) nothrow @nogc 1756 { 1757 _hnsecs = hnsecs; 1758 } 1759 1760 1761 long _hnsecs; 1762 } 1763 1764 /// 1765 unittest 1766 { 1767 import core.time; 1768 1769 // using the dur template 1770 auto numDays = dur!"days"(12); 1771 1772 // using the days function 1773 numDays = days(12); 1774 1775 // alternatively using UFCS syntax 1776 numDays = 12.days; 1777 1778 auto myTime = 100.msecs + 20_000.usecs + 30_000.hnsecs; 1779 assert(myTime == 123.msecs); 1780 } 1781 1782 // Ensure `toString` doesn't allocate if the sink doesn't 1783 version (CoreUnittest) @safe pure nothrow @nogc unittest 1784 { 1785 char[256] buffer; size_t len; 1786 scope sink = (in char[] data) { 1787 assert(data.length + len <= buffer.length); 1788 buffer[len .. len + data.length] = data[]; 1789 len += data.length; 1790 }; 1791 auto dur = Duration(-12_096_020_900_003); 1792 dur.toString(sink); 1793 assert(buffer[0 .. len] == "-2 weeks, -2 secs, -90 ms, and -3 hnsecs"); 1794 } 1795 1796 /++ 1797 $(RED TickDuration is DEPRECATED) 1798 1799 Converts a $(D TickDuration) to the given units as either an integral 1800 value or a floating point value. 1801 1802 Params: 1803 units = The units to convert to. Accepts $(D "seconds") and smaller 1804 only. 1805 T = The type to convert to (either an integral type or a 1806 floating point type). 1807 1808 td = The TickDuration to convert 1809 +/ 1810 deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead") 1811 T to(string units, T, D)(D td) @safe pure nothrow @nogc 1812 if (is(immutable D == immutable TickDuration) && 1813 (units == "seconds" || 1814 units == "msecs" || 1815 units == "usecs" || 1816 units == "hnsecs" || 1817 units == "nsecs")) 1818 { 1819 static if (__traits(isIntegral, T) && T.sizeof >= 4) 1820 { 1821 enum unitsPerSec = convert!("seconds", units)(1); 1822 1823 return cast(T) (td.length / (TickDuration.ticksPerSec / cast(real) unitsPerSec)); 1824 } 1825 else static if (__traits(isFloating, T)) 1826 { 1827 static if (units == "seconds") 1828 return td.length / cast(T)TickDuration.ticksPerSec; 1829 else 1830 { 1831 enum unitsPerSec = convert!("seconds", units)(1); 1832 1833 return cast(T) (td.length / 1834 (TickDuration.ticksPerSec / cast(real) unitsPerSec)); 1835 } 1836 } 1837 else 1838 static assert(0, "Incorrect template constraint."); 1839 } 1840 1841 /// 1842 deprecated unittest 1843 { 1844 auto t = TickDuration.from!"seconds"(1000); 1845 1846 long tl = to!("seconds",long)(t); 1847 assert(tl == 1000); 1848 1849 import core.stdc.math : fabs; 1850 double td = to!("seconds",double)(t); 1851 assert(fabs(td - 1000) < 0.001); 1852 } 1853 1854 deprecated unittest 1855 { 1856 void testFun(string U)() { 1857 auto t1v = 1000; 1858 auto t2v = 333; 1859 1860 auto t1 = TickDuration.from!U(t1v); 1861 auto t2 = TickDuration.from!U(t2v); 1862 1863 auto _str(F)(F val) 1864 { 1865 static if (is(F == int) || is(F == long)) 1866 return signedToTempString(val); 1867 else 1868 return unsignedToTempString(val); 1869 } 1870 1871 foreach (F; AliasSeq!(int,uint,long,ulong,float,double,real)) 1872 { 1873 F t1f = to!(U,F)(t1); 1874 F t2f = to!(U,F)(t2); 1875 auto t12d = t1 / t2v; 1876 auto t12m = t1 - t2; 1877 F t3f = to!(U,F)(t12d); 1878 F t4f = to!(U,F)(t12m); 1879 1880 1881 static if (is(F == float) || is(F == double) || is(F == real)) 1882 { 1883 assert((t1f - cast(F)t1v) <= 3.0, 1884 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t1f) ~ " " ~ 1885 doubleToString(cast(F)t1v) 1886 ); 1887 assert((t2f - cast(F)t2v) <= 3.0, 1888 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t2f) ~ " " ~ 1889 doubleToString(cast(F)t2v) 1890 ); 1891 assert(t3f - (cast(F)t1v) / (cast(F)t2v) <= 3.0, 1892 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t3f) ~ " " ~ 1893 doubleToString((cast(F)t1v)/(cast(F)t2v)) 1894 ); 1895 assert(t4f - (cast(F)(t1v - t2v)) <= 3.0, 1896 F.stringof ~ " " ~ U ~ " " ~ doubleToString(t4f) ~ " " ~ 1897 doubleToString(cast(F)(t1v - t2v)) 1898 ); 1899 } 1900 else 1901 { 1902 // even though this should be exact math it is not as internal 1903 // in "to" floating point is used 1904 assert(_abs(t1f) - _abs(cast(F)t1v) <= 3, 1905 F.stringof ~ " " ~ U ~ " " ~ _str(t1f) ~ " " ~ 1906 _str(cast(F)t1v) 1907 ); 1908 assert(_abs(t2f) - _abs(cast(F)t2v) <= 3, 1909 F.stringof ~ " " ~ U ~ " " ~ _str(t2f) ~ " " ~ 1910 _str(cast(F)t2v) 1911 ); 1912 assert(_abs(t3f) - _abs((cast(F)t1v) / (cast(F)t2v)) <= 3, 1913 F.stringof ~ " " ~ U ~ " " ~ _str(t3f) ~ " " ~ 1914 _str((cast(F)t1v) / (cast(F)t2v)) 1915 ); 1916 assert(_abs(t4f) - _abs((cast(F)t1v) - (cast(F)t2v)) <= 3, 1917 F.stringof ~ " " ~ U ~ " " ~ _str(t4f) ~ " " ~ 1918 _str((cast(F)t1v) - (cast(F)t2v)) 1919 ); 1920 } 1921 } 1922 } 1923 1924 testFun!"seconds"(); 1925 testFun!"msecs"(); 1926 testFun!"usecs"(); 1927 } 1928 1929 /++ 1930 These allow you to construct a $(D Duration) from the given time units 1931 with the given length. 1932 1933 You can either use the generic function $(D dur) and give it the units as 1934 a $(D string) or use the named aliases. 1935 1936 The possible values for units are $(D "weeks"), $(D "days"), $(D "hours"), 1937 $(D "minutes"), $(D "seconds"), $(D "msecs") (milliseconds), $(D "usecs"), 1938 (microseconds), $(D "hnsecs") (hecto-nanoseconds, i.e. 100 ns), and 1939 $(D "nsecs"). 1940 1941 Params: 1942 units = The time units of the $(D Duration) (e.g. $(D "days")). 1943 length = The number of units in the $(D Duration). 1944 +/ 1945 Duration dur(string units)(long length) @safe pure nothrow @nogc 1946 if (units == "weeks" || 1947 units == "days" || 1948 units == "hours" || 1949 units == "minutes" || 1950 units == "seconds" || 1951 units == "msecs" || 1952 units == "usecs" || 1953 units == "hnsecs" || 1954 units == "nsecs") 1955 { 1956 return Duration(convert!(units, "hnsecs")(length)); 1957 } 1958 1959 alias weeks = dur!"weeks"; /// Ditto 1960 alias days = dur!"days"; /// Ditto 1961 alias hours = dur!"hours"; /// Ditto 1962 alias minutes = dur!"minutes"; /// Ditto 1963 alias seconds = dur!"seconds"; /// Ditto 1964 alias msecs = dur!"msecs"; /// Ditto 1965 alias usecs = dur!"usecs"; /// Ditto 1966 alias hnsecs = dur!"hnsecs"; /// Ditto 1967 alias nsecs = dur!"nsecs"; /// Ditto 1968 1969 /// 1970 unittest 1971 { 1972 // Generic 1973 assert(dur!"weeks"(142).total!"weeks" == 142); 1974 assert(dur!"days"(142).total!"days" == 142); 1975 assert(dur!"hours"(142).total!"hours" == 142); 1976 assert(dur!"minutes"(142).total!"minutes" == 142); 1977 assert(dur!"seconds"(142).total!"seconds" == 142); 1978 assert(dur!"msecs"(142).total!"msecs" == 142); 1979 assert(dur!"usecs"(142).total!"usecs" == 142); 1980 assert(dur!"hnsecs"(142).total!"hnsecs" == 142); 1981 assert(dur!"nsecs"(142).total!"nsecs" == 100); 1982 1983 // Non-generic 1984 assert(weeks(142).total!"weeks" == 142); 1985 assert(days(142).total!"days" == 142); 1986 assert(hours(142).total!"hours" == 142); 1987 assert(minutes(142).total!"minutes" == 142); 1988 assert(seconds(142).total!"seconds" == 142); 1989 assert(msecs(142).total!"msecs" == 142); 1990 assert(usecs(142).total!"usecs" == 142); 1991 assert(hnsecs(142).total!"hnsecs" == 142); 1992 assert(nsecs(142).total!"nsecs" == 100); 1993 } 1994 1995 unittest 1996 { 1997 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 1998 { 1999 assert(dur!"weeks"(7).total!"weeks" == 7); 2000 assert(dur!"days"(7).total!"days" == 7); 2001 assert(dur!"hours"(7).total!"hours" == 7); 2002 assert(dur!"minutes"(7).total!"minutes" == 7); 2003 assert(dur!"seconds"(7).total!"seconds" == 7); 2004 assert(dur!"msecs"(7).total!"msecs" == 7); 2005 assert(dur!"usecs"(7).total!"usecs" == 7); 2006 assert(dur!"hnsecs"(7).total!"hnsecs" == 7); 2007 assert(dur!"nsecs"(7).total!"nsecs" == 0); 2008 2009 assert(dur!"weeks"(1007) == weeks(1007)); 2010 assert(dur!"days"(1007) == days(1007)); 2011 assert(dur!"hours"(1007) == hours(1007)); 2012 assert(dur!"minutes"(1007) == minutes(1007)); 2013 assert(dur!"seconds"(1007) == seconds(1007)); 2014 assert(dur!"msecs"(1007) == msecs(1007)); 2015 assert(dur!"usecs"(1007) == usecs(1007)); 2016 assert(dur!"hnsecs"(1007) == hnsecs(1007)); 2017 assert(dur!"nsecs"(10) == nsecs(10)); 2018 } 2019 } 2020 2021 // used in MonoTimeImpl 2022 private string _clockTypeName(ClockType clockType) 2023 { 2024 final switch (clockType) 2025 { 2026 foreach (name; __traits(allMembers, ClockType)) 2027 { 2028 case __traits(getMember, ClockType, name): 2029 return name; 2030 } 2031 } 2032 assert(0); 2033 } 2034 2035 // used in MonoTimeImpl 2036 private size_t _clockTypeIdx(ClockType clockType) 2037 { 2038 final switch (clockType) 2039 { 2040 foreach (i, name; __traits(allMembers, ClockType)) 2041 { 2042 case __traits(getMember, ClockType, name): 2043 return i; 2044 } 2045 } 2046 assert(0); 2047 } 2048 2049 2050 /++ 2051 alias for $(D MonoTimeImpl) instantiated with $(D ClockType.normal). This is 2052 what most programs should use. It's also what much of $(D MonoTimeImpl) uses 2053 in its documentation (particularly in the examples), because that's what's 2054 going to be used in most code. 2055 +/ 2056 alias MonoTime = MonoTimeImpl!(ClockType.normal); 2057 2058 /++ 2059 Represents a timestamp of the system's monotonic clock. 2060 2061 A monotonic clock is one which always goes forward and never moves 2062 backwards, unlike the system's wall clock time (as represented by 2063 $(REF SysTime, std,datetime)). The system's wall clock time can be adjusted 2064 by the user or by the system itself via services such as NTP, so it is 2065 unreliable to use the wall clock time for timing. Timers which use the wall 2066 clock time could easily end up never going off due to changes made to the 2067 wall clock time or otherwise waiting for a different period of time than 2068 that specified by the programmer. However, because the monotonic clock 2069 always increases at a fixed rate and is not affected by adjustments to the 2070 wall clock time, it is ideal for use with timers or anything which requires 2071 high precision timing. 2072 2073 So, MonoTime should be used for anything involving timers and timing, 2074 whereas $(REF SysTime, std,datetime) should be used when the wall clock time 2075 is required. 2076 2077 The monotonic clock has no relation to wall clock time. Rather, it holds 2078 its time as the number of ticks of the clock which have occurred since the 2079 clock started (typically when the system booted up). So, to determine how 2080 much time has passed between two points in time, one monotonic time is 2081 subtracted from the other to determine the number of ticks which occurred 2082 between the two points of time, and those ticks are divided by the number of 2083 ticks that occur every second (as represented by MonoTime.ticksPerSecond) 2084 to get a meaningful duration of time. Normally, MonoTime does these 2085 calculations for the programmer, but the $(D ticks) and $(D ticksPerSecond) 2086 properties are provided for those who require direct access to the system 2087 ticks. The normal way that MonoTime would be used is 2088 2089 -------------------- 2090 MonoTime before = MonoTime.currTime; 2091 // do stuff... 2092 MonoTime after = MonoTime.currTime; 2093 Duration timeElapsed = after - before; 2094 -------------------- 2095 2096 $(LREF MonoTime) is an alias to $(D MonoTimeImpl!(ClockType.normal)) and is 2097 what most programs should use for the monotonic clock, so that's what is 2098 used in most of $(D MonoTimeImpl)'s documentation. But $(D MonoTimeImpl) 2099 can be instantiated with other clock types for those rare programs that need 2100 it. 2101 2102 See_Also: 2103 $(LREF ClockType) 2104 +/ 2105 struct MonoTimeImpl(ClockType clockType) 2106 { 2107 private enum _clockIdx = _clockTypeIdx(clockType); 2108 private enum _clockName = _clockTypeName(clockType); 2109 2110 @safe: 2111 2112 version (Windows) 2113 { 2114 static if (clockType != ClockType.coarse && 2115 clockType != ClockType.normal && 2116 clockType != ClockType.precise) 2117 { 2118 static assert(0, "ClockType." ~ _clockName ~ 2119 " is not supported by MonoTimeImpl on this system."); 2120 } 2121 } 2122 else version (Darwin) 2123 { 2124 static if (clockType != ClockType.coarse && 2125 clockType != ClockType.normal && 2126 clockType != ClockType.precise) 2127 { 2128 static assert(0, "ClockType." ~ _clockName ~ 2129 " is not supported by MonoTimeImpl on this system."); 2130 } 2131 } 2132 else version (Posix) 2133 { 2134 enum clockArg = _posixClock(clockType); 2135 } 2136 else version (WASI) 2137 { 2138 static if (clockType != ClockType.normal && 2139 clockType != ClockType.raw) 2140 { 2141 static assert(0, "ClockType." ~ _clockName ~ 2142 " is not supported by MonoTimeImpl on this system."); 2143 } 2144 } 2145 else static assert(0, "Unsupported platform"); 2146 2147 // POD value, test mutable/const/immutable conversion 2148 version (CoreUnittest) unittest 2149 { 2150 MonoTimeImpl m; 2151 const MonoTimeImpl cm = m; 2152 immutable MonoTimeImpl im = m; 2153 m = cm; 2154 m = im; 2155 } 2156 2157 /++ 2158 The current time of the system's monotonic clock. This has no relation 2159 to the wall clock time, as the wall clock time can be adjusted (e.g. 2160 by NTP), whereas the monotonic clock always moves forward. The source 2161 of the monotonic time is system-specific. 2162 2163 On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X, 2164 $(D mach_absolute_time) is used, while on other POSIX systems, 2165 $(D clock_gettime) is used. 2166 2167 $(RED Warning): On some systems, the monotonic clock may stop counting 2168 when the computer goes to sleep or hibernates. So, the 2169 monotonic clock may indicate less time than has actually 2170 passed if that occurs. This is known to happen on 2171 Mac OS X. It has not been tested whether it occurs on 2172 either Windows or Linux. 2173 +/ 2174 static @property MonoTimeImpl currTime() @trusted nothrow @nogc 2175 { 2176 if (ticksPerSecond == 0) 2177 { 2178 import core.internal.abort : abort; 2179 abort("MonoTimeImpl!(ClockType." ~ _clockName ~ 2180 ") failed to get the frequency of the system's monotonic clock."); 2181 } 2182 2183 version (Windows) 2184 { 2185 long ticks = void; 2186 QueryPerformanceCounter(&ticks); 2187 return MonoTimeImpl(ticks); 2188 } 2189 else version (Darwin) 2190 return MonoTimeImpl(mach_absolute_time()); 2191 else version (Posix) 2192 { 2193 timespec ts = void; 2194 immutable error = clock_gettime(clockArg, &ts); 2195 // clockArg is supported and if tv_sec is long or larger 2196 // overflow won't happen before 292 billion years A.D. 2197 static if (ts.tv_sec.max < long.max) 2198 { 2199 if (error) 2200 { 2201 import core.internal.abort : abort; 2202 abort("Call to clock_gettime failed."); 2203 } 2204 } 2205 return MonoTimeImpl(convClockFreq(ts.tv_sec * 1_000_000_000L + ts.tv_nsec, 2206 1_000_000_000L, 2207 ticksPerSecond)); 2208 } else version (WASI) { 2209 time_result_t timestamp_res = clock_time_get(CLOCK_REALTIME, -1); 2210 if (timestamp_res.errno) 2211 { 2212 import core.internal.abort : abort; 2213 abort("Call to clock_time_get failed."); 2214 } 2215 return MonoTimeImpl(timestamp_res.timestamp); 2216 } 2217 } 2218 2219 2220 static @property pure nothrow @nogc 2221 { 2222 /++ 2223 A $(D MonoTime) of $(D 0) ticks. It's provided to be consistent with 2224 $(D Duration.zero), and it's more explicit than $(D MonoTime.init). 2225 +/ 2226 MonoTimeImpl zero() { return MonoTimeImpl(0); } 2227 2228 /++ 2229 Largest $(D MonoTime) possible. 2230 +/ 2231 MonoTimeImpl max() { return MonoTimeImpl(long.max); } 2232 2233 /++ 2234 Most negative $(D MonoTime) possible. 2235 +/ 2236 MonoTimeImpl min() { return MonoTimeImpl(long.min); } 2237 } 2238 2239 version (CoreUnittest) unittest 2240 { 2241 assert(MonoTimeImpl.zero == MonoTimeImpl(0)); 2242 assert(MonoTimeImpl.max == MonoTimeImpl(long.max)); 2243 assert(MonoTimeImpl.min == MonoTimeImpl(long.min)); 2244 assert(MonoTimeImpl.min < MonoTimeImpl.zero); 2245 assert(MonoTimeImpl.zero < MonoTimeImpl.max); 2246 assert(MonoTimeImpl.min < MonoTimeImpl.max); 2247 } 2248 2249 2250 /++ 2251 Compares this MonoTime with the given MonoTime. 2252 2253 Returns: 2254 $(BOOKTABLE, 2255 $(TR $(TD this < rhs) $(TD < 0)) 2256 $(TR $(TD this == rhs) $(TD 0)) 2257 $(TR $(TD this > rhs) $(TD > 0)) 2258 ) 2259 +/ 2260 int opCmp(MonoTimeImpl rhs) const pure nothrow @nogc 2261 { 2262 return (_ticks > rhs._ticks) - (_ticks < rhs._ticks); 2263 } 2264 2265 version (CoreUnittest) unittest 2266 { 2267 import core.internal.traits : rvalueOf; 2268 const t = MonoTimeImpl.currTime; 2269 assert(t == rvalueOf(t)); 2270 } 2271 2272 version (CoreUnittest) unittest 2273 { 2274 import core.internal.traits : rvalueOf; 2275 const before = MonoTimeImpl.currTime; 2276 auto after = MonoTimeImpl(before._ticks + 42); 2277 assert(before < after); 2278 assert(rvalueOf(before) <= before); 2279 assert(rvalueOf(after) > before); 2280 assert(after >= rvalueOf(after)); 2281 } 2282 2283 version (CoreUnittest) unittest 2284 { 2285 const currTime = MonoTimeImpl.currTime; 2286 assert(MonoTimeImpl(long.max) > MonoTimeImpl(0)); 2287 assert(MonoTimeImpl(0) > MonoTimeImpl(long.min)); 2288 assert(MonoTimeImpl(long.max) > currTime); 2289 assert(currTime > MonoTimeImpl(0)); 2290 assert(MonoTimeImpl(0) < currTime); 2291 assert(MonoTimeImpl(0) < MonoTimeImpl(long.max)); 2292 assert(MonoTimeImpl(long.min) < MonoTimeImpl(0)); 2293 } 2294 2295 2296 /++ 2297 Subtracting two MonoTimes results in a $(LREF Duration) representing 2298 the amount of time which elapsed between them. 2299 2300 The primary way that programs should time how long something takes is to 2301 do 2302 -------------------- 2303 MonoTime before = MonoTime.currTime; 2304 // do stuff 2305 MonoTime after = MonoTime.currTime; 2306 2307 // How long it took. 2308 Duration timeElapsed = after - before; 2309 -------------------- 2310 or to use a wrapper (such as a stop watch type) which does that. 2311 2312 $(RED Warning): 2313 Because $(LREF Duration) is in hnsecs, whereas MonoTime is in system 2314 ticks, it's usually the case that this assertion will fail 2315 -------------------- 2316 auto before = MonoTime.currTime; 2317 // do stuff 2318 auto after = MonoTime.currTime; 2319 auto timeElapsed = after - before; 2320 assert(before + timeElapsed == after); 2321 -------------------- 2322 2323 This is generally fine, and by its very nature, converting from 2324 system ticks to any type of seconds (hnsecs, nsecs, etc.) will 2325 introduce rounding errors, but if code needs to avoid any of the 2326 small rounding errors introduced by conversion, then it needs to use 2327 MonoTime's $(D ticks) property and keep all calculations in ticks 2328 rather than using $(LREF Duration). 2329 +/ 2330 Duration opBinary(string op)(MonoTimeImpl rhs) const pure nothrow @nogc 2331 if (op == "-") 2332 { 2333 immutable diff = _ticks - rhs._ticks; 2334 return Duration(convClockFreq(diff , ticksPerSecond, hnsecsPer!"seconds")); 2335 } 2336 2337 version (CoreUnittest) unittest 2338 { 2339 import core.internal.traits : rvalueOf; 2340 const t = MonoTimeImpl.currTime; 2341 assert(t - rvalueOf(t) == Duration.zero); 2342 static assert(!__traits(compiles, t + t)); 2343 } 2344 2345 version (CoreUnittest) unittest 2346 { 2347 static void test(const scope MonoTimeImpl before, const scope MonoTimeImpl after, const scope Duration min) 2348 { 2349 immutable diff = after - before; 2350 assert(diff >= min); 2351 auto calcAfter = before + diff; 2352 assertApprox(calcAfter, calcAfter - Duration(1), calcAfter + Duration(1)); 2353 assert(before - after == -diff); 2354 } 2355 2356 const before = MonoTimeImpl.currTime; 2357 test(before, MonoTimeImpl(before._ticks + 4202), Duration.zero); 2358 test(before, MonoTimeImpl.currTime, Duration.zero); 2359 2360 const durLargerUnits = dur!"minutes"(7) + dur!"seconds"(22); 2361 test(before, before + durLargerUnits + dur!"msecs"(33) + dur!"hnsecs"(571), durLargerUnits); 2362 } 2363 2364 2365 /++ 2366 Adding or subtracting a $(LREF Duration) to/from a MonoTime results in 2367 a MonoTime which is adjusted by that amount. 2368 +/ 2369 MonoTimeImpl opBinary(string op)(Duration rhs) const pure nothrow @nogc 2370 if (op == "+" || op == "-") 2371 { 2372 immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond); 2373 mixin("return MonoTimeImpl(_ticks " ~ op ~ " rhsConverted);"); 2374 } 2375 2376 version (CoreUnittest) unittest 2377 { 2378 const t = MonoTimeImpl.currTime; 2379 assert(t + Duration(0) == t); 2380 assert(t - Duration(0) == t); 2381 } 2382 2383 version (CoreUnittest) unittest 2384 { 2385 const t = MonoTimeImpl.currTime; 2386 2387 // We reassign ticks in order to get the same rounding errors 2388 // that we should be getting with Duration (e.g. MonoTimeImpl may be 2389 // at a higher precision than hnsecs, meaning that 7333 would be 2390 // truncated when converting to hnsecs). 2391 long ticks = 7333; 2392 auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds"); 2393 ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond); 2394 2395 assert(t - Duration(hnsecs) == MonoTimeImpl(t._ticks - ticks)); 2396 assert(t + Duration(hnsecs) == MonoTimeImpl(t._ticks + ticks)); 2397 } 2398 2399 2400 /++ Ditto +/ 2401 ref MonoTimeImpl opOpAssign(string op)(Duration rhs) pure nothrow @nogc 2402 if (op == "+" || op == "-") 2403 { 2404 immutable rhsConverted = convClockFreq(rhs._hnsecs, hnsecsPer!"seconds", ticksPerSecond); 2405 mixin("_ticks " ~ op ~ "= rhsConverted;"); 2406 return this; 2407 } 2408 2409 version (CoreUnittest) unittest 2410 { 2411 auto mt = MonoTimeImpl.currTime; 2412 const initial = mt; 2413 mt += Duration(0); 2414 assert(mt == initial); 2415 mt -= Duration(0); 2416 assert(mt == initial); 2417 2418 // We reassign ticks in order to get the same rounding errors 2419 // that we should be getting with Duration (e.g. MonoTimeImpl may be 2420 // at a higher precision than hnsecs, meaning that 7333 would be 2421 // truncated when converting to hnsecs). 2422 long ticks = 7333; 2423 auto hnsecs = convClockFreq(ticks, ticksPerSecond, hnsecsPer!"seconds"); 2424 ticks = convClockFreq(hnsecs, hnsecsPer!"seconds", ticksPerSecond); 2425 auto before = MonoTimeImpl(initial._ticks - ticks); 2426 2427 assert((mt -= Duration(hnsecs)) == before); 2428 assert(mt == before); 2429 assert((mt += Duration(hnsecs)) == initial); 2430 assert(mt == initial); 2431 } 2432 2433 2434 /++ 2435 The number of ticks in the monotonic time. 2436 2437 Most programs should not use this directly, but it's exposed for those 2438 few programs that need it. 2439 2440 The main reasons that a program might need to use ticks directly is if 2441 the system clock has higher precision than hnsecs, and the program needs 2442 that higher precision, or if the program needs to avoid the rounding 2443 errors caused by converting to hnsecs. 2444 +/ 2445 @property long ticks() const pure nothrow @nogc 2446 { 2447 return _ticks; 2448 } 2449 2450 version (CoreUnittest) unittest 2451 { 2452 const mt = MonoTimeImpl.currTime; 2453 assert(mt.ticks == mt._ticks); 2454 } 2455 2456 2457 /++ 2458 The number of ticks that MonoTime has per second - i.e. the resolution 2459 or frequency of the system's monotonic clock. 2460 2461 e.g. if the system clock had a resolution of microseconds, then 2462 ticksPerSecond would be $(D 1_000_000). 2463 +/ 2464 static @property long ticksPerSecond() pure nothrow @nogc 2465 { 2466 return _ticksPerSecond[_clockIdx]; 2467 } 2468 2469 version (CoreUnittest) unittest 2470 { 2471 assert(MonoTimeImpl.ticksPerSecond == _ticksPerSecond[_clockIdx]); 2472 } 2473 2474 2475 /// 2476 string toString() const pure nothrow 2477 { 2478 static if (clockType == ClockType.normal) 2479 return "MonoTime(" ~ signedToTempString(_ticks) ~ " ticks, " ~ signedToTempString(ticksPerSecond) ~ " ticks per second)"; 2480 else 2481 return "MonoTimeImpl!(ClockType." ~ _clockName ~ ")(" ~ signedToTempString(_ticks) ~ " ticks, " ~ 2482 signedToTempString(ticksPerSecond) ~ " ticks per second)"; 2483 } 2484 2485 version (CoreUnittest) unittest 2486 { 2487 import core.internal.util.math : min; 2488 2489 static void eat(ref string s, const(char)[] exp) 2490 { 2491 assert(s[0 .. min($, exp.length)] == exp, s~" != "~exp); 2492 s = s[exp.length .. $]; 2493 } 2494 2495 immutable mt = MonoTimeImpl.currTime; 2496 auto str = mt.toString(); 2497 static if (is(typeof(this) == MonoTime)) 2498 eat(str, "MonoTime("); 2499 else 2500 eat(str, "MonoTimeImpl!(ClockType."~_clockName~")("); 2501 2502 eat(str, signedToTempString(mt._ticks)); 2503 eat(str, " ticks, "); 2504 eat(str, signedToTempString(ticksPerSecond)); 2505 eat(str, " ticks per second)"); 2506 } 2507 2508 private: 2509 2510 // static immutable long _ticksPerSecond; 2511 2512 version (CoreUnittest) unittest 2513 { 2514 assert(_ticksPerSecond[_clockIdx]); 2515 } 2516 2517 2518 long _ticks; 2519 } 2520 2521 // This is supposed to be a static variable in MonoTimeImpl with the static 2522 // constructor being in there, but https://issues.dlang.org/show_bug.cgi?id=14517 2523 // prevents that from working. However, moving it back to a static ctor will 2524 // reraise issues with other systems using MonoTime, so we should leave this 2525 // here even when that bug is fixed. 2526 private immutable long[__traits(allMembers, ClockType).length] _ticksPerSecond; 2527 2528 // This is called directly from the runtime initilization function (rt_init), 2529 // instead of using a static constructor. Other subsystems inside the runtime 2530 // (namely, the GC) may need time functionality, but cannot wait until the 2531 // static ctors have run. Therefore, we initialize these specially. Because 2532 // it's a normal function, we need to do some dangerous casting PLEASE take 2533 // care when modifying this function, and it should NOT be called except from 2534 // the runtime init. 2535 // 2536 // NOTE: the code below SPECIFICALLY does not assert when it cannot initialize 2537 // the ticks per second array. This allows cases where a clock is never used on 2538 // a system that doesn't support it. See bugzilla issue 2539 // https://issues.dlang.org/show_bug.cgi?id=14863 2540 // The assert will occur when someone attempts to use _ticksPerSecond for that 2541 // value. 2542 extern(C) void _d_initMonoTime() @nogc nothrow 2543 { 2544 // We need a mutable pointer to the ticksPerSecond array. Although this 2545 // would appear to break immutability, it is logically the same as a static 2546 // ctor. So we should ONLY write these values once (we will check for 0 2547 // values when setting to ensure this is truly only called once). 2548 auto tps = cast(long[])_ticksPerSecond[]; 2549 2550 // If we try to do anything with ClockType in the documentation build, it'll 2551 // trigger the static assertions related to ClockType, since the 2552 // documentation build defines all of the possible ClockTypes, which won't 2553 // work when they're used in the static ifs, because no system supports them 2554 // all. 2555 version (CoreDdoc) 2556 {} 2557 else version (Windows) 2558 { 2559 long ticksPerSecond; 2560 if (QueryPerformanceFrequency(&ticksPerSecond) != 0) 2561 { 2562 foreach (i, typeStr; __traits(allMembers, ClockType)) 2563 { 2564 // ensure we are only writing immutable data once 2565 if (tps[i] != 0) 2566 // should only be called once 2567 assert(0); 2568 tps[i] = ticksPerSecond; 2569 } 2570 } 2571 } 2572 else version (Darwin) 2573 { 2574 immutable long ticksPerSecond = machTicksPerSecond(); 2575 foreach (i, typeStr; __traits(allMembers, ClockType)) 2576 { 2577 // ensure we are only writing immutable data once 2578 if (tps[i] != 0) 2579 // should only be called once 2580 assert(0); 2581 tps[i] = ticksPerSecond; 2582 } 2583 } 2584 else version (Posix) 2585 { 2586 timespec ts; 2587 foreach (i, typeStr; __traits(allMembers, ClockType)) 2588 { 2589 static if (typeStr != "second") 2590 { 2591 enum clockArg = _posixClock(__traits(getMember, ClockType, typeStr)); 2592 if (clock_getres(clockArg, &ts) == 0) 2593 { 2594 // ensure we are only writing immutable data once 2595 if (tps[i] != 0) 2596 // should only be called once 2597 assert(0); 2598 2599 // For some reason, on some systems, clock_getres returns 2600 // a resolution which is clearly wrong: 2601 // - it's a millisecond or worse, but the time is updated 2602 // much more frequently than that. 2603 // - it's negative 2604 // - it's zero 2605 // In such cases, we'll just use nanosecond resolution. 2606 tps[i] = ts.tv_sec != 0 || ts.tv_nsec <= 0 || ts.tv_nsec >= 1000 2607 ? 1_000_000_000L : 1_000_000_000L / ts.tv_nsec; 2608 } 2609 } 2610 } 2611 } 2612 } 2613 2614 2615 // Tests for MonoTimeImpl.currTime. It has to be outside, because MonoTimeImpl 2616 // is a template. This unittest block also makes sure that MonoTimeImpl actually 2617 // is instantiated with all of the various ClockTypes so that those types and 2618 // their tests are compiled and run. 2619 unittest 2620 { 2621 // This test is separate so that it can be tested with MonoTime and not just 2622 // MonoTimeImpl. 2623 auto norm1 = MonoTime.currTime; 2624 auto norm2 = MonoTimeImpl!(ClockType.normal).currTime; 2625 assert(norm1 <= norm2); 2626 2627 static bool clockSupported(ClockType c) 2628 { 2629 // Skip unsupported clocks on older linux kernels, assume that only 2630 // CLOCK_MONOTONIC and CLOCK_REALTIME exist, as that is the lowest 2631 // common denominator supported by all versions of Linux pre-2.6.12. 2632 version (Linux_Pre_2639) 2633 return c == ClockType.normal || c == ClockType.precise; 2634 else 2635 return c != ClockType.second; // second doesn't work with MonoTimeImpl 2636 2637 } 2638 2639 foreach (typeStr; __traits(allMembers, ClockType)) 2640 { 2641 mixin("alias type = ClockType." ~ typeStr ~ ";"); 2642 static if (clockSupported(type)) 2643 { 2644 auto v1 = MonoTimeImpl!type.currTime; 2645 auto v2 = MonoTimeImpl!type.currTime; 2646 scope(failure) 2647 { 2648 printf("%s: v1 %s, v2 %s, tps %s\n", 2649 (type.stringof ~ "\0").ptr, 2650 numToStringz(v1._ticks), 2651 numToStringz(v2._ticks), 2652 numToStringz(typeof(v1).ticksPerSecond)); 2653 } 2654 assert(v1 <= v2); 2655 2656 foreach (otherStr; __traits(allMembers, ClockType)) 2657 { 2658 mixin("alias other = ClockType." ~ otherStr ~ ";"); 2659 static if (clockSupported(other)) 2660 { 2661 static assert(is(typeof({auto o1 = MonTimeImpl!other.currTime; auto b = v1 <= o1;})) == 2662 is(type == other)); 2663 } 2664 } 2665 } 2666 } 2667 } 2668 2669 2670 /++ 2671 Converts the given time from one clock frequency/resolution to another. 2672 2673 See_Also: 2674 $(LREF ticksToNSecs) 2675 +/ 2676 long convClockFreq(long ticks, long srcTicksPerSecond, long dstTicksPerSecond) @safe pure nothrow @nogc 2677 { 2678 // This would be more straightforward with floating point arithmetic, 2679 // but we avoid it here in order to avoid the rounding errors that that 2680 // introduces. Also, by splitting out the units in this way, we're able 2681 // to deal with much larger values before running into problems with 2682 // integer overflow. 2683 return ticks / srcTicksPerSecond * dstTicksPerSecond + 2684 ticks % srcTicksPerSecond * dstTicksPerSecond / srcTicksPerSecond; 2685 } 2686 2687 /// 2688 unittest 2689 { 2690 // one tick is one second -> one tick is a hecto-nanosecond 2691 assert(convClockFreq(45, 1, 10_000_000) == 450_000_000); 2692 2693 // one tick is one microsecond -> one tick is a millisecond 2694 assert(convClockFreq(9029, 1_000_000, 1_000) == 9); 2695 2696 // one tick is 1/3_515_654 of a second -> 1/1_001_010 of a second 2697 assert(convClockFreq(912_319, 3_515_654, 1_001_010) == 259_764); 2698 2699 // one tick is 1/MonoTime.ticksPerSecond -> one tick is a nanosecond 2700 // Equivalent to ticksToNSecs 2701 auto nsecs = convClockFreq(1982, MonoTime.ticksPerSecond, 1_000_000_000); 2702 } 2703 2704 unittest 2705 { 2706 assert(convClockFreq(99, 43, 57) == 131); 2707 assert(convClockFreq(131, 57, 43) == 98); 2708 assert(convClockFreq(1234567890, 10_000_000, 1_000_000_000) == 123456789000); 2709 assert(convClockFreq(1234567890, 1_000_000_000, 10_000_000) == 12345678); 2710 assert(convClockFreq(123456789000, 1_000_000_000, 10_000_000) == 1234567890); 2711 assert(convClockFreq(12345678, 10_000_000, 1_000_000_000) == 1234567800); 2712 assert(convClockFreq(13131, 3_515_654, 10_000_000) == 37350); 2713 assert(convClockFreq(37350, 10_000_000, 3_515_654) == 13130); 2714 assert(convClockFreq(37350, 3_515_654, 10_000_000) == 106239); 2715 assert(convClockFreq(106239, 10_000_000, 3_515_654) == 37349); 2716 2717 // It would be too expensive to cover a large range of possible values for 2718 // ticks, so we use random values in an attempt to get reasonable coverage. 2719 import core.stdc.stdlib; 2720 immutable seed = cast(int)time(null); 2721 srand(seed); 2722 scope(failure) printf("seed %d\n", seed); 2723 enum freq1 = 5_527_551L; 2724 enum freq2 = 10_000_000L; 2725 enum freq3 = 1_000_000_000L; 2726 enum freq4 = 98_123_320L; 2727 immutable freq5 = MonoTime.ticksPerSecond; 2728 2729 // This makes it so that freq6 is the first multiple of 10 which is greater 2730 // than or equal to freq5, which at one point was considered for MonoTime's 2731 // ticksPerSecond rather than using the system's actual clock frequency, so 2732 // it seemed like a good test case to have. 2733 import core.stdc.math; 2734 immutable numDigitsMinus1 = cast(int)floor(log10(freq5)); 2735 auto freq6 = cast(long)pow(10, numDigitsMinus1); 2736 if (freq5 > freq6) 2737 freq6 *= 10; 2738 2739 foreach (_; 0 .. 10_000) 2740 { 2741 long[2] values = [rand(), cast(long)rand() * (rand() % 16)]; 2742 foreach (i; values) 2743 { 2744 scope(failure) printf("i %s\n", numToStringz(i)); 2745 assertApprox(convClockFreq(convClockFreq(i, freq1, freq2), freq2, freq1), i - 10, i + 10); 2746 assertApprox(convClockFreq(convClockFreq(i, freq2, freq1), freq1, freq2), i - 10, i + 10); 2747 2748 assertApprox(convClockFreq(convClockFreq(i, freq3, freq4), freq4, freq3), i - 100, i + 100); 2749 assertApprox(convClockFreq(convClockFreq(i, freq4, freq3), freq3, freq4), i - 100, i + 100); 2750 2751 scope(failure) printf("sys %s mt %s\n", numToStringz(freq5), numToStringz(freq6)); 2752 assertApprox(convClockFreq(convClockFreq(i, freq5, freq6), freq6, freq5), i - 10, i + 10); 2753 assertApprox(convClockFreq(convClockFreq(i, freq6, freq5), freq5, freq6), i - 10, i + 10); 2754 2755 // This is here rather than in a unittest block immediately after 2756 // ticksToNSecs in order to avoid code duplication in the unit tests. 2757 assert(convClockFreq(i, MonoTime.ticksPerSecond, 1_000_000_000) == ticksToNSecs(i)); 2758 } 2759 } 2760 } 2761 2762 2763 /++ 2764 Convenience wrapper around $(LREF convClockFreq) which converts ticks at 2765 a clock frequency of $(D MonoTime.ticksPerSecond) to nanoseconds. 2766 2767 It's primarily of use when $(D MonoTime.ticksPerSecond) is greater than 2768 hecto-nanosecond resolution, and an application needs a higher precision 2769 than hecto-nanoceconds. 2770 2771 See_Also: 2772 $(LREF convClockFreq) 2773 +/ 2774 long ticksToNSecs(long ticks) @safe pure nothrow @nogc 2775 { 2776 return convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000); 2777 } 2778 2779 /// 2780 unittest 2781 { 2782 auto before = MonoTime.currTime; 2783 // do stuff 2784 auto after = MonoTime.currTime; 2785 auto diffInTicks = after.ticks - before.ticks; 2786 auto diffInNSecs = ticksToNSecs(diffInTicks); 2787 assert(diffInNSecs == convClockFreq(diffInTicks, MonoTime.ticksPerSecond, 1_000_000_000)); 2788 } 2789 2790 2791 /++ 2792 The reverse of $(LREF ticksToNSecs). 2793 +/ 2794 long nsecsToTicks(long ticks) @safe pure nothrow @nogc 2795 { 2796 return convClockFreq(ticks, 1_000_000_000, MonoTime.ticksPerSecond); 2797 } 2798 2799 unittest 2800 { 2801 long ticks = 123409832717333; 2802 auto nsecs = convClockFreq(ticks, MonoTime.ticksPerSecond, 1_000_000_000); 2803 ticks = convClockFreq(nsecs, 1_000_000_000, MonoTime.ticksPerSecond); 2804 assert(nsecsToTicks(nsecs) == ticks); 2805 } 2806 2807 2808 2809 /++ 2810 $(RED Warning: TickDuration is deprecated. Please use 2811 $(LREF MonoTime) for the cases where a monotonic timestamp is needed 2812 and $(LREF Duration) when a duration is needed, rather than using 2813 TickDuration.) 2814 2815 Represents a duration of time in system clock ticks. 2816 2817 The system clock ticks are the ticks of the system clock at the highest 2818 precision that the system provides. 2819 +/ 2820 deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead") 2821 struct TickDuration 2822 { 2823 deprecated: 2824 private static TickDuration TDRvalueOf(TickDuration td) 2825 { 2826 return td; 2827 } 2828 /++ 2829 The number of ticks that the system clock has in one second. 2830 2831 If $(D ticksPerSec) is $(D 0), then then $(D TickDuration) failed to 2832 get the value of $(D ticksPerSec) on the current system, and 2833 $(D TickDuration) is not going to work. That would be highly abnormal 2834 though. 2835 +/ 2836 static immutable long ticksPerSec; 2837 2838 2839 /++ 2840 The tick of the system clock (as a $(D TickDuration)) when the 2841 application started. 2842 +/ 2843 static immutable TickDuration appOrigin; 2844 2845 2846 static @property @safe pure nothrow @nogc 2847 { 2848 /++ 2849 It's the same as $(D TickDuration(0)), but it's provided to be 2850 consistent with $(D Duration), which provides a $(D zero) property. 2851 +/ 2852 TickDuration zero() { return TickDuration(0); } 2853 2854 /++ 2855 Largest $(D TickDuration) possible. 2856 +/ 2857 TickDuration max() { return TickDuration(long.max); } 2858 2859 /++ 2860 Most negative $(D TickDuration) possible. 2861 +/ 2862 TickDuration min() { return TickDuration(long.min); } 2863 } 2864 2865 version (CoreUnittest) unittest 2866 { 2867 assert((zero == TickDuration(0)) == true); 2868 assert((TickDuration.max == TickDuration(long.max)) == true); 2869 assert((TickDuration.min == TickDuration(long.min)) == true); 2870 assert((TickDuration.min < TickDuration.zero) == true); 2871 assert((TickDuration.zero < TickDuration.max) == true); 2872 assert((TickDuration.min < TickDuration.max) == true); 2873 assert((TickDuration.min - TickDuration(1) == TickDuration.max) == true); 2874 assert((TickDuration.max + TickDuration(1) == TickDuration.min) == true); 2875 } 2876 2877 2878 static pragma(crt_constructor) void time_initializer() 2879 { 2880 version (Windows) 2881 { 2882 if (QueryPerformanceFrequency(cast(long*)&ticksPerSec) == 0) 2883 ticksPerSec = 0; 2884 } 2885 else version (Darwin) 2886 { 2887 ticksPerSec = machTicksPerSecond(); 2888 } 2889 else version (Posix) 2890 { 2891 static if (is(typeof(clock_gettime))) 2892 { 2893 timespec ts; 2894 2895 if (clock_getres(CLOCK_MONOTONIC, &ts) != 0) 2896 ticksPerSec = 0; 2897 else 2898 { 2899 //For some reason, on some systems, clock_getres returns 2900 //a resolution which is clearly wrong (it's a millisecond 2901 //or worse, but the time is updated much more frequently 2902 //than that). In such cases, we'll just use nanosecond 2903 //resolution. 2904 ticksPerSec = ts.tv_nsec >= 1000 ? 1_000_000_000 2905 : 1_000_000_000 / ts.tv_nsec; 2906 } 2907 } 2908 else 2909 ticksPerSec = 1_000_000; 2910 } 2911 2912 if (ticksPerSec != 0) 2913 appOrigin = TickDuration.currSystemTick; 2914 } 2915 2916 version (CoreUnittest) unittest 2917 { 2918 assert(ticksPerSec); 2919 } 2920 2921 2922 /++ 2923 The number of system ticks in this $(D TickDuration). 2924 2925 You can convert this $(D length) into the number of seconds by dividing 2926 it by $(D ticksPerSec) (or using one the appropriate property function 2927 to do it). 2928 +/ 2929 long length; 2930 2931 /++ 2932 Returns the total number of seconds in this $(D TickDuration). 2933 +/ 2934 @property long seconds() @safe const pure nothrow @nogc 2935 { 2936 return this.to!("seconds", long)(); 2937 } 2938 2939 version (CoreUnittest) unittest 2940 { 2941 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 2942 { 2943 assert((cast(T)TickDuration(ticksPerSec)).seconds == 1); 2944 assert((cast(T)TickDuration(ticksPerSec - 1)).seconds == 0); 2945 assert((cast(T)TickDuration(ticksPerSec * 2)).seconds == 2); 2946 assert((cast(T)TickDuration(ticksPerSec * 2 - 1)).seconds == 1); 2947 assert((cast(T)TickDuration(-1)).seconds == 0); 2948 assert((cast(T)TickDuration(-ticksPerSec - 1)).seconds == -1); 2949 assert((cast(T)TickDuration(-ticksPerSec)).seconds == -1); 2950 } 2951 } 2952 2953 2954 /++ 2955 Returns the total number of milliseconds in this $(D TickDuration). 2956 +/ 2957 @property long msecs() @safe const pure nothrow @nogc 2958 { 2959 return this.to!("msecs", long)(); 2960 } 2961 2962 2963 /++ 2964 Returns the total number of microseconds in this $(D TickDuration). 2965 +/ 2966 @property long usecs() @safe const pure nothrow @nogc 2967 { 2968 return this.to!("usecs", long)(); 2969 } 2970 2971 2972 /++ 2973 Returns the total number of hecto-nanoseconds in this $(D TickDuration). 2974 +/ 2975 @property long hnsecs() @safe const pure nothrow @nogc 2976 { 2977 return this.to!("hnsecs", long)(); 2978 } 2979 2980 2981 /++ 2982 Returns the total number of nanoseconds in this $(D TickDuration). 2983 +/ 2984 @property long nsecs() @safe const pure nothrow @nogc 2985 { 2986 return this.to!("nsecs", long)(); 2987 } 2988 2989 2990 /++ 2991 This allows you to construct a $(D TickDuration) from the given time 2992 units with the given length. 2993 2994 Params: 2995 units = The time units of the $(D TickDuration) (e.g. $(D "msecs")). 2996 length = The number of units in the $(D TickDuration). 2997 +/ 2998 static TickDuration from(string units)(long length) @safe pure nothrow @nogc 2999 if (units == "seconds" || 3000 units == "msecs" || 3001 units == "usecs" || 3002 units == "hnsecs" || 3003 units == "nsecs") 3004 { 3005 enum unitsPerSec = convert!("seconds", units)(1); 3006 3007 return TickDuration(cast(long)(length * (ticksPerSec / cast(real)unitsPerSec))); 3008 } 3009 3010 version (CoreUnittest) unittest 3011 { 3012 foreach (units; AliasSeq!("seconds", "msecs", "usecs", "nsecs")) 3013 { 3014 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3015 { 3016 assertApprox((cast(T)TickDuration.from!units(1000)).to!(units, long)(), 3017 500, 1500, units); 3018 assertApprox((cast(T)TickDuration.from!units(1_000_000)).to!(units, long)(), 3019 900_000, 1_100_000, units); 3020 assertApprox((cast(T)TickDuration.from!units(2_000_000)).to!(units, long)(), 3021 1_900_000, 2_100_000, units); 3022 } 3023 } 3024 } 3025 3026 3027 /++ 3028 Returns a $(LREF Duration) with the same number of hnsecs as this 3029 $(D TickDuration). 3030 Note that the conventional way to convert between $(D TickDuration) 3031 and $(D Duration) is using $(REF to, std,conv), e.g.: 3032 $(D tickDuration.to!Duration()) 3033 +/ 3034 Duration opCast(T)() @safe const pure nothrow @nogc 3035 if (is(immutable T == immutable Duration)) 3036 { 3037 return Duration(hnsecs); 3038 } 3039 3040 version (CoreUnittest) unittest 3041 { 3042 foreach (D; AliasSeq!(Duration, const Duration, immutable Duration)) 3043 { 3044 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3045 { 3046 auto expected = dur!"seconds"(1); 3047 assert(cast(D)cast(T)TickDuration.from!"seconds"(1) == expected); 3048 3049 foreach (units; AliasSeq!("msecs", "usecs", "hnsecs")) 3050 { 3051 D actual = cast(D)cast(T)TickDuration.from!units(1_000_000); 3052 assertApprox(actual, dur!units(900_000), dur!units(1_100_000)); 3053 } 3054 } 3055 } 3056 } 3057 3058 3059 //Temporary hack until bug http://d.puremagic.com/issues/show_bug.cgi?id=5747 is fixed. 3060 TickDuration opCast(T)() @safe const pure nothrow @nogc 3061 if (is(immutable T == immutable TickDuration)) 3062 { 3063 return this; 3064 } 3065 3066 3067 /++ 3068 Adds or subtracts two $(D TickDuration)s as well as assigning the result 3069 to this $(D TickDuration). 3070 3071 The legal types of arithmetic for $(D TickDuration) using this operator 3072 are 3073 3074 $(TABLE 3075 $(TR $(TD TickDuration) $(TD +=) $(TD TickDuration) $(TD -->) $(TD TickDuration)) 3076 $(TR $(TD TickDuration) $(TD -=) $(TD TickDuration) $(TD -->) $(TD TickDuration)) 3077 ) 3078 3079 Params: 3080 rhs = The $(D TickDuration) to add to or subtract from this 3081 $(D $(D TickDuration)). 3082 +/ 3083 ref TickDuration opOpAssign(string op)(TickDuration rhs) @safe pure nothrow @nogc 3084 if (op == "+" || op == "-") 3085 { 3086 mixin("length " ~ op ~ "= rhs.length;"); 3087 return this; 3088 } 3089 3090 version (CoreUnittest) unittest 3091 { 3092 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3093 { 3094 auto a = TickDuration.currSystemTick; 3095 auto result = a += cast(T)TickDuration.currSystemTick; 3096 assert((a == result) == true); 3097 assert(a.to!("seconds", real)() >= 0); 3098 3099 auto b = TickDuration.currSystemTick; 3100 result = b -= cast(T)TickDuration.currSystemTick; 3101 assert((b == result) == true); 3102 assert(b.to!("seconds", real)() <= 0); 3103 3104 foreach (U; AliasSeq!(const TickDuration, immutable TickDuration)) 3105 { 3106 U u = TickDuration(12); 3107 static assert(!__traits(compiles, u += cast(T)TickDuration.currSystemTick)); 3108 static assert(!__traits(compiles, u -= cast(T)TickDuration.currSystemTick)); 3109 } 3110 } 3111 } 3112 3113 3114 /++ 3115 Adds or subtracts two $(D TickDuration)s. 3116 3117 The legal types of arithmetic for $(D TickDuration) using this operator 3118 are 3119 3120 $(TABLE 3121 $(TR $(TD TickDuration) $(TD +) $(TD TickDuration) $(TD -->) $(TD TickDuration)) 3122 $(TR $(TD TickDuration) $(TD -) $(TD TickDuration) $(TD -->) $(TD TickDuration)) 3123 ) 3124 3125 Params: 3126 rhs = The $(D TickDuration) to add to or subtract from this 3127 $(D TickDuration). 3128 +/ 3129 TickDuration opBinary(string op)(TickDuration rhs) @safe const pure nothrow @nogc 3130 if (op == "+" || op == "-") 3131 { 3132 return TickDuration(mixin("length " ~ op ~ " rhs.length")); 3133 } 3134 3135 version (CoreUnittest) unittest 3136 { 3137 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3138 { 3139 T a = TickDuration.currSystemTick; 3140 T b = TickDuration.currSystemTick; 3141 assert((a + b).usecs > 0); 3142 assert((a - b).seconds <= 0); 3143 } 3144 } 3145 3146 3147 /++ 3148 Returns the negation of this $(D TickDuration). 3149 +/ 3150 TickDuration opUnary(string op)() @safe const pure nothrow @nogc 3151 if (op == "-") 3152 { 3153 return TickDuration(-length); 3154 } 3155 3156 version (CoreUnittest) unittest 3157 { 3158 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3159 { 3160 assert((-(cast(T)TickDuration(7)) == TickDuration(-7)) == true); 3161 assert((-(cast(T)TickDuration(5)) == TickDuration(-5)) == true); 3162 assert((-(cast(T)TickDuration(-7)) == TickDuration(7)) == true); 3163 assert((-(cast(T)TickDuration(-5)) == TickDuration(5)) == true); 3164 assert((-(cast(T)TickDuration(0)) == TickDuration(0)) == true); 3165 } 3166 } 3167 3168 3169 /++ 3170 operator overloading "<, >, <=, >=" 3171 +/ 3172 int opCmp(TickDuration rhs) @safe const pure nothrow @nogc 3173 { 3174 return (length > rhs.length) - (length < rhs.length); 3175 } 3176 3177 version (CoreUnittest) unittest 3178 { 3179 import core.internal.traits : rvalueOf; 3180 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3181 { 3182 foreach (U; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3183 { 3184 T t = TickDuration.currSystemTick; 3185 U u = t; 3186 assert((t == u) == true); 3187 assert((TDRvalueOf(t) == u) == true); 3188 assert((t == TDRvalueOf(u)) == true); 3189 } 3190 } 3191 3192 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3193 { 3194 foreach (U; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3195 { 3196 T t = TickDuration.currSystemTick; 3197 U u = t + t; 3198 assert((t < u) == true); 3199 assert((t <= t) == true); 3200 assert((u > t) == true); 3201 assert((u >= u) == true); 3202 3203 assert((TDRvalueOf(t) < u) == true); 3204 assert((TDRvalueOf(t) <= t) == true); 3205 assert((TDRvalueOf(u) > t) == true); 3206 assert((TDRvalueOf(u) >= u) == true); 3207 3208 assert((t < TDRvalueOf(u)) == true); 3209 assert((t <= TDRvalueOf(t)) == true); 3210 assert((u > TDRvalueOf(t)) == true); 3211 assert((u >= TDRvalueOf(u)) == true); 3212 } 3213 } 3214 } 3215 3216 3217 /++ 3218 The legal types of arithmetic for $(D TickDuration) using this operator 3219 overload are 3220 3221 $(TABLE 3222 $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) 3223 $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) 3224 ) 3225 3226 Params: 3227 value = The value to divide from this duration. 3228 +/ 3229 void opOpAssign(string op, T)(T value) @safe pure nothrow @nogc 3230 if (op == "*" && 3231 (__traits(isIntegral, T) || __traits(isFloating, T))) 3232 { 3233 length = cast(long)(length * value); 3234 } 3235 3236 version (CoreUnittest) unittest 3237 { 3238 immutable curr = TickDuration.currSystemTick; 3239 TickDuration t1 = curr; 3240 immutable t2 = curr + curr; 3241 t1 *= 2; 3242 assert((t1 == t2) == true); 3243 3244 t1 = curr; 3245 t1 *= 2.0; 3246 immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0)); 3247 assertApprox(t1, t2 - tol, t2 + tol); 3248 3249 t1 = curr; 3250 t1 *= 2.1; 3251 assert((t1 > t2) == true); 3252 3253 foreach (T; AliasSeq!(const TickDuration, immutable TickDuration)) 3254 { 3255 T t = TickDuration.currSystemTick; 3256 assert(!__traits(compiles, t *= 12)); 3257 assert(!__traits(compiles, t *= 12.0)); 3258 } 3259 } 3260 3261 3262 /++ 3263 The legal types of arithmetic for $(D TickDuration) using this operator 3264 overload are 3265 3266 $(TABLE 3267 $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) 3268 $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) 3269 ) 3270 3271 Params: 3272 value = The value to divide from this $(D TickDuration). 3273 3274 Throws: 3275 $(D TimeException) if an attempt to divide by $(D 0) is made. 3276 +/ 3277 void opOpAssign(string op, T)(T value) @safe pure 3278 if (op == "/" && 3279 (__traits(isIntegral, T) || __traits(isFloating, T))) 3280 { 3281 if (value == 0) 3282 throw new TimeException("Attempted division by 0."); 3283 3284 length = cast(long)(length / value); 3285 } 3286 3287 version (CoreUnittest) unittest 3288 { 3289 immutable curr = TickDuration.currSystemTick; 3290 immutable t1 = curr; 3291 TickDuration t2 = curr + curr; 3292 t2 /= 2; 3293 assert((t1 == t2) == true); 3294 3295 t2 = curr + curr; 3296 t2 /= 2.0; 3297 immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0)); 3298 assertApprox(t1, t2 - tol, t2 + tol); 3299 3300 t2 = curr + curr; 3301 t2 /= 2.1; 3302 assert((t1 > t2) == true); 3303 3304 _assertThrown!TimeException(t2 /= 0); 3305 3306 foreach (T; AliasSeq!(const TickDuration, immutable TickDuration)) 3307 { 3308 T t = TickDuration.currSystemTick; 3309 assert(!__traits(compiles, t /= 12)); 3310 assert(!__traits(compiles, t /= 12.0)); 3311 } 3312 } 3313 3314 3315 /++ 3316 The legal types of arithmetic for $(D TickDuration) using this operator 3317 overload are 3318 3319 $(TABLE 3320 $(TR $(TD TickDuration) $(TD *) $(TD long) $(TD -->) $(TD TickDuration)) 3321 $(TR $(TD TickDuration) $(TD *) $(TD floating point) $(TD -->) $(TD TickDuration)) 3322 ) 3323 3324 Params: 3325 value = The value to divide from this $(D TickDuration). 3326 +/ 3327 TickDuration opBinary(string op, T)(T value) @safe const pure nothrow @nogc 3328 if (op == "*" && 3329 (__traits(isIntegral, T) || __traits(isFloating, T))) 3330 { 3331 return TickDuration(cast(long)(length * value)); 3332 } 3333 3334 version (CoreUnittest) unittest 3335 { 3336 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3337 { 3338 T t1 = TickDuration.currSystemTick; 3339 T t2 = t1 + t1; 3340 assert((t1 * 2 == t2) == true); 3341 immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0)); 3342 assertApprox(t1 * 2.0, t2 - tol, t2 + tol); 3343 assert((t1 * 2.1 > t2) == true); 3344 } 3345 } 3346 3347 3348 /++ 3349 The legal types of arithmetic for $(D TickDuration) using this operator 3350 overload are 3351 3352 $(TABLE 3353 $(TR $(TD TickDuration) $(TD /) $(TD long) $(TD -->) $(TD TickDuration)) 3354 $(TR $(TD TickDuration) $(TD /) $(TD floating point) $(TD -->) $(TD TickDuration)) 3355 ) 3356 3357 Params: 3358 value = The value to divide from this $(D TickDuration). 3359 3360 Throws: 3361 $(D TimeException) if an attempt to divide by $(D 0) is made. 3362 +/ 3363 TickDuration opBinary(string op, T)(T value) @safe const pure 3364 if (op == "/" && 3365 (__traits(isIntegral, T) || __traits(isFloating, T))) 3366 { 3367 if (value == 0) 3368 throw new TimeException("Attempted division by 0."); 3369 3370 return TickDuration(cast(long)(length / value)); 3371 } 3372 3373 version (CoreUnittest) unittest 3374 { 3375 foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration)) 3376 { 3377 T t1 = TickDuration.currSystemTick; 3378 T t2 = t1 + t1; 3379 assert((t2 / 2 == t1) == true); 3380 immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0)); 3381 assertApprox(t2 / 2.0, t1 - tol, t1 + tol); 3382 assert((t2 / 2.1 < t1) == true); 3383 3384 _assertThrownDep!TimeException(t2 / 0); 3385 } 3386 } 3387 3388 3389 /++ 3390 Params: 3391 ticks = The number of ticks in the TickDuration. 3392 +/ 3393 @safe pure nothrow @nogc this(long ticks) 3394 { 3395 this.length = ticks; 3396 } 3397 3398 version (CoreUnittest) unittest 3399 { 3400 foreach (i; [-42, 0, 42]) 3401 assert(TickDuration(i).length == i); 3402 } 3403 3404 3405 /++ 3406 The current system tick. The number of ticks per second varies from 3407 system to system. $(D currSystemTick) uses a monotonic clock, so it's 3408 intended for precision timing by comparing relative time values, not for 3409 getting the current system time. 3410 3411 On Windows, $(D QueryPerformanceCounter) is used. On Mac OS X, 3412 $(D mach_absolute_time) is used, while on other Posix systems, 3413 $(D clock_gettime) is used. If $(D mach_absolute_time) or 3414 $(D clock_gettime) is unavailable, then Posix systems use 3415 $(D gettimeofday) (the decision is made when $(D TickDuration) is 3416 compiled), which unfortunately, is not monotonic, but if 3417 $(D mach_absolute_time) and $(D clock_gettime) aren't available, then 3418 $(D gettimeofday) is the best that there is. 3419 3420 $(RED Warning): 3421 On some systems, the monotonic clock may stop counting when 3422 the computer goes to sleep or hibernates. So, the monotonic 3423 clock could be off if that occurs. This is known to happen 3424 on Mac OS X. It has not been tested whether it occurs on 3425 either Windows or on Linux. 3426 3427 Throws: 3428 $(D TimeException) if it fails to get the time. 3429 +/ 3430 static @property TickDuration currSystemTick() @trusted nothrow @nogc 3431 { 3432 import core.internal.abort : abort; 3433 version (WASI) { 3434 time_result_t timestamp_res = clock_time_get(CLOCK_REALTIME, -1); 3435 if (timestamp_res.errno) 3436 { 3437 import core.internal.abort : abort; 3438 abort("Call to clock_time_get failed."); 3439 } 3440 return TickDuration(timestamp_res.timestamp); 3441 } 3442 else version (Windows) 3443 { 3444 ulong ticks = void; 3445 QueryPerformanceCounter(cast(long*)&ticks); 3446 return TickDuration(ticks); 3447 } 3448 else version (Darwin) 3449 { 3450 static if (is(typeof(mach_absolute_time))) 3451 return TickDuration(cast(long)mach_absolute_time()); 3452 else 3453 { 3454 timeval tv = void; 3455 gettimeofday(&tv, null); 3456 return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + 3457 tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); 3458 } 3459 } 3460 else version (Posix) 3461 { 3462 static if (is(typeof(clock_gettime))) 3463 { 3464 timespec ts = void; 3465 immutable error = clock_gettime(CLOCK_MONOTONIC, &ts); 3466 // CLOCK_MONOTONIC is supported and if tv_sec is long or larger 3467 // overflow won't happen before 292 billion years A.D. 3468 static if (ts.tv_sec.max < long.max) 3469 { 3470 if (error) 3471 { 3472 import core.internal.abort : abort; 3473 abort("Call to clock_gettime failed."); 3474 } 3475 } 3476 return TickDuration(ts.tv_sec * TickDuration.ticksPerSec + 3477 ts.tv_nsec * TickDuration.ticksPerSec / 1000 / 1000 / 1000); 3478 } 3479 else 3480 { 3481 timeval tv = void; 3482 gettimeofday(&tv, null); 3483 return TickDuration(tv.tv_sec * TickDuration.ticksPerSec + 3484 tv.tv_usec * TickDuration.ticksPerSec / 1000 / 1000); 3485 } 3486 } 3487 } 3488 3489 version (CoreUnittest) @safe nothrow unittest 3490 { 3491 assert(TickDuration.currSystemTick.length > 0); 3492 } 3493 } 3494 3495 /++ 3496 Generic way of converting between two time units. Conversions to smaller 3497 units use truncating division. Years and months can be converted to each 3498 other, small units can be converted to each other, but years and months 3499 cannot be converted to or from smaller units (due to the varying number 3500 of days in a month or year). 3501 3502 Params: 3503 from = The units of time to convert from. 3504 to = The units of time to convert to. 3505 value = The value to convert. 3506 +/ 3507 long convert(string from, string to)(long value) @safe pure nothrow @nogc 3508 if (((from == "weeks" || 3509 from == "days" || 3510 from == "hours" || 3511 from == "minutes" || 3512 from == "seconds" || 3513 from == "msecs" || 3514 from == "usecs" || 3515 from == "hnsecs" || 3516 from == "nsecs") && 3517 (to == "weeks" || 3518 to == "days" || 3519 to == "hours" || 3520 to == "minutes" || 3521 to == "seconds" || 3522 to == "msecs" || 3523 to == "usecs" || 3524 to == "hnsecs" || 3525 to == "nsecs")) || 3526 ((from == "years" || from == "months") && (to == "years" || to == "months"))) 3527 { 3528 static if (from == "years") 3529 { 3530 static if (to == "years") 3531 return value; 3532 else static if (to == "months") 3533 return value * 12; 3534 else 3535 static assert(0, "A generic month or year cannot be converted to or from smaller units."); 3536 } 3537 else static if (from == "months") 3538 { 3539 static if (to == "years") 3540 return value / 12; 3541 else static if (to == "months") 3542 return value; 3543 else 3544 static assert(0, "A generic month or year cannot be converted to or from smaller units."); 3545 } 3546 else static if (from == "nsecs" && to == "nsecs") 3547 return value; 3548 else static if (from == "nsecs") 3549 return convert!("hnsecs", to)(value / 100); 3550 else static if (to == "nsecs") 3551 return convert!(from, "hnsecs")(value) * 100; 3552 else 3553 return (hnsecsPer!from * value) / hnsecsPer!to; 3554 } 3555 3556 /// 3557 unittest 3558 { 3559 assert(convert!("years", "months")(1) == 12); 3560 assert(convert!("months", "years")(12) == 1); 3561 3562 assert(convert!("weeks", "days")(1) == 7); 3563 assert(convert!("hours", "seconds")(1) == 3600); 3564 assert(convert!("seconds", "days")(1) == 0); 3565 assert(convert!("seconds", "days")(86_400) == 1); 3566 3567 assert(convert!("nsecs", "nsecs")(1) == 1); 3568 assert(convert!("nsecs", "hnsecs")(1) == 0); 3569 assert(convert!("hnsecs", "nsecs")(1) == 100); 3570 assert(convert!("nsecs", "seconds")(1) == 0); 3571 assert(convert!("seconds", "nsecs")(1) == 1_000_000_000); 3572 } 3573 3574 unittest 3575 { 3576 foreach (units; AliasSeq!("weeks", "days", "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs")) 3577 { 3578 static assert(!__traits(compiles, convert!("years", units)(12)), units); 3579 static assert(!__traits(compiles, convert!(units, "years")(12)), units); 3580 } 3581 3582 foreach (units; AliasSeq!("years", "months", "weeks", "days", 3583 "hours", "seconds", "msecs", "usecs", "hnsecs", "nsecs")) 3584 { 3585 assert(convert!(units, units)(12) == 12); 3586 } 3587 3588 assert(convert!("weeks", "hnsecs")(1) == 6_048_000_000_000L); 3589 assert(convert!("days", "hnsecs")(1) == 864_000_000_000L); 3590 assert(convert!("hours", "hnsecs")(1) == 36_000_000_000L); 3591 assert(convert!("minutes", "hnsecs")(1) == 600_000_000L); 3592 assert(convert!("seconds", "hnsecs")(1) == 10_000_000L); 3593 assert(convert!("msecs", "hnsecs")(1) == 10_000); 3594 assert(convert!("usecs", "hnsecs")(1) == 10); 3595 3596 assert(convert!("hnsecs", "weeks")(6_048_000_000_000L) == 1); 3597 assert(convert!("hnsecs", "days")(864_000_000_000L) == 1); 3598 assert(convert!("hnsecs", "hours")(36_000_000_000L) == 1); 3599 assert(convert!("hnsecs", "minutes")(600_000_000L) == 1); 3600 assert(convert!("hnsecs", "seconds")(10_000_000L) == 1); 3601 assert(convert!("hnsecs", "msecs")(10_000) == 1); 3602 assert(convert!("hnsecs", "usecs")(10) == 1); 3603 3604 assert(convert!("weeks", "days")(1) == 7); 3605 assert(convert!("days", "weeks")(7) == 1); 3606 3607 assert(convert!("days", "hours")(1) == 24); 3608 assert(convert!("hours", "days")(24) == 1); 3609 3610 assert(convert!("hours", "minutes")(1) == 60); 3611 assert(convert!("minutes", "hours")(60) == 1); 3612 3613 assert(convert!("minutes", "seconds")(1) == 60); 3614 assert(convert!("seconds", "minutes")(60) == 1); 3615 3616 assert(convert!("seconds", "msecs")(1) == 1000); 3617 assert(convert!("msecs", "seconds")(1000) == 1); 3618 3619 assert(convert!("msecs", "usecs")(1) == 1000); 3620 assert(convert!("usecs", "msecs")(1000) == 1); 3621 3622 assert(convert!("usecs", "hnsecs")(1) == 10); 3623 assert(convert!("hnsecs", "usecs")(10) == 1); 3624 3625 assert(convert!("weeks", "nsecs")(1) == 604_800_000_000_000L); 3626 assert(convert!("days", "nsecs")(1) == 86_400_000_000_000L); 3627 assert(convert!("hours", "nsecs")(1) == 3_600_000_000_000L); 3628 assert(convert!("minutes", "nsecs")(1) == 60_000_000_000L); 3629 assert(convert!("seconds", "nsecs")(1) == 1_000_000_000L); 3630 assert(convert!("msecs", "nsecs")(1) == 1_000_000); 3631 assert(convert!("usecs", "nsecs")(1) == 1000); 3632 assert(convert!("hnsecs", "nsecs")(1) == 100); 3633 3634 assert(convert!("nsecs", "weeks")(604_800_000_000_000L) == 1); 3635 assert(convert!("nsecs", "days")(86_400_000_000_000L) == 1); 3636 assert(convert!("nsecs", "hours")(3_600_000_000_000L) == 1); 3637 assert(convert!("nsecs", "minutes")(60_000_000_000L) == 1); 3638 assert(convert!("nsecs", "seconds")(1_000_000_000L) == 1); 3639 assert(convert!("nsecs", "msecs")(1_000_000) == 1); 3640 assert(convert!("nsecs", "usecs")(1000) == 1); 3641 assert(convert!("nsecs", "hnsecs")(100) == 1); 3642 } 3643 3644 /++ 3645 Exception type used by core.time. 3646 +/ 3647 class TimeException : Exception 3648 { 3649 /++ 3650 Params: 3651 msg = The message for the exception. 3652 file = The file where the exception occurred. 3653 line = The line number where the exception occurred. 3654 next = The previous exception in the chain of exceptions, if any. 3655 +/ 3656 this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @safe pure nothrow 3657 { 3658 super(msg, file, line, next); 3659 } 3660 3661 /++ 3662 Params: 3663 msg = The message for the exception. 3664 next = The previous exception in the chain of exceptions. 3665 file = The file where the exception occurred. 3666 line = The line number where the exception occurred. 3667 +/ 3668 this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow 3669 { 3670 super(msg, file, line, next); 3671 } 3672 } 3673 3674 unittest 3675 { 3676 { 3677 auto e = new TimeException("hello"); 3678 assert(e.msg == "hello"); 3679 assert(e.file == __FILE__); 3680 assert(e.line == __LINE__ - 3); 3681 assert(e.next is null); 3682 } 3683 3684 { 3685 auto next = new Exception("foo"); 3686 auto e = new TimeException("goodbye", next); 3687 assert(e.msg == "goodbye"); 3688 assert(e.file == __FILE__); 3689 assert(e.line == __LINE__ - 3); 3690 assert(e.next is next); 3691 } 3692 } 3693 3694 3695 3696 /++ 3697 Returns the absolute value of a duration. 3698 +/ 3699 Duration abs(Duration duration) @safe pure nothrow @nogc 3700 { 3701 return Duration(_abs(duration._hnsecs)); 3702 } 3703 3704 /++ Ditto +/ 3705 deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead") 3706 TickDuration abs(TickDuration duration) @safe pure nothrow @nogc 3707 { 3708 return TickDuration(_abs(duration.length)); 3709 } 3710 3711 unittest 3712 { 3713 assert(abs(dur!"msecs"(5)) == dur!"msecs"(5)); 3714 assert(abs(dur!"msecs"(-5)) == dur!"msecs"(5)); 3715 } 3716 3717 deprecated unittest 3718 { 3719 assert((abs(TickDuration(17)) == TickDuration(17)) == true); 3720 assert((abs(TickDuration(-17)) == TickDuration(17)) == true); 3721 } 3722 3723 3724 //============================================================================== 3725 // Private Section. 3726 // 3727 // Much of this is a copy or simplified copy of what's in std.datetime. 3728 //============================================================================== 3729 private: 3730 3731 3732 /+ 3733 Template to help with converting between time units. 3734 +/ 3735 template hnsecsPer(string units) 3736 if (units == "weeks" || 3737 units == "days" || 3738 units == "hours" || 3739 units == "minutes" || 3740 units == "seconds" || 3741 units == "msecs" || 3742 units == "usecs" || 3743 units == "hnsecs") 3744 { 3745 static if (units == "hnsecs") 3746 enum hnsecsPer = 1L; 3747 else static if (units == "usecs") 3748 enum hnsecsPer = 10L; 3749 else static if (units == "msecs") 3750 enum hnsecsPer = 1000 * hnsecsPer!"usecs"; 3751 else static if (units == "seconds") 3752 enum hnsecsPer = 1000 * hnsecsPer!"msecs"; 3753 else static if (units == "minutes") 3754 enum hnsecsPer = 60 * hnsecsPer!"seconds"; 3755 else static if (units == "hours") 3756 enum hnsecsPer = 60 * hnsecsPer!"minutes"; 3757 else static if (units == "days") 3758 enum hnsecsPer = 24 * hnsecsPer!"hours"; 3759 else static if (units == "weeks") 3760 enum hnsecsPer = 7 * hnsecsPer!"days"; 3761 } 3762 3763 /+ 3764 Splits out a particular unit from hnsecs and gives you the value for that 3765 unit and the remaining hnsecs. It really shouldn't be used unless all units 3766 larger than the given units have already been split out. 3767 3768 Params: 3769 units = The units to split out. 3770 hnsecs = The current total hnsecs. Upon returning, it is the hnsecs left 3771 after splitting out the given units. 3772 3773 Returns: 3774 The number of the given units from converting hnsecs to those units. 3775 +/ 3776 long splitUnitsFromHNSecs(string units)(ref long hnsecs) @safe pure nothrow @nogc 3777 if (units == "weeks" || 3778 units == "days" || 3779 units == "hours" || 3780 units == "minutes" || 3781 units == "seconds" || 3782 units == "msecs" || 3783 units == "usecs" || 3784 units == "hnsecs") 3785 { 3786 immutable value = convert!("hnsecs", units)(hnsecs); 3787 hnsecs -= convert!(units, "hnsecs")(value); 3788 3789 return value; 3790 } 3791 3792 unittest 3793 { 3794 auto hnsecs = 2595000000007L; 3795 immutable days = splitUnitsFromHNSecs!"days"(hnsecs); 3796 assert(days == 3); 3797 assert(hnsecs == 3000000007); 3798 3799 immutable minutes = splitUnitsFromHNSecs!"minutes"(hnsecs); 3800 assert(minutes == 5); 3801 assert(hnsecs == 7); 3802 } 3803 3804 /+ 3805 Whether all of the given strings are among the accepted strings. 3806 +/ 3807 bool allAreAcceptedUnits(acceptedUnits...)(scope string[] units) 3808 { 3809 foreach (unit; units) 3810 { 3811 bool found = false; 3812 foreach (acceptedUnit; acceptedUnits) 3813 { 3814 if (unit == acceptedUnit) 3815 { 3816 found = true; 3817 break; 3818 } 3819 } 3820 if (!found) 3821 return false; 3822 } 3823 return true; 3824 } 3825 3826 unittest 3827 { 3828 assert(allAreAcceptedUnits!("hours", "seconds")(["seconds", "hours"])); 3829 assert(!allAreAcceptedUnits!("hours", "seconds")(["minutes", "hours"])); 3830 assert(!allAreAcceptedUnits!("hours", "seconds")(["seconds", "minutes"])); 3831 assert(allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["minutes"])); 3832 assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["usecs"])); 3833 assert(!allAreAcceptedUnits!("days", "hours", "minutes", "seconds", "msecs")(["secs"])); 3834 } 3835 3836 3837 /+ 3838 Whether the given time unit strings are arranged in order from largest to 3839 smallest. 3840 +/ 3841 bool unitsAreInDescendingOrder(scope string[] units) 3842 { 3843 if (units.length <= 1) 3844 return true; 3845 3846 immutable string[] timeStrings = ["nsecs", "hnsecs", "usecs", "msecs", "seconds", 3847 "minutes", "hours", "days", "weeks", "months", "years"]; 3848 size_t currIndex = 42; 3849 foreach (i, timeStr; timeStrings) 3850 { 3851 if (units[0] == timeStr) 3852 { 3853 currIndex = i; 3854 break; 3855 } 3856 } 3857 assert(currIndex != 42); 3858 3859 foreach (unit; units[1 .. $]) 3860 { 3861 size_t nextIndex = 42; 3862 foreach (i, timeStr; timeStrings) 3863 { 3864 if (unit == timeStr) 3865 { 3866 nextIndex = i; 3867 break; 3868 } 3869 } 3870 assert(nextIndex != 42); 3871 3872 if (currIndex <= nextIndex) 3873 return false; 3874 currIndex = nextIndex; 3875 } 3876 return true; 3877 } 3878 3879 unittest 3880 { 3881 assert(unitsAreInDescendingOrder(["years", "months", "weeks", "days", "hours", "minutes", 3882 "seconds", "msecs", "usecs", "hnsecs", "nsecs"])); 3883 assert(unitsAreInDescendingOrder(["weeks", "hours", "msecs"])); 3884 assert(unitsAreInDescendingOrder(["days", "hours", "minutes"])); 3885 assert(unitsAreInDescendingOrder(["hnsecs"])); 3886 assert(!unitsAreInDescendingOrder(["days", "hours", "hours"])); 3887 assert(!unitsAreInDescendingOrder(["days", "hours", "days"])); 3888 } 3889 3890 version (Darwin) 3891 long machTicksPerSecond() @nogc nothrow 3892 { 3893 // Be optimistic that ticksPerSecond (1e9*denom/numer) is integral. So far 3894 // so good on Darwin based platforms OS X, iOS. 3895 import core.internal.abort : abort; 3896 mach_timebase_info_data_t info; 3897 if (mach_timebase_info(&info) != 0) 3898 abort("Failed in mach_timebase_info()."); 3899 3900 long scaledDenom = 1_000_000_000L * info.denom; 3901 if (scaledDenom % info.numer != 0) 3902 abort("Non integral ticksPerSecond from mach_timebase_info."); 3903 return scaledDenom / info.numer; 3904 } 3905 3906 /+ 3907 Local version of abs, since std.math.abs is in Phobos, not druntime. 3908 +/ 3909 long _abs(long val) @safe pure nothrow @nogc 3910 { 3911 return val >= 0 ? val : -val; 3912 } 3913 3914 double _abs(double val) @safe pure nothrow @nogc 3915 { 3916 return val >= 0.0 ? val : -val; 3917 } 3918 3919 3920 version (CoreUnittest) 3921 string doubleToString(double value) @safe pure nothrow 3922 { 3923 string result; 3924 if (value < 0 && cast(long)value == 0) 3925 result = "-0"; 3926 else 3927 result = signedToTempString(cast(long)value).idup; 3928 result ~= '.'; 3929 result ~= unsignedToTempString(cast(ulong)(_abs((value - cast(long)value) * 1_000_000) + .5)); 3930 3931 while (result[$-1] == '0') 3932 result = result[0 .. $-1]; 3933 return result; 3934 } 3935 3936 unittest 3937 { 3938 auto a = 1.337; 3939 auto aStr = doubleToString(a); 3940 assert(aStr == "1.337", aStr); 3941 3942 a = 0.337; 3943 aStr = doubleToString(a); 3944 assert(aStr == "0.337", aStr); 3945 3946 a = -0.337; 3947 aStr = doubleToString(a); 3948 assert(aStr == "-0.337", aStr); 3949 } 3950 3951 version (CoreUnittest) const(char)* numToStringz()(long value) @trusted pure nothrow 3952 { 3953 return (signedToTempString(value) ~ "\0").ptr; 3954 } 3955 3956 3957 import core.internal.traits : AliasSeq; 3958 3959 3960 /+ An adjusted copy of std.exception.assertThrown. +/ 3961 version (CoreUnittest) void _assertThrown(T : Throwable = Exception, E) 3962 (lazy E expression, 3963 string msg = null, 3964 string file = __FILE__, 3965 size_t line = __LINE__) 3966 { 3967 bool thrown = false; 3968 3969 try 3970 expression(); 3971 catch (T t) 3972 thrown = true; 3973 3974 if (!thrown) 3975 { 3976 immutable tail = msg.length == 0 ? "." : ": " ~ msg; 3977 3978 throw new AssertError("assertThrown() failed: No " ~ T.stringof ~ " was thrown" ~ tail, file, line); 3979 } 3980 } 3981 3982 unittest 3983 { 3984 3985 void throwEx(Throwable t) 3986 { 3987 throw t; 3988 } 3989 3990 void nothrowEx() 3991 {} 3992 3993 try 3994 _assertThrown!Exception(throwEx(new Exception("It's an Exception"))); 3995 catch (AssertError) 3996 assert(0); 3997 3998 try 3999 _assertThrown!Exception(throwEx(new Exception("It's an Exception")), "It's a message"); 4000 catch (AssertError) 4001 assert(0); 4002 4003 try 4004 _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); 4005 catch (AssertError) 4006 assert(0); 4007 4008 try 4009 _assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), "It's a message"); 4010 catch (AssertError) 4011 assert(0); 4012 4013 4014 { 4015 bool thrown = false; 4016 try 4017 _assertThrown!Exception(nothrowEx()); 4018 catch (AssertError) 4019 thrown = true; 4020 4021 assert(thrown); 4022 } 4023 4024 { 4025 bool thrown = false; 4026 try 4027 _assertThrown!Exception(nothrowEx(), "It's a message"); 4028 catch (AssertError) 4029 thrown = true; 4030 4031 assert(thrown); 4032 } 4033 4034 { 4035 bool thrown = false; 4036 try 4037 _assertThrown!AssertError(nothrowEx()); 4038 catch (AssertError) 4039 thrown = true; 4040 4041 assert(thrown); 4042 } 4043 4044 { 4045 bool thrown = false; 4046 try 4047 _assertThrown!AssertError(nothrowEx(), "It's a message"); 4048 catch (AssertError) 4049 thrown = true; 4050 4051 assert(thrown); 4052 } 4053 } 4054 4055 version (CoreUnittest) deprecated void _assertThrownDep(T : Throwable = Exception, E) 4056 (lazy E expression, 4057 string msg = null, 4058 string file = __FILE__, 4059 size_t line = __LINE__) 4060 { 4061 bool thrown = false; 4062 4063 try 4064 expression(); 4065 catch (T t) 4066 thrown = true; 4067 4068 if (!thrown) 4069 { 4070 immutable tail = msg.length == 0 ? "." : ": " ~ msg; 4071 4072 throw new AssertError("assertThrown() failed: No " ~ T.stringof ~ " was thrown" ~ tail, file, line); 4073 } 4074 } 4075 4076 4077 4078 version (CoreUnittest) void assertApprox(D, E)(D actual, 4079 E lower, 4080 E upper, 4081 string msg = "unittest failure", 4082 size_t line = __LINE__) 4083 if (is(D : const Duration) && is(E : const Duration)) 4084 { 4085 if (actual < lower) 4086 throw new AssertError(msg ~ ": lower: " ~ actual.toString(), __FILE__, line); 4087 if (actual > upper) 4088 throw new AssertError(msg ~ ": upper: " ~ actual.toString(), __FILE__, line); 4089 } 4090 4091 version (CoreUnittest) deprecated void assertApprox(D, E)(D actual, 4092 E lower, 4093 E upper, 4094 string msg = "unittest failure", 4095 size_t line = __LINE__) 4096 if (is(D : const TickDuration) && is(E : const TickDuration)) 4097 { 4098 if (actual.length < lower.length || actual.length > upper.length) 4099 { 4100 throw new AssertError(msg ~ (": [" ~ signedToTempString(lower.length) ~ "] [" ~ 4101 signedToTempString(actual.length) ~ "] [" ~ 4102 signedToTempString(upper.length) ~ "]").idup, 4103 __FILE__, line); 4104 } 4105 } 4106 4107 version (CoreUnittest) void assertApprox(MT)(MT actual, 4108 MT lower, 4109 MT upper, 4110 string msg = "unittest failure", 4111 size_t line = __LINE__) 4112 if (is(MT == MonoTimeImpl!type, ClockType type)) 4113 { 4114 assertApprox(actual._ticks, lower._ticks, upper._ticks, msg, line); 4115 } 4116 4117 version (CoreUnittest) void assertApprox()(long actual, 4118 long lower, 4119 long upper, 4120 string msg = "unittest failure", 4121 size_t line = __LINE__) 4122 { 4123 if (actual < lower) 4124 throw new AssertError(msg ~ ": lower: " ~ signedToTempString(actual).idup, __FILE__, line); 4125 if (actual > upper) 4126 throw new AssertError(msg ~ ": upper: " ~ signedToTempString(actual).idup, __FILE__, line); 4127 }