|
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 |
|
3 | | -from datetime import datetime |
| 3 | +from collections import namedtuple |
| 4 | + |
4 | 5 |
|
5 | 6 | EPOCH_YEAR = 1970 |
6 | 7 |
|
|
74 | 75 | TM_DECEMBER = 11 |
75 | 76 |
|
76 | 77 |
|
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 |
127 | 124 | 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] |
133 | 125 |
|
| 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 |
134 | 131 | 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] |
140 | 132 |
|
| 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 |
141 | 138 | 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