17 |
17 |
18 # |
18 # |
19 # Support classes for dealing with different times |
19 # Support classes for dealing with different times |
20 # |
20 # |
21 |
21 |
22 # Return difference (delay) of "dreamtime" to monotonic time |
22 # Time snapshotting to helps to create stable comparisons of different |
23 def dreamtime_difference(): |
23 # subclasses of Time. |
24 if _dreamtime_monitor: |
24 class Snapshot: |
25 return _dreamtime_monitor.diff() |
25 def __init__(self): |
26 else: |
26 self._monotonic=None |
27 return time.monotonic() |
27 self._realtime=None |
28 |
28 self._dreamtime=None |
29 # Return "dreamtime" |
29 |
30 def dreamtime(): |
30 def monotonic(self): |
31 return max(0, time.monotonic()-dreamtime_difference()) |
31 if self._monotonic is None: |
32 |
32 self._monotonic=time.monotonic() |
|
33 return self._monotonic |
|
34 |
|
35 def realtime(self): |
|
36 if self._realtime is None: |
|
37 self._realtime=time.time() |
|
38 return self._realtime |
|
39 |
|
40 def dreamtime(self): |
|
41 if self._dreamtime is None: |
|
42 if _dreamtime_monitor: |
|
43 self._dreamtime=_dreamtime_monitor.dreamtime(snapshot=self) |
|
44 else: |
|
45 self._dreamtime=self.monotonic() |
|
46 return self._dreamtime |
|
47 |
|
48 # The main Time class, for time advancing in various paces |
33 class Time: |
49 class Time: |
34 def __init__(self, when): |
50 def __init__(self, when): |
35 self._value=when |
51 self._value=when |
36 |
52 |
37 def realtime(self): |
53 def _monotonic(self, snapshot): |
38 raise NotImplementedError |
54 raise NotImplementedError |
39 |
55 |
40 def monotonic(self): |
56 def _realtime(self, snapshot): |
41 raise NotImplementedError |
57 raise NotImplementedError |
42 |
58 |
43 @staticmethod |
59 @staticmethod |
44 def _now(): |
60 def _now(snapshot): |
45 raise NotImplementedError |
61 raise NotImplementedError |
46 |
62 |
47 @classmethod |
63 @classmethod |
48 def now(cls): |
64 def now(cls): |
49 return cls(cls._now()) |
65 return cls(cls._now(Snapshot())) |
50 |
66 |
51 @classmethod |
67 @classmethod |
52 def from_realtime(cls, realtime): |
68 def from_realtime(cls, realtime, snapshot=Snapshot()): |
53 return cls(realtime-time.time()+cls._now()) |
69 return cls(realtime-snapshot.realtime()+cls._now(snapshot)) |
54 |
70 |
55 @classmethod |
71 @classmethod |
56 def from_monotonic(cls, monotonic): |
72 def from_monotonic(cls, monotonic, snapshot=Snapshot()): |
57 return cls(monotonic-time.monotonic()+cls._now()) |
73 return cls(monotonic-snapshot.monotonic()+cls._now(snapshot)) |
58 |
74 |
59 @classmethod |
75 @classmethod |
60 def after(cls, seconds): |
76 def after(cls, seconds, snapshot=Snapshot()): |
61 return cls(cls._now()+seconds) |
77 return cls(cls._now(snapshot)+seconds) |
62 |
78 |
63 @classmethod |
79 @classmethod |
64 def after_other(cls, other, seconds): |
80 def after_other(cls, other, seconds, snapshot=Snapshot()): |
65 if isinstance(other, cls): |
81 if isinstance(other, cls): |
66 return cls(other._value+seconds) |
82 return cls(other._value+seconds) |
67 else: |
83 else: |
68 return cls.from_monotonic(other.monotonic()+seconds) |
84 return cls.from_monotonic(other._monotonic(snapshot)+seconds, |
|
85 snapshot) |
69 |
86 |
70 def datetime(self): |
87 def datetime(self): |
71 return datetime.datetime.fromtimestamp(self.realtime()) |
88 return datetime.datetime.fromtimestamp(self.realtime()) |
72 |
89 |
73 def seconds_to(self): |
90 def seconds_to(self): |
74 return self._value-self._now() |
91 return self._value-self._now(Snapshot()) |
75 |
92 |
76 def isoformat(self): |
93 def isoformat(self): |
77 return self.datetime().isoformat() |
94 return self.datetime().isoformat() |
78 |
95 |
|
96 def realtime(self): |
|
97 return self._realtime(Snapshot()) |
|
98 |
|
99 def monotonic(self): |
|
100 return self._monotonic(Snapshot()) |
|
101 |
|
102 def __compare(self, other, fn): |
|
103 if isinstance(other, self.__class__): |
|
104 return fn(self._value, other._value) |
|
105 else: |
|
106 snapshot=Snapshot() |
|
107 return fn(self._monotonic(snapshot), other._monotonic(snapshot)) |
|
108 |
79 def __lt__(self, other): |
109 def __lt__(self, other): |
80 return self.monotonic() < other.monotonic() |
110 return self.__compare(other, lambda x, y: x < y) |
81 |
111 |
82 def __gt__(self, other): |
112 def __gt__(self, other): |
83 return self.monotonic() > other.monotonic() |
113 return self.__compare(other, lambda x, y: x > y) |
84 |
114 |
85 def __le__(self, other): |
115 def __le__(self, other): |
86 return self.monotonic() <= other.monotonic() |
116 return self.__compare(other, lambda x, y: x <= y) |
87 |
117 |
88 def __ge__(self, other): |
118 def __ge__(self, other): |
89 return self.monotonic() >= other.monotonic() |
119 return self.__compare(other, lambda x, y: x >= y) |
90 |
120 |
91 def __eq__(self, other): |
121 def __eq__(self, other): |
92 return self.monotonic() == other.realtime() |
122 return self.__compare(other, lambda x, y: x == y) |
93 |
123 |
94 class RealTime(Time): |
124 class RealTime(Time): |
95 def realtime(self): |
125 def _realtime(self, snapshot): |
96 return self._value |
126 return self._value |
97 |
127 |
98 def monotonic(self): |
128 def _monotonic(self, snapshot): |
99 return self._value+(time.monotonic()-time.time()) |
129 return self._value+(snapshot.monotonic()-snapshot.realtime()) |
100 |
130 |
101 @staticmethod |
131 @staticmethod |
102 def _now(): |
132 def _now(snapshot): |
103 return time.time() |
133 return snapshot.realtime() |
104 |
134 |
105 class MonotonicTime(Time): |
135 class MonotonicTime(Time): |
106 def realtime(self): |
136 def _realtime(self, snapshot): |
107 return self._value+(time.time()-time.monotonic()) |
137 return self._value+(snapshot.realtime()-snapshot.monotonic()) |
108 |
138 |
109 def monotonic(self): |
139 def _monotonic(self, snapshot): |
110 return self._value |
140 return self._value |
111 |
141 |
112 @staticmethod |
142 @staticmethod |
113 def _now(): |
143 def _now(snapshot): |
114 return time.monotonic() |
144 return snapshot.monotonic() |
115 |
145 |
116 class DreamTime(Time): |
146 class DreamTime(Time): |
117 def realtime(self): |
147 def _realtime(self, snapshot): |
118 return self._value+(time.time()-dreamtime()) |
148 return self._value+(snapshot.realtime()-snapshot.dreamtime()) |
119 |
149 |
120 # Important: monotonic is "static" within a wakeup period |
150 # Important: monotonic is "static" within a wakeup period |
121 # and does not need to call time.monotonic(), as it gets compared |
151 # and does not need to call time.monotonic(), as it gets compared |
122 # to a specific time.monotonic() realisation |
152 # to a specific time.monotonic() realisation |
123 def monotonic(self): |
153 def _monotonic(self, snapshot): |
124 return self._value+dreamtime_difference() |
154 return self._value+(snapshot.monotonic()-snapshot.dreamtime()) |
125 |
155 |
126 @staticmethod |
156 @staticmethod |
127 def _now(): |
157 def _now(snapshot): |
128 return dreamtime() |
158 return snapshot.dreamtime() |
129 |
159 |
130 |
160 |
131 if platform.system()=='Darwin': |
161 if platform.system()=='Darwin': |
132 |
162 |
133 import Foundation |
163 import Foundation |