1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from datetime import datetime
20 import re
21
22 from timelinelib.calendar.gregorian.gregorian import GregorianDateTime
23 from timelinelib.calendar.gregorian.monthnames import abbreviated_name_of_month
24 from timelinelib.calendar.gregorian.time import GregorianDelta
25 from timelinelib.calendar.gregorian.time import GregorianTime
26 from timelinelib.calendar.gregorian.time import SECONDS_IN_DAY
27 from timelinelib.calendar.gregorian.weekdaynames import abbreviated_name_of_weekday
28 from timelinelib.calendar.timetype import TimeType
29 from timelinelib.canvas.data import TimeOutOfRangeLeftError
30 from timelinelib.canvas.data import TimeOutOfRangeRightError
31 from timelinelib.canvas.data import TimePeriod
32 from timelinelib.canvas.data import time_period_center
33 from timelinelib.canvas.drawing.interface import Strip
34
35
36 BC = _("BC")
40
43
45 return not (self == other)
46
49
51 match = re.search(r"^(-?\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", time_string)
52 if match:
53 year = int(match.group(1))
54 month = int(match.group(2))
55 day = int(match.group(3))
56 hour = int(match.group(4))
57 minute = int(match.group(5))
58 second = int(match.group(6))
59 try:
60 return GregorianDateTime(year, month, day, hour, minute, second).to_time()
61 except ValueError:
62 raise ValueError("Invalid time, time string = '%s'" % time_string)
63 else:
64 raise ValueError("Time not on correct format = '%s'" % time_string)
65
67 return [
68 (_("Go to &Today") + "\tCtrl+T", go_to_today_fn),
69 (_("Go to &Date...") + "\tCtrl+G", go_to_date_fn),
70 ("SEP", None),
71 (_("Backward") + "\tPgUp", backward_fn),
72 (_("Forward") + "\tPgDn", forward_fn),
73 (_("Forward One Wee&k") + "\tCtrl+K", forward_one_week_fn),
74 (_("Back One &Week") + "\tCtrl+W", backward_one_week_fn),
75 (_("Forward One Mont&h") + "\tCtrl+H", forward_one_month_fn),
76 (_("Back One &Month") + "\tCtrl+M", backward_one_month_fn),
77 (_("Forward One Yea&r") + "\tCtrl+R", forward_one_year_fn),
78 (_("Back One &Year") + "\tCtrl+Y", backward_one_year_fn),
79 ("SEP", None),
80 (_("Fit Millennium"), fit_millennium_fn),
81 (_("Fit Century"), create_strip_fitter(StripCentury)),
82 (_("Fit Decade"), create_strip_fitter(StripDecade)),
83 (_("Fit Year"), create_strip_fitter(StripYear)),
84 (_("Fit Month"), create_strip_fitter(StripMonth)),
85 (_("Fit Week"), fit_week_fn),
86 (_("Fit Day"), create_strip_fitter(StripDay)),
87 ]
88
93
94 def label_without_time(time):
95 gregorian_datetime = GregorianDateTime.from_time(time)
96 return u"%s %s %s" % (
97 gregorian_datetime.day,
98 abbreviated_name_of_month(gregorian_datetime.month),
99 format_year(gregorian_datetime.year)
100 )
101
102 def time_label(time):
103 return "%02d:%02d" % time.get_time_of_day()[:-1]
104 if time_period.is_period():
105 if has_nonzero_time(time_period):
106 label = u"%s to %s" % (label_with_time(time_period.start_time),
107 label_with_time(time_period.end_time))
108 else:
109 label = u"%s to %s" % (label_without_time(time_period.start_time),
110 label_without_time(time_period.end_time))
111 else:
112 if has_nonzero_time(time_period):
113 label = u"%s" % label_with_time(time_period.start_time)
114 else:
115 label = u"%s" % label_without_time(time_period.start_time)
116 return label
117
123
126
129
131 """
132 Return a tuple (major_strip, minor_strip) for current time period and
133 window size.
134 """
135 day_period = TimePeriod(GregorianTime(0, 0), GregorianTime(1, 0))
136 one_day_width = metrics.calc_exact_width(day_period)
137 if one_day_width > 20000:
138 return (StripHour(), StripMinute())
139 elif one_day_width > 600:
140 return (StripDay(), StripHour())
141 elif one_day_width > 45:
142 return (StripWeek(appearance), StripWeekday())
143 elif one_day_width > 25:
144 return (StripMonth(), StripDay())
145 elif one_day_width > 1.5:
146 return (StripYear(), StripMonth())
147 elif one_day_width > 0.12:
148 return (StripDecade(), StripYear())
149 elif one_day_width > 0.012:
150 return (StripCentury(), StripDecade())
151 else:
152 return (StripCentury(), StripCentury())
153
156
159
162
174
177
179 return u"gregoriantime"
180
188
191
194
196 return time.julian_day % 7
197
201
205
209
210
211 -def go_to_date_fn(main_frame, current_period, navigation_fn):
212 def navigate_to(time):
213 navigation_fn(lambda tp: tp.center(time))
214 main_frame.display_time_editor_dialog(
215 GregorianTimeType(), current_period.mean_time(), navigate_to, _("Go to Date"))
216
217
218 -def backward_fn(main_frame, current_period, navigation_fn):
219 _move_page_smart(current_period, navigation_fn, -1)
220
221
222 -def forward_fn(main_frame, current_period, navigation_fn):
223 _move_page_smart(current_period, navigation_fn, 1)
224
225
226 -def _move_page_smart(current_period, navigation_fn, direction):
227 if _whole_number_of_years(current_period):
228 _move_page_years(current_period, navigation_fn, direction)
229 elif _whole_number_of_months(current_period):
230 _move_page_months(current_period, navigation_fn, direction)
231 else:
232 navigation_fn(lambda tp: tp.move_delta(direction * current_period.delta()))
233
254
255
256 -def _move_page_years(curret_period, navigation_fn, direction):
257 def navigate(tp):
258 year_delta = direction * _calculate_year_diff(curret_period)
259 gregorian_start = GregorianDateTime.from_time(curret_period.start_time)
260 gregorian_end = GregorianDateTime.from_time(curret_period.end_time)
261 new_start_year = gregorian_start.year + year_delta
262 new_end_year = gregorian_end.year + year_delta
263 try:
264 new_start = gregorian_start.replace(year=new_start_year).to_time()
265 new_end = gregorian_end.replace(year=new_end_year).to_time()
266 if new_end > GregorianTimeType().get_max_time():
267 raise ValueError()
268 if new_start < GregorianTimeType().get_min_time():
269 raise ValueError()
270 except ValueError:
271 if direction < 0:
272 raise TimeOutOfRangeLeftError()
273 else:
274 raise TimeOutOfRangeRightError()
275 return tp.update(new_start, new_end)
276 navigation_fn(navigate)
277
282
285 """
286 >>> from timelinelib.test.utils import gregorian_period
287
288 >>> _whole_number_of_months(gregorian_period("1 Jan 2013", "1 Jan 2014"))
289 True
290
291 >>> _whole_number_of_months(gregorian_period("1 Jan 2013", "1 Mar 2014"))
292 True
293
294 >>> _whole_number_of_months(gregorian_period("2 Jan 2013", "2 Mar 2014"))
295 False
296
297 >>> _whole_number_of_months(gregorian_period("1 Jan 2013 12:00", "1 Mar 2014"))
298 False
299 """
300 start, end = GregorianDateTime.from_time(period.start_time), GregorianDateTime.from_time(period.end_time)
301 start_months = start.year * 12 + start.month
302 end_months = end.year * 12 + end.month
303 month_diff = end_months - start_months
304 return (start.is_first_of_month() and
305 end.is_first_of_month() and
306 month_diff > 0)
307
308
309 -def _move_page_months(curret_period, navigation_fn, direction):
310 def navigate(tp):
311 start = GregorianDateTime.from_time(curret_period.start_time)
312 end = GregorianDateTime.from_time(curret_period.end_time)
313 start_months = start.year * 12 + start.month
314 end_months = end.year * 12 + end.month
315 month_diff = end_months - start_months
316 month_delta = month_diff * direction
317 new_start_year, new_start_month = _months_to_year_and_month(start_months + month_delta)
318 new_end_year, new_end_month = _months_to_year_and_month(end_months + month_delta)
319 try:
320 new_start = start.replace(year=new_start_year, month=new_start_month)
321 new_end = end.replace(year=new_end_year, month=new_end_month)
322 start = new_start.to_time()
323 end = new_end.to_time()
324 if end > GregorianTimeType().get_max_time():
325 raise ValueError()
326 if start < GregorianTimeType().get_min_time():
327 raise ValueError()
328 except ValueError:
329 if direction < 0:
330 raise TimeOutOfRangeLeftError()
331 else:
332 raise TimeOutOfRangeRightError()
333 return tp.update(start, end)
334 navigation_fn(navigate)
335
338 years = int(months / 12)
339 month = months - years * 12
340 if month == 0:
341 month = 12
342 years -= 1
343 return years, month
344
349
354
357 """
358 Currently does notice leap years.
359 """
360
361 tm = current_period.mean_time()
362 gt = GregorianDateTime.from_time(tm)
363 if direction > 0:
364 if gt.month == 2:
365 d = 28
366 elif gt.month in (4, 6, 9, 11):
367 d = 30
368 else:
369 d = 31
370 else:
371 if gt.month == 3:
372 d = 28
373 elif gt.month in (5, 7, 10, 12):
374 d = 30
375 else:
376 d = 31
377 mv = GregorianDelta.from_days(d)
378 navigation_fn(lambda tp: tp.move_delta(direction * mv))
379
383
387
392
397
408
412
416
417
418 -def fit_week_fn(main_frame, current_period, navigation_fn):
427
436 navigation_fn(navigate)
437 return fit
438
441
442 """
443 Year Name | Year integer | Decade name
444 ----------+--------------+------------
445 .. | .. |
446 200 BC | -199 | 200s BC (100 years)
447 ----------+--------------+------------
448 199 BC | -198 |
449 ... | ... | 100s BC (100 years)
450 100 BC | -99 |
451 ----------+--------------+------------
452 99 BC | -98 |
453 ... | ... | 0s BC (only 99 years)
454 1 BC | 0 |
455 ----------+--------------+------------
456 1 | 1 |
457 ... | ... | 0s (only 99 years)
458 99 | 99 |
459 ----------+--------------+------------
460 100 | 100 |
461 .. | .. | 100s (100 years)
462 199 | 199 |
463 ----------+--------------+------------
464 200 | 200 | 200s (100 years)
465 .. | .. |
466 """
467
468 - def label(self, time, major=False):
469 if major:
470 gregorian_time = GregorianDateTime.from_time(time)
471 return self._format_century(
472 self._century_number(
473 self._century_start_year(gregorian_time.year)
474 ),
475 gregorian_time.is_bc()
476 )
477 else:
478 return ""
479
486
492
494 if century_start_year > 99:
495 return century_start_year
496 elif century_start_year >= -98:
497 return 0
498 else:
499 return self._century_number(-century_start_year - 98)
500
502 return start_year + self._century_year_len(start_year)
503
505 if start_year in [-98, 1]:
506 return 99
507 else:
508 return 100
509
515
517 if year > 99:
518 return year - int(year) % 100
519 elif year >= 1:
520 return 1
521 elif year >= -98:
522 return -98
523 else:
524 return -self._century_start_year(-year + 1) - 98
525
528
529 """
530 Year Name | Year integer | Decade name
531 ----------+--------------+------------
532 .. | .. |
533 20 BC | -19 | 20s BC (10 years)
534 ----------+--------------+------------
535 19 BC | -18 |
536 18 BC | -17 |
537 17 BC | -16 |
538 16 BC | -15 |
539 15 BC | -14 | 10s BC (10 years)
540 14 BC | -13 |
541 13 BC | -12 |
542 12 BC | -11 |
543 11 BC | -10 |
544 10 BC | -9 |
545 ----------+--------------+------------
546 9 BC | -8 |
547 8 BC | -7 |
548 7 BC | -6 |
549 6 BC | -5 |
550 5 BC | -4 | 0s BC (only 9 years)
551 4 BC | -3 |
552 3 BC | -2 |
553 2 BC | -1 |
554 1 BC | 0 |
555 ----------+--------------+------------
556 1 | 1 |
557 2 | 2 |
558 3 | 3 |
559 4 | 4 |
560 5 | 5 | 0s (only 9 years)
561 6 | 6 |
562 7 | 7 |
563 8 | 8 |
564 9 | 9 |
565 ----------+--------------+------------
566 10 | 10 |
567 11 | 11 |
568 12 | 12 |
569 13 | 13 |
570 14 | 14 |
571 15 | 15 | 10s (10 years)
572 16 | 16 |
573 17 | 17 |
574 18 | 18 |
575 19 | 19 |
576 ----------+--------------+------------
577 20 | 20 | 20s (10 years)
578 .. | .. |
579 """
580
582 self.skip_s_in_decade_text = False
583
584 - def label(self, time, major=False):
585 gregorian_time = GregorianDateTime.from_time(time)
586 return self._format_decade(
587 self._decade_number(self._decade_start_year(gregorian_time.year)),
588 gregorian_time.is_bc()
589 )
590
597
603
605 self.skip_s_in_decade_text = value
606
616
618 if year > 9:
619 return int(year) - (int(year) % 10)
620 elif year >= 1:
621 return 1
622 elif year >= -8:
623 return -8
624 else:
625 return -self._decade_start_year(-year + 1) - 8
626
628 return start_year + self._decade_year_len(start_year)
629
631 if self._decade_number(start_year) == 0:
632 return 9
633 else:
634 return 10
635
637 if start_year > 9:
638 return start_year
639 elif start_year >= -8:
640 return 0
641 else:
642 return self._decade_number(-start_year - 8)
643
646
647 - def label(self, time, major=False):
649
654
658
661
662 - def label(self, time, major=False):
668
676
681
684
685 - def label(self, time, major=False):
692
700
703
706
709
713
714 - def label(self, time, major=False):
730
732 start = GregorianDateTime.from_time(start)
733 end = GregorianDateTime.from_time(end)
734 if start.year == end.year:
735 if start.month == end.month:
736 return "%s-%s %s %s" % (start.day, end.day,
737 abbreviated_name_of_month(start.month),
738 format_year(start.year))
739 return "%s %s-%s %s %s" % (start.day,
740 abbreviated_name_of_month(start.month),
741 end.day,
742 abbreviated_name_of_month(end.month),
743 format_year(start.year))
744 return "%s %s %s-%s %s %s" % (start.day,
745 abbreviated_name_of_month(start.month),
746 format_year(start.year),
747 end.day,
748 abbreviated_name_of_month(end.month),
749 format_year(end.year))
750
758
761
764
765 - def label(self, time, major=False):
775
780
783
786
789
790 - def label(self, time, major=False):
796
800
803
806
807 - def label(self, time, major=False):
813
817
820
827
834
841
844 def move_time(time):
845 gregorian_time = GregorianDateTime.from_time(time)
846 new_month = gregorian_time.month + num
847 new_year = gregorian_time.year
848 while new_month < 1:
849 new_month += 12
850 new_year -= 1
851 while new_month > 12:
852 new_month -= 12
853 new_year += 1
854 return gregorian_time.replace(year=new_year, month=new_month).to_time()
855 try:
856 return TimePeriod(
857 move_time(period.start_time),
858 move_time(period.end_time)
859 )
860 except ValueError:
861 return None
862
874
879
882
883 - def __init__(self, name, single_name, value_fn, remainder_fn):
888
889 @property
892
893 @property
895 return self._single_name
896
897 @property
899 return self._value_fn
900
901 @property
902 - def remainder_fn(self):
903 return self._remainder_fn
904
905
906 YEARS = DurationType(_('years'), _('year'),
907 lambda ds: ds[0] / 365,
908 lambda ds: (ds[0] % 365, ds[1]))
909 MONTHS = DurationType(_('months'), _('month'),
910 lambda ds: ds[0] / 30,
911 lambda ds: (ds[0] % 30, ds[1]))
912 WEEKS = DurationType(_('weeks'), _('week'),
913 lambda ds: ds[0] / 7,
914 lambda ds: (ds[0] % 7, ds[1]))
915 DAYS = DurationType(_('days'), _('day'),
916 lambda ds: ds[0],
917 lambda ds: (0, ds[1]))
918 HOURS = DurationType(_('hours'), _('hour'),
919 lambda ds: ds[0] * 24 + ds[1] / 3600,
920 lambda ds: (0, ds[1] % 3600))
921 MINUTES = DurationType(_('minutes'), _('minute'),
922 lambda ds: ds[0] * 1440 + ds[1] / 60,
923 lambda ds: (0, ds[1] % 60))
924 SECONDS = DurationType(_('seconds'), _('second'),
925 lambda ds: ds[0] * 86400 + ds[1],
926 lambda ds: (0, 0))
974