1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from datetime import datetime
20 from datetime import time
21 from datetime import timedelta
22 import calendar
23 import re
24
25 from timelinelib.calendar.monthnames import abbreviated_name_of_month
26 from timelinelib.calendar.weekdaynames import abbreviated_name_of_weekday
27 from timelinelib.db.objects import TimeOutOfRangeLeftError
28 from timelinelib.db.objects import TimeOutOfRangeRightError
29 from timelinelib.db.objects import TimePeriod
30 from timelinelib.db.objects import time_period_center
31 from timelinelib.drawing.interface import Strip
32 from timelinelib.drawing.utils import get_default_font
33 from timelinelib.time.typeinterface import TimeType
34
35
36
37 US_PER_SEC = 1000000
38 US_PER_DAY = 24 * 60 * 60 * US_PER_SEC
39
40
42
45
47 return not (self == other)
48
52
54 match = re.search(r"^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", time_string)
55 if match:
56 year = int(match.group(1))
57 month = int(match.group(2))
58 day = int(match.group(3))
59 hour = int(match.group(4))
60 minute = int(match.group(5))
61 second = int(match.group(6))
62 try:
63 return datetime(year, month, day, hour, minute, second)
64 except ValueError:
65 raise ValueError("Invalid time, time string = '%s'" % time_string)
66 else:
67 raise ValueError("Time not on correct format = '%s'" % time_string)
68
70 return [
71 (_("Go to &Today\tCtrl+T"), go_to_today_fn),
72 (_("Go to D&ate...\tCtrl+G"), go_to_date_fn),
73 ("SEP", None),
74 (_("Backward\tPgUp"), backward_fn),
75 (_("Forward\tPgDn"), forward_fn),
76 (_("Forward One Wee&k\tCtrl+K"), forward_one_week_fn),
77 (_("Back One &Week\tCtrl+W"), backward_one_week_fn),
78 (_("Forward One Mont&h\tCtrl+h"), forward_one_month_fn),
79 (_("Back One &Month\tCtrl+M"), backward_one_month_fn),
80 (_("Forward One Yea&r\tCtrl+R"), forward_one_year_fn),
81 (_("Back One &Year\tCtrl+Y"), backward_one_year_fn),
82 ("SEP", None),
83 (_("Fit Millennium"), fit_millennium_fn),
84 (_("Fit Century"), fit_century_fn),
85 (_("Fit Decade"), fit_decade_fn),
86 (_("Fit Year"), fit_year_fn),
87 (_("Fit Month"), fit_month_fn),
88 (_("Fit Week"), fit_week_fn),
89 (_("Fit Day"), fit_day_fn),
90 ]
91
94
99 def label_without_time(time):
100 return u"%s %s %s" % (time.day, abbreviated_name_of_month(time.month), time.year)
101 def time_label(time):
102 return time.time().isoformat()[0:5]
103 if time_period.is_period():
104 if time_period.has_nonzero_time():
105 label = u"%s to %s" % (label_with_time(time_period.start_time),
106 label_with_time(time_period.end_time))
107 else:
108 label = u"%s to %s" % (label_without_time(time_period.start_time),
109 label_without_time(time_period.end_time))
110 else:
111 if time_period.has_nonzero_time():
112 label = u"%s" % label_with_time(time_period.start_time)
113 else:
114 label = u"%s" % label_without_time(time_period.start_time)
115 return label
116
138
140 min_time = datetime(10, 1, 1)
141 return (min_time, _("can't be before year 10"))
142
144 max_time = datetime(9990, 1, 1)
145 return (max_time, _("can't be after year 9989"))
146
148 """
149 Return a tuple (major_strip, minor_strip) for current time period and
150 window size.
151 """
152 today = datetime.now()
153 tomorrow = today + timedelta(days=1)
154 day_period = TimePeriod(self, today, tomorrow)
155 one_day_width = metrics.calc_exact_width(day_period)
156 if one_day_width > 600:
157 return (StripDay(), StripHour())
158 elif one_day_width > 45:
159 return (StripWeek(config), StripWeekday())
160 elif one_day_width > 25:
161 return (StripMonth(), StripDay())
162 elif one_day_width > 1.5:
163 return (StripYear(), StripMonth())
164 elif one_day_width > 0.12:
165 return (StripDecade(), StripYear())
166 elif one_day_width > 0.012:
167 return (StripCentury(), StripDecade())
168 else:
169 return (StripCentury(), StripCentury())
170
172 """Return a new timedelta that is `num` times larger than `delta`."""
173 days = delta.days * num
174 seconds = delta.seconds * num
175 microseconds = delta.microseconds * num
176 return timedelta(days, seconds, microseconds)
177
180
182 return datetime.now()
183
189
199
201 return (timedelta(days=1200*365),
202 _("Can't zoom wider than 1200 years"))
203
205 return (timedelta(hours=1), _("Can't zoom deeper than 1 hour"))
206
209
211 nonzero_time = (time_period.start_time.time() != time(0, 0, 0) or
212 time_period.end_time.time() != time(0, 0, 0))
213 return nonzero_time
214
217
225
227 return (delta.seconds > 3600) or (delta.days > 0)
228
231
234
236 return "%04d-%02d-%02d" % (time.year, time.month, time.day)
237
239 return "%02d:%02d" % (time.hour, time.minute)
240
247
250
252 navigation_fn(lambda tp: tp.center(datetime.now()))
253
254
256 def navigate_to(time):
257 navigation_fn(lambda tp: tp.center(time))
258 main_frame.display_time_editor_dialog(
259 PyTimeType(), current_period.mean_time(), navigate_to, _("Go to Date"))
260
261
262 -def backward_fn(main_frame, current_period, navigation_fn):
263 _move_page_smart(current_period, navigation_fn, -1)
264
265
266 -def forward_fn(main_frame, current_period, navigation_fn):
267 _move_page_smart(current_period, navigation_fn, 1)
268
269
270 -def _move_page_smart(current_period, navigation_fn, direction):
271 if _whole_number_of_years(current_period):
272 _move_page_years(current_period, navigation_fn, direction)
273 elif _whole_number_of_months(current_period):
274 _move_page_months(current_period, navigation_fn, direction)
275 else:
276 navigation_fn(lambda tp: tp.move_delta(direction*current_period.delta()))
277
278
280 start, end = period.start_time, period.end_time
281 year_diff = _calculate_year_diff(period)
282 whole_years = start.replace(year=start.year+year_diff) == end
283 return whole_years and year_diff > 0
284
285
286 -def _move_page_years(curret_period, navigation_fn, direction):
287 def navigate(tp):
288 year_delta = direction * _calculate_year_diff(curret_period)
289 new_start_year = curret_period.start_time.year + year_delta
290 new_end_year = curret_period.end_time.year + year_delta
291 try:
292 new_start = curret_period.start_time.replace(year=new_start_year)
293 new_end = curret_period.end_time.replace(year=new_end_year)
294 except ValueError:
295 if direction < 0:
296 raise TimeOutOfRangeLeftError()
297 else:
298 raise TimeOutOfRangeRightError()
299 return tp.update(new_start, new_end)
300 navigation_fn(navigate)
301
302
304 return period.end_time.year - period.start_time.year
305
306
308 start, end = period.start_time, period.end_time
309 start_months = start.year * 12 + start.month
310 end_months = end.year * 12 + end.month
311 month_diff = end_months - start_months
312 whole_months = start.day == 1 and end.day == 1
313 return whole_months and month_diff > 0
314
315
316 -def _move_page_months(curret_period, navigation_fn, direction):
317 def navigate(tp):
318 start_months = curret_period.start_time.year * 12 + curret_period.start_time.month
319 end_months = curret_period.end_time.year * 12 + curret_period.end_time.month
320 month_diff = end_months - start_months
321 month_delta = month_diff * direction
322 new_start_year, new_start_month = _months_to_year_and_month(start_months + month_delta)
323 new_end_year, new_end_month = _months_to_year_and_month(end_months + month_delta)
324 try:
325 new_start = curret_period.start_time.replace(year=new_start_year, month=new_start_month)
326 new_end = curret_period.end_time.replace(year=new_end_year, month=new_end_month)
327 except ValueError:
328 if direction < 0:
329 raise TimeOutOfRangeLeftError()
330 else:
331 raise TimeOutOfRangeRightError()
332 return tp.update(new_start, new_end)
333 navigation_fn(navigate)
334
335
337 years = int(months / 12)
338 month = months - years * 12
339 if month == 0:
340 month = 12
341 years -= 1
342 return years, month
343
344
346 wk = timedelta(days=7)
347 navigation_fn(lambda tp: tp.move_delta(wk))
348
349
351 wk = timedelta(days=7)
352 navigation_fn(lambda tp: tp.move_delta(-1*wk))
353
354
356 """
357 Currently does notice leap years.
358 """
359 tm = current_period.mean_time()
360 if direction > 0:
361 if tm.month == 2:
362 d = 28
363 elif tm.month in (4,6,9,11):
364 d = 30
365 else:
366 d = 31
367 else:
368 if tm.month == 3:
369 d = 28
370 elif tm.month in (5,7,10,12):
371 d = 30
372 else:
373 d = 31
374 mv = timedelta(days=d)
375 navigation_fn(lambda tp: tp.move_delta(direction*mv))
376
377
380
381
384
385
387 yr = timedelta(days=365)
388 navigation_fn(lambda tp: tp.move_delta(yr))
389
390
392 yr = timedelta(days=365)
393 navigation_fn(lambda tp: tp.move_delta(-1*yr))
394
395
405
406
409
410
413
414
417
418
428
429
431 mean = current_period.mean_time()
432 start = datetime(int(mean.year/10)*10, 1, 1)
433 end = datetime(int(mean.year/10)*10+10, 1, 1)
434 navigation_fn(lambda tp: tp.update(start, end))
435
436
437 -def fit_year_fn(main_frame, current_period, navigation_fn):
438 mean = current_period.mean_time()
439 start = datetime(mean.year, 1, 1)
440 end = datetime(mean.year + 1, 1, 1)
441 navigation_fn(lambda tp: tp.update(start, end))
442
443
444 -def fit_month_fn(main_frame, current_period, navigation_fn):
445 mean = current_period.mean_time()
446 start = datetime(mean.year, mean.month, 1)
447 if mean.month == 12:
448 end = datetime(mean.year + 1, 1, 1)
449 else:
450 end = datetime(mean.year, mean.month + 1, 1)
451 navigation_fn(lambda tp: tp.update(start, end))
452
453
454 -def fit_day_fn(main_frame, current_period, navigation_fn):
455 mean = current_period.mean_time()
456 start = datetime(mean.year, mean.month, mean.day)
457 end = start + timedelta(days=1)
458 navigation_fn(lambda tp: tp.update(start, end))
459
460
461 -def fit_week_fn(main_frame, current_period, navigation_fn):
470
471
473
474 - def label(self, time, major=False):
475 if major:
476
477 start_year = self._century_start_year(time.year)
478 next_start_year = start_year + 100
479 return str(next_start_year / 100) + " century"
480 return ""
481
483 return datetime(max(self._century_start_year(time.year), 10), 1, 1)
484
486 return time.replace(year=time.year + 100)
487
490
492 year = (int(year) / 100) * 100
493
494
495 return year
496
497
499
500 - def label(self, time, major=False):
501
502 return str(self._decade_start_year(time.year)) + "s"
503
505 return datetime(self._decade_start_year(time.year), 1, 1)
506
508 return time.replace(year=time.year+10)
509
511 return (int(year) / 10) * 10
512
515
516
518
519 - def label(self, time, major=False):
520 return str(time.year)
521
523 return datetime(time.year, 1, 1)
524
526 return time.replace(year=time.year+1)
527
530
531
533
534 - def label(self, time, major=False):
538
540 return datetime(time.year, time.month, 1)
541
544
547
548
550
551 - def label(self, time, major=False):
555
558
560 return time + timedelta(1)
561
567
568
570
574
575 - def label(self, time, major=False):
576 if major:
577
578 first_weekday = self.start(time)
579 next_first_weekday = self.increment(first_weekday)
580 last_weekday = next_first_weekday - timedelta(days=1)
581 range_string = self._time_range_string(first_weekday, last_weekday)
582 if self.config.week_start == "monday":
583 return (_("Week") + " %s (%s)") % (time.isocalendar()[1], range_string)
584 else:
585
586 return range_string
587
588 return ""
589
591 stripped_date = datetime(time.year, time.month, time.day)
592 if self.config.week_start == "monday":
593 days_to_subtract = stripped_date.weekday()
594 else:
595
596 days_to_subtract = (stripped_date.weekday() + 1) % 7
597 return stripped_date - timedelta(days=days_to_subtract)
598
600 return time + timedelta(7)
601
604
606 """
607 Examples:
608
609 * 1-7 Jun 2009
610 * 28 Jun-3 Jul 2009
611 * 28 Jun 08-3 Jul 2009
612 """
613 if time1.year == time2.year:
614 if time1.month == time2.month:
615 return "%s-%s %s %s" % (time1.day, time2.day,
616 abbreviated_name_of_month(time1.month),
617 time1.year)
618 return "%s %s-%s %s %s" % (time1.day,
619 abbreviated_name_of_month(time1.month),
620 time2.day,
621 abbreviated_name_of_month(time2.month),
622 time1.year)
623 return "%s %s %s-%s %s %s" % (time1.day,
624 abbreviated_name_of_month(time1.month),
625 time1.year,
626 time2.day,
627 abbreviated_name_of_month(time2.month),
628 time2.year)
629
630
632
633 - def label(self, time, major=False):
640
643
645 return time + timedelta(1)
646
649
650
652
653 - def label(self, time, major=False):
658
661
663 return time + timedelta(hours=1)
664
667
668
670 """Return a timedelta representing the given number of microseconds."""
671 return timedelta(microseconds=microsecs)
672
673
679
680
682 delta = timedelta(days=1) * num
683 start_time = period.start_time + delta
684 end_time = period.end_time + delta
685 return TimePeriod(period.time_type, start_time, end_time)
686
687
689 delta = timedelta(weeks=1) * num
690 start_time = period.start_time + delta
691 end_time = period.end_time + delta
692 return TimePeriod(period.time_type, start_time, end_time)
693
694
696 try:
697 delta = num
698 years = abs(delta) / 12
699 if num < 0:
700 years = -years
701 delta = delta - 12 * years
702 if delta < 0:
703 start_month = period.start_time.month + 12 + delta
704 end_month = period.end_time.month + 12 + delta
705 if start_month > 12:
706 start_month -=12
707 end_month -=12
708 if start_month > period.start_time.month:
709 years -= 1
710 else:
711 start_month = period.start_time.month + delta
712 end_month = period.start_time.month + delta
713 if start_month > 12:
714 start_month -=12
715 end_month -=12
716 years += 1
717 start_year = period.start_time.year + years
718 end_year = period.start_time.year + years
719 start_time = period.start_time.replace(year=start_year, month=start_month)
720 end_time = period.end_time.replace(year=end_year, month=end_month)
721 return TimePeriod(period.time_type, start_time, end_time)
722 except ValueError:
723 return None
724
725
727 try:
728 delta = num
729 start_year = period.start_time.year
730 end_year = period.end_time.year
731 start_time = period.start_time.replace(year=start_year + delta)
732 end_time = period.end_time.replace(year=end_year + delta)
733 return TimePeriod(period.time_type, start_time, end_time)
734 except ValueError:
735 return None
736