1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
20 """
21 Represents a period in time using a start and end time.
22
23 This is used both to store the time period for an event and for storing the
24 currently displayed time period in the GUI.
25 """
26
27 - def __init__(self, time_type, start_time, end_time):
28 """
29 Create a time period.
30
31 `start_time` and `end_time` should be of a type that can be handled
32 by the time_type object.
33 """
34 self.time_type = time_type
35 self.start_time, self.end_time = self._update(start_time, end_time)
36
38 return TimePeriod(self.time_type, self.start_time, self.end_time)
39
41 if isinstance(other, TimePeriod):
42 return (self.start_time == other.start_time and
43 self.end_time == other.end_time)
44 return False
45
47 return not (self == other)
48
50 return "TimePeriod<%s, %s>" % (self.start_time, self.end_time)
51
52 - def update(self, start_time, end_time,
53 start_delta=None, end_delta=None):
54 new_start, new_end = self._update(start_time, end_time, start_delta, end_delta)
55 return TimePeriod(self.time_type, new_start, new_end)
56
57 - def _update(self, start_time, end_time,
58 start_delta=None, end_delta=None):
59 """
60 Change the time period data.
61
62 Optionally add the deltas to the times like this: time + delta.
63
64 If data is invalid, it will not be set, and a ValueError will be raised
65 instead.
66
67 Data is invalid if time + delta is not within the range
68 [self.time_type.get_min_time(), self.time_type.get_max_time()] or if
69 the start time is larger than the end time.
70 """
71 new_start = self._ensure_within_range(start_time, start_delta,
72 _("Start time "))
73 new_end = self._ensure_within_range(end_time, end_delta,
74 _("End time "))
75 self._assert_period_is_valid(new_start, new_end)
76 return (new_start, new_end)
77
79 self._assert_start_gt_end(new_start, new_end)
80 self._assert_period_lt_max(new_start, new_end)
81
83 if new_start > new_end:
84 raise ValueError(_("Start time can't be after end time"))
85
87 MAX_ZOOM_DELTA, max_zoom_error_text = self.time_type.get_max_zoom_delta()
88 if MAX_ZOOM_DELTA and (new_end - new_start > MAX_ZOOM_DELTA):
89 raise PeriodTooLongError(max_zoom_error_text)
90
92 """
93 Return True if the given time is inside this period or on the border,
94 otherwise False.
95 """
96 return time >= self.start_time and time <= self.end_time
97
99 """Return True if this time period has any overlap with the given."""
100 return not (time_period.end_time < self.start_time or
101 time_period.start_time > self.end_time)
102
104 """
105 Return True if this time period is longer than just a point in time,
106 otherwise False.
107 """
108 return self.start_time != self.end_time
109
111 """
112 Return the time in the middle if this time period is longer than just a
113 point in time, otherwise the point in time for this time period.
114 """
115 return self.start_time + self.time_type.half_delta(self.delta())
116
117 - def zoom(self, times, ratio=0.5):
118 MAX_ZOOM_DELTA, max_zoom_error_text = self.time_type.get_max_zoom_delta()
119 MIN_ZOOM_DELTA, min_zoom_error_text = self.time_type.get_min_zoom_delta()
120 start_delta = self.time_type.mult_timedelta(self.delta(), times * ratio / 5.0)
121 end_delta = self.time_type.mult_timedelta(self.delta(), -times * (1.0 - ratio) / 5.0)
122 new_delta = self.delta() - 2 * start_delta
123 if MAX_ZOOM_DELTA and new_delta > MAX_ZOOM_DELTA:
124 raise ValueError(max_zoom_error_text)
125 if new_delta < MIN_ZOOM_DELTA:
126 raise ValueError(min_zoom_error_text)
127 return self.update(self.start_time, self.end_time, start_delta, end_delta)
128
129 - def move(self, direction):
130 """
131 Move this time period one 10th to the given direction.
132
133 Direction should be -1 for moving to the left or 1 for moving to the
134 right.
135 """
136 delta = self.time_type.mult_timedelta(self.delta(), direction / 10.0)
137 return self.move_delta(delta)
138
141
143 """Return the length of this time period as a timedelta object."""
144 return self.end_time - self.start_time
145
147 """
148 Center time period around time keeping the length.
149
150 If we can't center because we are on the edge, we do as good as we can.
151 """
152 delta = time - self.mean_time()
153 start_overflow = self._calculate_overflow(self.start_time, delta)[1]
154 end_overflow = self._calculate_overflow(self.end_time, delta)[1]
155 if start_overflow == -1:
156 delta = self.time_type.get_min_time()[0] - self.start_time
157 elif end_overflow == 1:
158 delta = self.time_type.get_max_time()[0] - self.end_time
159 return self.move_delta(delta)
160
162 """
163 Return new time (time + delta) or raise ValueError if it is not within
164 the range [self.time_type.get_min_time(),
165 self.time_type.get_max_time()].
166 """
167 if delta == None:
168 delta = self.time_type.get_zero_delta()
169 new_time, overflow, error_text = self._calculate_overflow(time, delta)
170 if overflow != 0:
171 error_text = "%s %s" % (error_prefix, error_text)
172 raise ValueError(error_text)
173 else:
174 return new_time
175
177 """
178 Return a tuple (new time, overflow flag).
179
180 Overflow flag can be -1 (overflow to the left), 0 (no overflow), or 1
181 (overflow to the right).
182
183 If overflow flag is 0 new time is time + delta, otherwise None.
184 """
185 try:
186 min_time, min_error_text = self.time_type.get_min_time()
187 max_time, max_error_text = self.time_type.get_max_time()
188 new_time = time + delta
189 if min_time and new_time < min_time:
190 return (None, -1, min_error_text)
191 if max_time and new_time > max_time:
192 return (None, 1, max_error_text)
193 return (new_time, 0, "")
194 except OverflowError:
195 if delta > self.time_type.get_zero_delta():
196 return (None, 1, max_error_text)
197 else:
198 return (None, -1, min_error_text)
199
201 """Returns a unicode string describing the time period."""
202 return self.time_type.format_period(self)
203
206
207
210
211
214
215
218
219
221 """
222 TimePeriod factory method.
223
224 Return a time period with the given length (represented as a timedelta)
225 centered around `time`.
226 """
227 half_length = time_type.mult_timedelta(length, 0.5)
228 start_time = time - half_length
229 end_time = time + half_length
230 return TimePeriod(time_type, start_time, end_time)
231