Skip to content

Commit 86117d4

Browse files
committed
Improves performances
1 parent 71fde7e commit 86117d4

File tree

7 files changed

+895
-2166
lines changed

7 files changed

+895
-2166
lines changed
Lines changed: 86 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: utf-8 -*-
22

3-
from datetime import datetime
3+
from collections import namedtuple
4+
45

56
EPOCH_YEAR = 1970
67

@@ -74,119 +75,92 @@
7475
TM_DECEMBER = 11
7576

7677

77-
class Breakdown(object):
78-
79-
def __init__(self, year, month, day,
80-
hour, minute, second, microsecond,
81-
offset, is_dst, abbrev):
82-
self.year = year
83-
self.month = month
84-
self.day = day
85-
self.hour = hour
86-
self.minute = minute
87-
self.second = second
88-
self.microsecond = microsecond
89-
self.offset = offset
90-
self.is_dst = is_dst
91-
self.abbrev = abbrev
92-
93-
@classmethod
94-
def local_time(cls, unix_time, transition_type):
95-
"""
96-
Returns a translation as a broken down time
97-
for a particular transition type.
98-
99-
:type unix_time: int
100-
:type transition_type: TransitionType
101-
102-
:rtype: Breakdown
103-
"""
104-
year = EPOCH_YEAR
105-
microsecond = int(round(unix_time % 1, 6) * 1e6)
106-
seconds = int(unix_time)
107-
108-
# Shift to a base year that is 400-year aligned.
109-
if seconds >= 0:
110-
seconds -= 10957 * SECS_PER_DAY
111-
year += 30 # == 2000
112-
else:
113-
seconds += (146097 - 10957) * SECS_PER_DAY
114-
year -= 370 # == 1600
115-
116-
seconds += transition_type.utc_offset
117-
118-
# Handle years in chunks of 400/100/4/1
119-
year += 400 * (seconds // SECS_PER_400_YEARS)
120-
seconds %= SECS_PER_400_YEARS
121-
if seconds < 0:
122-
seconds += SECS_PER_400_YEARS
123-
year -= 400
124-
125-
leap_year = 1 # 4-century aligned
126-
78+
Breakdown = namedtuple(
79+
'Breakdown',
80+
['year', 'month', 'day',
81+
'hour', 'minute', 'second', 'microsecond',
82+
'offset', 'is_dst', 'abbrev']
83+
)
84+
85+
86+
def local_time(unix_time, transition_type):
87+
"""
88+
Returns a translation as a broken down time
89+
for a particular transition type.
90+
91+
:type unix_time: int
92+
:type transition_type: TransitionType
93+
94+
:rtype: Breakdown
95+
"""
96+
year = EPOCH_YEAR
97+
microsecond = int(round(unix_time % 1, 6) * 1e6)
98+
seconds = int(unix_time)
99+
100+
# Shift to a base year that is 400-year aligned.
101+
if seconds >= 0:
102+
seconds -= 10957 * SECS_PER_DAY
103+
year += 30 # == 2000
104+
else:
105+
seconds += (146097 - 10957) * SECS_PER_DAY
106+
year -= 370 # == 1600
107+
108+
seconds += transition_type.utc_offset
109+
110+
# Handle years in chunks of 400/100/4/1
111+
year += 400 * (seconds // SECS_PER_400_YEARS)
112+
seconds %= SECS_PER_400_YEARS
113+
if seconds < 0:
114+
seconds += SECS_PER_400_YEARS
115+
year -= 400
116+
117+
leap_year = 1 # 4-century aligned
118+
119+
sec_per_100years = SECS_PER_100_YEARS[leap_year]
120+
while seconds >= sec_per_100years:
121+
seconds -= sec_per_100years
122+
year += 100
123+
leap_year = 0 # 1-century, non 4-century aligned
127124
sec_per_100years = SECS_PER_100_YEARS[leap_year]
128-
while seconds >= sec_per_100years:
129-
seconds -= sec_per_100years
130-
year += 100
131-
leap_year = 0 # 1-century, non 4-century aligned
132-
sec_per_100years = SECS_PER_100_YEARS[leap_year]
133125

126+
sec_per_4years = SECS_PER_4_YEARS[leap_year]
127+
while seconds >= sec_per_4years:
128+
seconds -= sec_per_4years
129+
year += 4
130+
leap_year = 1 # 4-year, non century aligned
134131
sec_per_4years = SECS_PER_4_YEARS[leap_year]
135-
while seconds >= sec_per_4years:
136-
seconds -= sec_per_4years
137-
year += 4
138-
leap_year = 1 # 4-year, non century aligned
139-
sec_per_4years = SECS_PER_4_YEARS[leap_year]
140132

133+
sec_per_year = SECS_PER_YEAR[leap_year]
134+
while seconds >= sec_per_year:
135+
seconds -= sec_per_year
136+
year += 1
137+
leap_year = 0 # non 4-year aligned
141138
sec_per_year = SECS_PER_YEAR[leap_year]
142-
while seconds >= sec_per_year:
143-
seconds -= sec_per_year
144-
year += 1
145-
leap_year = 0 # non 4-year aligned
146-
sec_per_year = SECS_PER_YEAR[leap_year]
147-
148-
# Handle months and days
149-
month = TM_DECEMBER + 1
150-
day = seconds // SECS_PER_DAY + 1
151-
seconds %= SECS_PER_DAY
152-
while month != TM_JANUARY + 1:
153-
month_offset = MONTHS_OFFSETS[leap_year][month]
154-
if day > month_offset:
155-
day -= month_offset
156-
break
157-
158-
month -= 1
159-
160-
# Handle hours, minutes, seconds and microseconds
161-
hour = seconds // SECS_PER_HOUR
162-
seconds %= SECS_PER_HOUR
163-
minute = seconds // SECS_PER_MIN
164-
second = seconds % SECS_PER_MIN
165-
166-
offset = transition_type.utc_offset
167-
is_dst = transition_type.is_dst
168-
abbrev = transition_type.abbrev
169-
170-
return cls(
171-
int(year), int(month), int(day),
172-
int(hour), int(minute), int(second), int(microsecond),
173-
offset, is_dst, abbrev
174-
)
175-
176-
177-
@classmethod
178-
def is_leap(cls, year):
179-
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
180-
181-
def as_datetime(self):
182-
return datetime(
183-
self.year, self.month, self.day,
184-
self.hour, self.minute, self.second, self.microsecond
185-
)
186-
187-
def __repr__(self):
188-
return '<Breakdown [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]>'.format(
189-
self.year, self.month, self.day,
190-
self.hour, self.minute, self.second, self.microsecond,
191-
self.offset, self.is_dst, self.abbrev
192-
)
139+
140+
# Handle months and days
141+
month = TM_DECEMBER + 1
142+
day = seconds // SECS_PER_DAY + 1
143+
seconds %= SECS_PER_DAY
144+
while month != TM_JANUARY + 1:
145+
month_offset = MONTHS_OFFSETS[leap_year][month]
146+
if day > month_offset:
147+
day -= month_offset
148+
break
149+
150+
month -= 1
151+
152+
# Handle hours, minutes, seconds and microseconds
153+
hour = seconds // SECS_PER_HOUR
154+
seconds %= SECS_PER_HOUR
155+
minute = seconds // SECS_PER_MIN
156+
second = seconds % SECS_PER_MIN
157+
158+
offset = transition_type.utc_offset
159+
is_dst = transition_type.is_dst
160+
abbrev = transition_type.abbrev
161+
162+
return (
163+
year, month, day,
164+
hour, minute, second, microsecond,
165+
offset, is_dst, abbrev
166+
)

0 commit comments

Comments
 (0)