|
5 | 5 | from collections import namedtuple |
6 | 6 | from datetime import date, datetime, timedelta |
7 | 7 | from numpy import ( |
8 | | - array, concatenate, cos, float64, int64, isnan, isinf, linspace, |
| 8 | + array, concatenate, cos, float64, floor, int64, isnan, isinf, linspace, |
9 | 9 | nan, ndarray, nonzero, pi, rollaxis, searchsorted, sin, where, zeros_like, |
10 | 10 |
|
11 | 11 | ) |
@@ -181,25 +181,44 @@ def utc(self, year, month=1, day=1, hour=0, minute=0, second=0.0): |
181 | 181 | def _utc(self, tup): |
182 | 182 | # Build a Time from a UTC tuple, carefully preserving its exact |
183 | 183 | # second number in the Time's hidden TAI seconds field. |
| 184 | + |
184 | 185 | year, month, day, hour, minute, second = tup |
185 | 186 | cutoff = self.julian_calendar_cutoff |
186 | 187 |
|
187 | | - # Figure out exactly the TAI second number. |
188 | | - seconds = (julian_day(year, month, day, cutoff) - 0.5) * DAY_S |
189 | | - seconds, sfr = divmod(seconds, 1.0) # in case there were any fractions |
190 | | - seconds += interp(seconds, self._leap_utc, self._leap_offsets) |
191 | | - more = hour * 3600.0 + minute * 60.0 + second |
192 | | - seconds2, sfr = divmod(sfr + more, 1.0) |
193 | | - seconds += seconds2 |
| 188 | + # Carefully preserve the day `fraction` before losing precision |
| 189 | + # by building the Julian day number. |
| 190 | + whole = floor(day) |
| 191 | + fraction = day - whole - 0.5 |
| 192 | + whole = julian_day(year, month, whole, cutoff) |
| 193 | + |
| 194 | + # Use "Julian seconds" to index into the leap second table. |
| 195 | + jseconds = whole * DAY_S |
| 196 | + leap_seconds = interp(jseconds, self._leap_utc, self._leap_offsets) |
| 197 | + |
| 198 | + # For accurate reconstruction of UTC later, save the time as TAI |
| 199 | + # seconds plus the exact seconds fraction, in a secret tuple. |
| 200 | + sfloor = floor(second) |
| 201 | + sfraction = second - sfloor |
| 202 | + seconds = sfloor + leap_seconds + minute * 60.0 + hour * 3600.0 |
| 203 | + seconds2 = seconds + fraction * DAY_S |
| 204 | + |
| 205 | + sfloor2 = floor(seconds2) # in case minutes or hours had fractions |
| 206 | + sfraction2 = seconds2 - sfloor2 |
| 207 | + tai_seconds = ( |
| 208 | + sfloor2 + whole * DAY_S, |
| 209 | + sfraction + sfraction2, |
| 210 | + ) |
194 | 211 |
|
195 | | - # For the other timescales, use the usual Julian date + fraction. |
196 | | - whole, fraction = divmod(seconds, DAY_S) |
197 | | - fraction += sfr |
198 | | - fraction /= DAY_S |
| 212 | + # And save the time more conventionally, counted in days. |
| 213 | + fraction += (seconds + sfraction) / DAY_S |
| 214 | + whole2 = floor(fraction) |
| 215 | + whole += whole2 |
| 216 | + fraction -= whole2 |
199 | 217 |
|
200 | 218 | t = Time(self, whole, fraction + tt_minus_tai) |
201 | 219 | t.tai_fraction = fraction |
202 | | - t._tai_seconds = seconds, sfr |
| 220 | + t._tai_seconds = tai_seconds |
| 221 | + |
203 | 222 | return t |
204 | 223 |
|
205 | 224 | def _jd(self, year, month, day, hour, minute, second): |
|
0 commit comments