comparison tango/tango/time/Time.d @ 132:1700239cab2e trunk

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