Skip to content

TimeDelta only allows TAI #1931

Closed
Closed

Description

@demorest

Hi,

It seems TimeDelta objects can currently only use TAI timescale. This is kind of annoying if one wants to do something like get the difference between two Times in TDB (or any other non-TAI timescale). It also leads to some (IMO) counter-intuitive and potentially confusing results, since all Times are silently converted to TAI when their difference is taken:

In [1]: import astropy.time as time

In [2]: t0 = time.Time(55000,0.123456789,format='mjd',scale='utc')

In [3]: t1 = time.Time(55100,0.987654321,format='mjd',scale='utc')

In [4]: t1 - t0
Out[4]: <TimeDelta object: scale='tai' format='jd' value=100.864197532>

In [5]: t1.tdb - t0.tdb
Out[5]: <TimeDelta object: scale='tai' format='jd' value=100.864197532>

In [6]: t1.tdb.value - t0.tdb.value
Out[6]: 100.86419750742789

In [7]: t1.tdb.value - t0.tdb.value - (t1.tdb-t0.tdb).value
Out[7]: -2.457211678574822e-08

Is there a rationale for only allowing TAI differences? Or are other scales just not implemented yet? It might be a good idea to raise an error/warning when two non-TAI times are differenced.

Cheers,
Paul

Activity

  1. taldcroft commented on Dec 28, 2013

    @taldcroft
    Member

    The rationale is that in at least some of the other time scales the length of the second (measured in SI seconds or atomic clock ticks) depends on the epoch. UT1 is an example. So a time delta of e.g. 86400.0 UT1 seconds is different in 1980 vs. 2013 and has no absolute meaning. Hence you cannot turn around and add that time delta back to another UT1 time. Likewise for UTC sometimes 1.0 jd is one SI second different than most other 1.0 jd. Astropy takes the approach of converting times to the TAI scale for which the length of the second is invariant with epoch.

    In your example above, I believe the difference you are seeing in Out[7] is a floating point error induced by using the value attribute which down-converts the 128-bit Time representation to 64-bits. You should never be using value if you care about full precision. Instead if you do all the arithmetic within Time the full 128-bits are used consistently and the answer is precisely 0.0 as expected (thank @mhvk for that):

    In [23]: t0 = Time(55000,0.123456789,format='mjd',scale='utc')
    In [24]: t1 = Time(55100,0.987654321,format='mjd',scale='utc')
    
    In [25]: dt_utc = t1 - t0
    In [26]: dt_tdb = t1.tdb - t0.tdb
    
    In [27]: dt_utc - dt_tdb
    Out[27]: <TimeDelta object: scale='tai' format='jd' value=0.0>
    
  2. mhvk commented on Dec 28, 2013

    @mhvk
    Contributor

    @demorest - I don't know the precise history (CC @taldcroft), but I think you're right that we should support time differences in any scale where they are well-defined (i.e., independent of location and epoch); I still get somewhat confused by the different time standards, but I think the well-defined time-scales are the following:

    1. Earth surface: tt, utc, tai: all differences should be the same as for tai.
    2. Geocentric, i.e., tcg, differences have constant factor relative to tai
    3. Barycentric, either tcb or tdb, differences have constant factor between tcb and tdb, but cannot be converted to tai or tcg without knowing location and epoch.
      So, I think there are four distinct TimeDelta scales: tai, tcg, tcb, and tdb, of which the former and latter pairs can be easily converted to each other, but it is not possible to convert between pairs.

    I think this is not difficult to implement in principle (either by adding one or three TimeDelta types), but we may need to think a little about what we allow. E.g., for adding a Time(..., scale='tai') to a TimeDelta(..., scale='tdb'), would one want to silently convert the time to tdb, add the time-delta, and then convert back to tai (consistent with what is done now for a tdb time and a by-definition tai time-difference)?

    @taldcroft - what do you think? I agree with your note above that one cannot support time differences for UT1, but the barycentric cases seem different.

  3. taldcroft commented on Dec 28, 2013

    @taldcroft
    Member

    OK thanks for the summary @mhvk, that sounds more or less reasonable. We just need to think about making this clean in the implementation and user interface.

  4. demorest commented on Dec 29, 2013

    @demorest
    Author

    @taldcroft - Sorry, I should have been more careful about the precision in my example. I certainly understand the precision issues, and the result in my original output line 7 is not due to this. It is several orders of magnitude larger (64-bit float MJDs have ~us precision, the line 7 value is ~ms). The difference is because t1.tdb - t0.tdb does not return the difference in TDB, as one would (reasonably I think) expect from the syntax. Instead it returns the difference between the two times converted to TAI. Here is the same example with better attention paid to precision:

    In [1]: import astropy.time as time
    
    In [2]: t0 = time.Time(55000,0.123456789,format='mjd',scale='utc')
    
    In [3]: t1 = time.Time(55100,0.987654321,format='mjd',scale='utc')
    
    In [4]: dt_utc_timedelta = t1 - t0
    
    In [5]: dt_utc_manual = (t1.jd1-t0.jd1) + (t1.jd2-t0.jd2)
    
    In [6]: dt_tdb_timedelta = t1.tdb - t0.tdb
    
    In [7]: dt_tdb_manual = (t1.tdb.jd1-t0.tdb.jd1) + (t1.tdb.jd2-t0.tdb.jd2)
    
    In [8]: dt_utc_timedelta.value - dt_utc_manual
    Out[8]: 0.0
    
    In [9]: dt_tdb_timedelta.value - dt_tdb_manual
    Out[9]: 2.4575214752076135e-08
    
    In [10]: dt_tdb_timedelta - dt_utc_timedelta
    Out[10]: <TimeDelta object: scale='tai' format='jd' value=0.0>
    
    In [11]: dt_tdb_manual - dt_utc_manual
    Out[11]: -2.4575214752076135e-08
    

    Anyways, I think you probably get the basic issues which is that sometimes we need a time difference computed in a scale other than TAI and the current interface makes one jump through hoops to get this.

    @mhvk - I think your suggestion is mostly good, except that automatically/silently converting between time scales based on what you think the user is trying to do sounds a bit dangerous to me. Why not just raise an exception if someone tries to add a TimeDelta to a Time that is not in a compatible scale?

    Thanks for your work on this!

  5. mhvk commented on Dec 29, 2013

    @mhvk
    Contributor

    @demorest - have a look at #1932; can you think of test cases that the class should pass? And, perhaps equally importantly, that it should fail on? (PRs to my branch very welcome!)

  6. added this to the Future milestone on May 9, 2014
  7. mhvk commented on Jul 11, 2014

    @mhvk
    Contributor

    TimeDelta scales other than TAI are now allowed (#1932), so closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions