Skip to content

Conversation

@lpsinger
Copy link
Contributor

@lpsinger lpsinger commented Feb 9, 2013

astropy.time.TimeDelta inherits from astropy.units.Quantity, so that it
gains the .to() method and can be converted to seconds, hours, minutes,
etc.

Now you can do this:

>>> from astropy import time, units
>>> t1 = time.Time('2013-01-01T05:44:00', scale='utc', format='isot')
>>> t2 = time.Time('2013-01-01T06:45:00', scale='utc', format='isot')
>>> print (t2 - t1).to(units.min)
61.0 min

astropy.time.TimeDelta inherits from astropy.units.Quantity, so that it
gains the .to() method and can be converted to seconds, hours, minutes,
etc.

Now you can do this:

    >>> from astropy import time, units
    >>> t1 = time.Time('2013-01-01T05:44:00', scale='utc', format='isot')
    >>> t2 = time.Time('2013-01-01T06:45:00', scale='utc', format='isot')
    >>> print (t2 - t1).to(units.min)
    61.0 min
@eteq
Copy link
Member

eteq commented Feb 11, 2013

This seems like a good idea to me, unless @taldcroft has some issue with it. I could see a possible concern here with the unit framework conflicting with the intended API of a time object, but in the case of a delta it seems safe enough to me.

@lpsinger, could you add a test or two to astropy/time/tests/test_delta.py?

@taldcroft
Copy link
Member

@eteq @lpsinger - sorry I haven't yet had a chance to play around with this. My immediate question shared with @eteq is API collision since this mixes two relatively complicated classes in a way that wasn't in the design of either. But maybe it just works. The idea of adding a suite of tests is good.

A lighter-weight option would just be adding a to() method to TimeDelta to bring in a subset of Quantity functionality, though that might end up being confusing. Not sure...

@lpsinger
Copy link
Contributor Author

TimeDelta and Quantity both have methods with the following names:

>>> from astropy.time import TimeDelta
>>> from astropy.units import Quantity
>>> from pprint import pprint
>>> pprint(sorted(list(set(dir(TimeDelta)) & set(dir(Quantity)))))
['__add__',
 '__class__',
 '__delattr__',
 '__dict__',
 '__doc__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__len__',
 '__module__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__sub__',
 '__subclasshook__',
 '__weakref__',
 'copy']

I think that this is fine. The main problem that I see is that Quantity is mutable with setters as well as getters for its value and unit properties, whereas TimeDelta (and Time, too, for that matter) is immutable. The value and units setters will fail:

>>> from astropy import time, units
>>> t1 = time.Time('2013-01-01T05:44:00', scale='utc', format='isot')
>>> t2 = time.Time('2013-01-01T06:45:00', scale='utc', format='isot')
>>> dt = t2 - t1
>>> dt.value
3659.9999999999964
>>> dt.value = 1
ERROR: AttributeError: can't set attribute [astropy.units.quantity]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/lady3jane/local/lib/python2.7/site-packages/astropy/units/quantity.py", line 126, in value
    self._value = _validate_value(obj)
AttributeError: can't set attribute

See issue #761, though.

@taldcroft
Copy link
Member

Some other thoughts on this idea:

  • As originally proposed one should be able to convert to different units with to(). BTW, the
    intent with DeltaTime is to provide built-in min, hour, and dhms (days hours minutes secs) formats
    that would do the same thing.
  • One should be able to do Time +/- Quantity when the quantity has units which are equivalent to
    seconds. Basically this would cast the Quantity as a DeltaTime.
  • Likewise adding or subtracting Quantity and DeltaTime (regardless of argument order) should give a DeltaTime.
    Since DeltaTime is a specialized high-precision delta time container,
    it should take precedence in operations. Also I think addition should be commutative wrt to output type.
    I'm not sure about this, but I think that if DeltaTime inherits from Quantity then
    transparently enforcing this rule will require some changes in the Quantity class.
  • Multiplying or dividing a DeltaTime by a Quantity should result in a Quantity.
  • Multiplying or dividing a DeltaTime by a scalar should result in a DeltaTime.

I see the motivation for inheriting from Quantity, but it may be possible accomplish everything discussed so far without inheriting and just providing limited transformation capabilities. I'm worried about collisions or unexpected interactions in future development, as well as user (and developer) confusion about the mixture. Note that there are a few "near-misses" in attributes. TimeDelta has val, and vals while Quantity provides value. Likewise there is isscalar and is_scalar (both of which should probably be hidden anyway).

After inheriting from Quantity a TimeDelta object has si and cgs properties and the decompose method, none of which are needed in this case.

So one possibility is to make sure all the combination rules above work, don't inherit from Quantity and then just provide a to() method. I'm just thinking out loud and not entirely convinced this is the right approach.

@eteq
Copy link
Member

eteq commented Feb 12, 2013

Hmm, the "near-misses" particular worry me. Although perhaps that means we should be doing things consistently in the first place... but that may be a separate issue (I'll open one). But even if that's fixed, I think I agree with @taldcroft that it's showing a potential danger/confusion from subclassing. There's also the issue of accidentally hurting precision is also higher because of the jd1/jd2 internal representation in Time is higher resolution than the single-object Quantity

An alternative to a direct to to consider: the accessors in Time and DeltaTime (including mjd and so on) could return Quantity objects instead of raw floats/arrays as they do now. Obviously that won't work for things like dhms that respond with strings, but everything that currently gives out a number could be switched to quantity. But maybe that degrades the flexibility? The to creating a new Quantity also seems like a reasonable solution, but I'm also thinking out loud.

@mhvk
Copy link
Contributor

mhvk commented Aug 18, 2013

Found this while looking through old issues. I think @taldcroft's summary is good, and especially Time +/- Quantity should work. The question is how to approach it. Simplest is to check for addition/subtraction whether other is a quantities with units of time [1], but possibly one should instead try instantiation of TimeDelta with a quantity (which should really work for time-like quantities, but then perhaps it should be more general: should one be able to do Time(q, format='gps') if q is time-like?)

Note that it has become somewhat more tricky to emulate the new quantity, with its loads of short-cut conversions (q.second, q.day, q.gigayear, etc.). Still, it might be useful just to have something like what I did in [1]:

    def to(self, *args, **kwargs):
        from astropy.units import day
        return (self._shaped_like_input(self._time.jd1 + self._time.jd2) * day
                ).to(*args, **kwargs)

[1] Trial implementation at https://github.com/mhvk/astropy/tree/time-and-timelike-quantities
(too quick & dirty to turn into a PR...)

@taldcroft
Copy link
Member

Superceded by #1431.

@taldcroft taldcroft closed this Sep 20, 2013
@embray
Copy link
Member

embray commented Sep 23, 2013

Since this was superseded not implemented as originally described I'm going to remove the milestone. In general we should remove milestones from any PRs that are never merged or implemented as-is to avoid confusion.

@taldcroft
Copy link
Member

@embray - copy.

mhvk added a commit to mhvk/astropy that referenced this pull request Oct 15, 2013
taldcroft added a commit that referenced this pull request Oct 15, 2013
Allow Time input/interaction/output with Quantities (closes #751)
@lpsinger lpsinger deleted the unitful_time_delta branch June 20, 2014 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants