If I try to do a round-trip conversion from UTC seconds to an Epoch and back, I expect it to be perfect at every point except in the case of a deleted leap second (where the skipped UTC second count wouldn't be able to round-trip correctly). What I actually get is a delta of +/-1 second leading up to the leap second insertion/removal point. See below for an example using toy leap second updates.
Insert leap second @ 100, from +3 to +4
UTC -> TAI -> UTC
96 -> 99 -> 96, delta = 0
97 -> 100 -> 96, delta = -1
98 -> 101 -> 97, delta = -1
99 -> 102 -> 98, delta = -1
-> 103 -> 99, delta = 0
100 -> 104 -> 100, delta = 0
101 -> 105 -> 101, delta = 0
102 -> 106 -> 102, delta = 0
Delete leap second @ 100, from +3 to +2
UTC -> TAI -> UTC
96 -> 99 -> 96, delta = 0
97 -> 100 -> 98, delta = 1
98 -> 101 -> 99, delta = 1
99 -> 102 -> 100, delta = 1
100 -> 102 -> 100, delta = 0
101 -> 103 -> 101, delta = 0
102 -> 104 -> 102, delta = 0
The reason for this LeapSecondProvider is used the same way for conversion both from UTC to TAI, and from TAI to UTC. The IERS leap second table lists times in UTC seconds, so the conversion to TAI is fine (and is exactly what IERS made the table for). To go in the other direction, we'd need to speculatively subtract the offset first and then examine the leap second table's seconds count.
I'm not sure what the preferred fix is here. Epoch has several functions for getting the number of leap seconds for the epoch, so it seems like the preference is for leap seconds tables to actually list themselves with TAI times instead of UTC times, and to go through the "offset-then-compare" leap second calculation when going from UTC to TAI. That would require all LeapSecondProvider implementers to change though.
The alternate would be to keep the leap second implementers the same, and to change the leap_seconds_with function to apply the offset before doing the comparison. In either case, there would need to be two functions: one to apply leap seconds to TAI, and one to remove leap seconds from UTC.
Also, not directly related to the problem, but is there a way to avoid creating a new leap second table every time I want to use one? It looks like the current implementations will, at minimum, need to clone or create the entire table every time the table is needed. A naive use of the LeapSecondsFile would cause the file to be re-parsed every time there's a leap second calculation. Maybe there's a good reason for the trait, but it does seem like a lot of needlessly duplicated work.
Example Code with the proposed function fix: hifitime_play.zip
If I try to do a round-trip conversion from UTC seconds to an
Epochand back, I expect it to be perfect at every point except in the case of a deleted leap second (where the skipped UTC second count wouldn't be able to round-trip correctly). What I actually get is a delta of +/-1 second leading up to the leap second insertion/removal point. See below for an example using toy leap second updates.The reason for this
LeapSecondProvideris used the same way for conversion both from UTC to TAI, and from TAI to UTC. The IERS leap second table lists times in UTC seconds, so the conversion to TAI is fine (and is exactly what IERS made the table for). To go in the other direction, we'd need to speculatively subtract the offset first and then examine the leap second table's seconds count.I'm not sure what the preferred fix is here.
Epochhas several functions for getting the number of leap seconds for the epoch, so it seems like the preference is for leap seconds tables to actually list themselves with TAI times instead of UTC times, and to go through the "offset-then-compare" leap second calculation when going from UTC to TAI. That would require allLeapSecondProviderimplementers to change though.The alternate would be to keep the leap second implementers the same, and to change the
leap_seconds_withfunction to apply the offset before doing the comparison. In either case, there would need to be two functions: one to apply leap seconds to TAI, and one to remove leap seconds from UTC.Also, not directly related to the problem, but is there a way to avoid creating a new leap second table every time I want to use one? It looks like the current implementations will, at minimum, need to clone or create the entire table every time the table is needed. A naive use of the
LeapSecondsFilewould cause the file to be re-parsed every time there's a leap second calculation. Maybe there's a good reason for the trait, but it does seem like a lot of needlessly duplicated work.Example Code with the proposed function fix: hifitime_play.zip