55 |
55 |
56 def sleeping(self): |
56 def sleeping(self): |
57 _, sleeping=self.dreamtime_sleeping() |
57 _, sleeping=self.dreamtime_sleeping() |
58 return sleeping |
58 return sleeping |
59 |
59 |
|
60 # Python's default arguments are purely idiotic (aka. pythonic): generated |
|
61 # only once. This makes sense in a purely functional language, which Python |
|
62 # lightyears away from, but severely limits their usefulness in an imperative |
|
63 # language. Decorators also seem clumsy for this, as one would have to tell |
|
64 # the number of positional arguments for things to work nice, being able to |
|
65 # pass the snapshot both positionally and as keyword. No luck. |
|
66 # So have to do things the old-fashioned hard way. |
|
67 def ensure_snapshot(snapshot): |
|
68 if not snapshot: |
|
69 return Snapshot() |
|
70 else: |
|
71 return snapshot |
|
72 |
60 # The main Time class, for time advancing in various paces |
73 # The main Time class, for time advancing in various paces |
61 class Time: |
74 class Time: |
62 def __init__(self, when): |
75 def __init__(self, when): |
63 self._value=when |
76 self._value=when |
64 |
77 |
65 def _monotonic(self, snapshot): |
|
66 raise NotImplementedError |
|
67 |
|
68 def _realtime(self, snapshot): |
|
69 raise NotImplementedError |
|
70 |
|
71 @staticmethod |
78 @staticmethod |
72 def _now(snapshot): |
79 def _now(snapshot): |
73 raise NotImplementedError |
80 raise NotImplementedError |
74 |
81 |
75 @classmethod |
82 def remaining(self, snapshot=None): |
76 def now(cls): |
83 snapshot=ensure_snapshot(snapshot) |
77 return cls(cls._now(Snapshot())) |
84 return self._value-self._now(snapshot) |
78 |
85 |
79 @classmethod |
86 # Mostly equal to remaining() but can be ∞ (math.inf) for DreamTime. |
80 def from_realtime(cls, realtime, snapshot=Snapshot()): |
87 def horizon(self, snapshot=None): |
|
88 snapshot=ensure_snapshot(snapshot) |
|
89 return self.remaining(snapshot) |
|
90 |
|
91 def realtime(self, snapshot=None): |
|
92 snapshot=ensure_snapshot(snapshot) |
|
93 return snapshot.realtime()+self.remaining(snapshot) |
|
94 |
|
95 def monotonic(self, snapshot=None): |
|
96 snapshot=ensure_snapshot(snapshot) |
|
97 return snapshot.monotonic()+self.remaining(snapshot) |
|
98 |
|
99 @classmethod |
|
100 def now(cls, snapshot=None): |
|
101 snapshot=ensure_snapshot(snapshot) |
|
102 return cls(cls._now(snapshot)) |
|
103 |
|
104 @classmethod |
|
105 def from_realtime(cls, realtime, snapshot=None): |
|
106 snapshot=ensure_snapshot(snapshot) |
81 return cls(realtime-snapshot.realtime()+cls._now(snapshot)) |
107 return cls(realtime-snapshot.realtime()+cls._now(snapshot)) |
82 |
108 |
83 @classmethod |
109 @classmethod |
84 def from_monotonic(cls, monotonic, snapshot=Snapshot()): |
110 def from_monotonic(cls, monotonic, snapshot=None): |
|
111 snapshot=ensure_snapshot(snapshot) |
85 return cls(monotonic-snapshot.monotonic()+cls._now(snapshot)) |
112 return cls(monotonic-snapshot.monotonic()+cls._now(snapshot)) |
86 |
113 |
87 @classmethod |
114 @classmethod |
88 def after(cls, seconds, snapshot=Snapshot()): |
115 def after(cls, seconds, snapshot=None): |
|
116 snapshot=ensure_snapshot(snapshot) |
89 return cls(cls._now(snapshot)+seconds) |
117 return cls(cls._now(snapshot)+seconds) |
90 |
118 |
91 @classmethod |
119 @classmethod |
92 def after_other(cls, other, seconds, snapshot=Snapshot()): |
120 def after_other(cls, other, seconds, snapshot=None): |
|
121 snapshot=ensure_snapshot(snapshot) |
93 if isinstance(other, cls): |
122 if isinstance(other, cls): |
94 return cls(other._value+seconds) |
123 return cls(other._value+seconds) |
95 else: |
124 else: |
96 return cls.from_monotonic(other._monotonic(snapshot)+seconds, |
125 return cls.from_monotonic(other.monotonic(snapshot)+seconds, |
97 snapshot) |
126 snapshot) |
98 |
127 |
99 def datetime(self, snapshot=Snapshot()): |
128 def datetime(self, snapshot=None): |
100 return datetime.datetime.fromtimestamp(self._realtime(snapshot)) |
129 snapshot=ensure_snapshot(snapshot) |
101 |
130 return datetime.datetime.fromtimestamp(self.realtime(snapshot)) |
102 def seconds_to(self, snapshot=Snapshot()): |
131 |
103 return self._value-self._now(snapshot) |
132 def isoformat(self, snapshot=None): |
104 |
133 snapshot=ensure_snapshot(snapshot) |
105 def isoformat(self): |
134 return self.datetime(snapshot).isoformat() |
106 return self.datetime().isoformat() |
|
107 |
|
108 def realtime(self, snapshot=Snapshot()): |
|
109 return self._realtime(snapshot) |
|
110 |
|
111 def monotonic(self, snapshot=Snapshot()): |
|
112 return self._monotonic(snapshot) |
|
113 |
|
114 # Counted from the monotonic epoch, how far is this event? Usually should |
|
115 # equal self.monotonic(), but Dreamtime can be stopped by system sleep, |
|
116 # and will return ∞ (math.inf). |
|
117 def horizon(self, snapshot=Snapshot()): |
|
118 return self._monotonic(snapshot) |
|
119 |
135 |
120 def __compare(self, other, fn): |
136 def __compare(self, other, fn): |
121 if isinstance(other, self.__class__): |
137 if isinstance(other, self.__class__): |
122 return fn(self._value, other._value) |
138 return fn(self._value, other._value) |
123 else: |
139 else: |
124 snapshot=Snapshot() |
140 snapshot=Snapshot() |
125 return fn(self._monotonic(snapshot), other._monotonic(snapshot)) |
141 return fn(self.monotonic(snapshot), other.monotonic(snapshot)) |
126 |
142 |
127 def __lt__(self, other): |
143 def __lt__(self, other): |
128 return self.__compare(other, lambda x, y: x < y) |
144 return self.__compare(other, lambda x, y: x < y) |
129 |
145 |
130 def __gt__(self, other): |
146 def __gt__(self, other): |
137 return self.__compare(other, lambda x, y: x >= y) |
153 return self.__compare(other, lambda x, y: x >= y) |
138 |
154 |
139 def __eq__(self, other): |
155 def __eq__(self, other): |
140 return self.__compare(other, lambda x, y: x == y) |
156 return self.__compare(other, lambda x, y: x == y) |
141 |
157 |
|
158 |
142 class RealTime(Time): |
159 class RealTime(Time): |
143 def _realtime(self, snapshot): |
|
144 return self._value |
|
145 |
|
146 def _monotonic(self, snapshot): |
|
147 return self._value+(snapshot.monotonic()-snapshot.realtime()) |
|
148 |
|
149 @staticmethod |
160 @staticmethod |
150 def _now(snapshot): |
161 def _now(snapshot): |
151 return snapshot.realtime() |
162 return snapshot.realtime() |
152 |
163 |
|
164 def realtime(self, snapshot=None): |
|
165 return self._value |
|
166 |
|
167 |
153 class MonotonicTime(Time): |
168 class MonotonicTime(Time): |
154 def _realtime(self, snapshot): |
|
155 return self._value+(snapshot.realtime()-snapshot.monotonic()) |
|
156 |
|
157 def _monotonic(self, snapshot): |
|
158 return self._value |
|
159 |
|
160 @staticmethod |
169 @staticmethod |
161 def _now(snapshot): |
170 def _now(snapshot): |
162 return snapshot.monotonic() |
171 return snapshot.monotonic() |
163 |
172 |
164 # class Infinity(Time): |
173 def monotonic(self, snapshot=None): |
165 # def __init__(self): |
174 return self._value |
166 # super().__init__(math.inf) |
175 |
167 # |
|
168 # def _realtime(self, snapshot): |
|
169 # return math.inf |
|
170 # |
|
171 # def _monotonic(self, snapshot): |
|
172 # return math.inf |
|
173 # |
|
174 # @staticmethod |
|
175 # def _now(snapshot): |
|
176 # return 0 |
|
177 |
176 |
178 class DreamTime(Time): |
177 class DreamTime(Time): |
179 def _realtime(self, snapshot): |
178 @staticmethod |
180 return self._value+(snapshot.realtime()-snapshot.dreamtime()) |
179 def _now(snapshot): |
181 |
180 return snapshot.dreamtime() |
182 # Important: monotonic is "static" within a wakeup period |
181 |
183 # and does not need to call time.monotonic(), as it gets compared |
182 def horizon(self, snapshot=None): |
184 # to a specific time.monotonic() realisation |
183 snapshot=ensure_snapshot(snapshot) |
185 def _monotonic(self, snapshot): |
|
186 return self._value+(snapshot.monotonic()-snapshot.dreamtime()) |
|
187 |
|
188 def horizon(self, snapshot=Snapshot()): |
|
189 if snapshot.sleeping(): |
184 if snapshot.sleeping(): |
190 return math.inf |
185 return math.inf |
191 else: |
186 else: |
192 return self._monotonic(snapshot) |
187 return self.remaining(snapshot) |
193 |
188 |
194 @staticmethod |
|
195 def _now(snapshot): |
|
196 return snapshot.dreamtime() |
|
197 |
189 |
198 |
190 |
199 if platform.system()=='Darwin': |
191 if platform.system()=='Darwin': |
200 |
192 |
201 import Foundation |
193 import Foundation |