<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 25, 2019, at 3:42 AM, Aldcroft, Thomas <<a href="mailto:aldcroft@head.cfa.harvard.edu" class="">aldcroft@head.cfa.harvard.edu</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div dir="ltr" class=""><br class=""></div><br class=""><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Aug 24, 2019 at 7:24 PM Russell Owen <<a href="mailto:rowen@uw.edu" class="">rowen@uw.edu</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;" class="">Thank you for the suggestion, but I’m afraid I don’t see how it works.. The given date I have to work from is a date in UTC. By specifying “Time(date, scale=“tai”)” I would be lying to the system: saying the date was TAI when it is UTC. I would expect that to give the wrong answer very near a UTC leap second.</div></blockquote><div class=""><br class=""></div><div class="">I think the code works as expected within a leap second, at the expense of an ERFA warning that you would need to catch:</div><div class=""><br class=""></div><div class="">In [2]: dts = [0, 0.5, 1.0, 1.5, 1.99, 2.0, 2.5, 3.0] * u.s</div>In [3]: dates_utc = Time(Time('2015-06-30 23:59:59') + dts, scale='utc')<br class="">In [4]: dates_tai = Time(dates_utc.iso, scale='tai')<br class="">WARNING: ErfaWarning: ERFA function "dtf2d" yielded 3 of "time is after end of day (Note 5)" [astropy._erfa.core]<br class="">In [5]: for date_utc, date_tai in zip(dates_utc, dates_tai):<br class="">   ...:     print(f'{date_utc} {(date_utc - date_tai).sec:.2f}')<br class="">   ...:     <br class="">2015-06-30 23:59:59.000 35.00<br class="">2015-06-30 23:59:59.500 35.00<br class="">2015-06-30 23:59:60.000 35.00<br class="">2015-06-30 23:59:60.500 35.00<br class="">2015-06-30 23:59:60.990 35.00<br class="">2015-07-01 00:00:00.000 36.00<br class="">2015-07-01 00:00:00.500 36.00<br class="">2015-07-01 00:00:01.000 36.00<br class=""><div class=""> <br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;" class=""><div class=""><br class=""></div><div class="">My code didn’t work at leap second either, but this code does:</div><div class=""><br class=""></div><div class=""><div class="">def tai_from_utc(utc):</div><div class="">    """Return TAI in unix seconds, given UTC in unix seconds.</div><div class="">    """</div><div class="">    astropy_utc = astropy.time.Time(utc, scale="utc", format="unix")</div><div class="">    dt_utc = astropy_utc.utc.to_datetime()</div><div class="">    dt_tai = astropy_utc.tai.to_datetime()</div><div class="">    tai_minus_utc = (dt_tai - dt_utc).total_seconds()</div><div class="">    return utc + tai_minus_utc</div></div></div></blockquote><div class=""><br class=""></div><div class="">On this, I would caution against using the astropy unix format for calculations where the details matter.  From the <a href="https://docs.astropy.org/en/stable/api/astropy.time.TimeUnix.html#astropy.time.TimeUnix" class="">TimeUnix API docs</a>:</div><br class=""><i class="">NOTE: this quantity is not exactly unix time and differs from the strict POSIX definition by up to 1 second on days with a leap second. POSIX unix time actually jumps backward by 1 second at midnight on leap second days while this class value is monotonically increasing at 86400 seconds per UTC day.</i><br class=""></div></div></div></blockquote><div><br class=""></div><div>I had missed that warning. Ouch!</div><div><br class=""></div><div>I think I have been approaching this the wrong way. We are representing timestamps in TAI unix seconds. I have two cases:</div><div><br class=""></div><div>1) Generate a TAI unix timestamp using the current time.</div><div><br class=""></div><div>I really want to get this one right.</div><div><br class=""></div><div>Originally I had hoped to use `Time.now().tai.unix`. Unfortunately that gives UTC, not TAI.</div><div><br class=""></div><div>My fallback was `tai_from_utc(ttime.time()) but this is looking even worse, since it’s not completely clear what time.time() will return near the leap second (at least based on the wikipedia article on unix timestamps).</div><div><br class=""></div><div><div>The wikipedia article on unix timestamps points out that the POSIX standard specifies one behavior for system time, but that systems that use NTP typically use a different standard (though one that includes useful flags). We’ll be using PTP or NTP. Unfortunately it may not be possible to use the time, datetime, and/or astropy.time packages as none of them appear to pay attention to those flags.</div><div class=""><br class=""></div></div><div>2) Convert a normal unix timestamp (as a float, any other information such as leap seconds flags is gone) to a TAI unix timestamp.</div><div><br class=""></div><div>In this case we could probably live with a 1 second error at or near a leap second because the information is only used to measure delays in our messaging system (DDS). But if I can get it right, so much the better.</div><div><br class=""></div><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_quote">I'm not sure about your test case, but the Python `datetime` does not support leap seconds.  I got this exception trying to run your code within a leap second, but maybe I did something differently:<br class=""><div class=""><br class=""></div><div class="">ValueError: Time (array(2015, dtype=int32), array(6, dtype=int32), array(30, dtype=int32), array(23, dtype=int32), array(59, dtype=int32), array(60, dtype=int32), array(0, dtype=int32)) is within a leap second but datetime does not support leap seconds<br class=""></div></div></div></blockquote><div><br class=""></div>That is very helpful. My test was missing “fraction of a second before seconds=60”. With that I get the same error. Of course I can subtract a second from the two times when that error occurs, but it doesn’t help with the fundamental issues.</div><div><br class=""></div><div>Regards,</div><div><br class=""></div><div>Russell</div><div><br class=""></div></body></html>