Chandra-specific astropy Time class

The cxotime package provides a CxoTime class which provides Chandra-specific functionality while deriving from the Time class of the astropytime package. The astropytime package provides robust 128-bit time representation, arithmetic, and comparisons.

The Chandra-specific time formats which are added to the astropy Time class are shown in the table below. Like DateTime, the CxoTime class default is to interpret any numerical values as secs (aka cxcsec in the native Time class).

Format

Description

System

secs

Seconds since 1998-01-01T00:00:00 (TT)

utc

date

YYYY:DDD:hh:mm:ss.ss..

utc

frac_year

YYYY.ffffff = date as a floating point year

utc

greta

YYYYDDD.hhmmsssss (string)

utc

maude

YYYYDDDhhmmsssss (integer)

utc

The standard built-in Time formats that are available in CxoTime are:

Format

Example

byear

1950.0

byear_str

‘B1950.0’

cxcsec

63072064.184

datetime

datetime(2000, 1, 2, 12, 0, 0)

decimalyear

2000.45

fits

‘2000-01-01T00:00:00.000(TAI)’

gps

630720013.0

iso

‘2000-01-01 00:00:00.000’

isot

‘2000-01-01T00:00:00.000’

jd

2451544.5

jyear

2000.0

jyear_str

‘J2000.0’

mjd

51544.0

plot_date

730120.0003703703

unix

946684800.0

yday

2000:001:00:00:00.000

Basic initialization

>>> from cxotime import CxoTime
>>> t = CxoTime(100.0)
>>> t.date
'1998:001:00:00:36.816'
>>> t.format
'secs'
>>> t.scale
'utc'

>>> import astropy.units as u
>>> t2 = t + [1, 2] * u.day + [10, 20] * u.s
>>> t2.date
array(['1998:002:00:00:46.816', '1998:003:00:00:56.816'], dtype='<U21')

>>> t = CxoTime([['1998:001:00:00:01.000', '1998:001:00:00:02.000'],
                 ['1998:001:00:00:03.000', '1998:001:00:00:04.000']])
>>> t.secs
array([[ 64.184,  65.184],
       [ 66.184,  67.184]])

>>> t.format
'date'

Guessing and specifying the format

Generally speaking CxoTime will successfully guess the format for string-based times. However this requires some time, so if you know the format in advance then it is recommended to provide this via the format argument.

>>> t = CxoTime('2020001223344555', format='maude')
>>> t.date
'2020:001:22:33:44.555'

Fast conversion between formats

Converting between time formats (e.g. from CXC seconds to Year Day-of-Year) is easily done with the CxoTime class, but this involves some overhead and is relatively slow for scalar values or small arrays (less than around 100 elements). For applications where this conversion time ends up being significant, the cxotime package provides a different interface that is typically at least 10x faster for scalar values or small arrays.

For fast conversion of an input date or dates to a different format there are two options that are described in the next two sections.

convert_time_format

The first option is a generalized time format conversion function convert_time_format() that can be used to convert between any of the supported fast formats:

  • secs: CXC seconds

  • date: Year Day-of-Year

  • greta: GRETA format (input can be string, float or int)

  • maude: MAUDE format (input can be string or int)

  • jd: Julian Day (requires fmt_in=”jd” to identity this format)

For example:

>>> from cxotime import convert_time_format
>>> convert_time_format("2022:001:00:00:00.123", "greta")
'2022001.000000123'
>>> convert_time_format(100.123, "date")
'1998:001:00:00:36.939'
>>> convert_time_format(2459580.5, "date", fmt_in="jd")
'2022:001:00:00:00.000'

Note that this function can be used to convert between any of the supported CxoTime formats, but it will internally use a CxoTime object so the performance will not be improved. For example:

>>> convert_time_format(2022.123, fmt_out="date", fmt_in="frac_year")
'2022:045:21:28:48.000'

# Exactly equivalent to:
>>> CxoTime(2022.123, format="frac_year").date
'2022:045:21:28:48.000'

Convenience functions like secs2date

For historical compatibility and for succinct code, direct conversion between any two of the “fast” formats is also available via convenience functions. These have the name <fmt_in>2<fmt_out> where fmt_in and fmt_out are the input and output formats. Examples include date2secs(), secs2greta(), and greta2jd().

::
>>> from cxotime import secs2greta
>>> secs2greta([100, 1000])
array(['1998001.000036816', '1998001.001536816'], dtype='<U17')

CxoTime.NOW sentinel

The CxoTime class has a special sentinel value CxoTime.NOW which can be used to specify the current time. This is useful for example when defining a function that has accepts a CxoTime-like argument that defaults to the current time.

Note

Prior to introduction of CxoTime.NOW, the standard idiom was to specify None as the argument default to indicate the current time. This is still supported but is strongly discouraged for new code.

For example:

>>> from cxotime import CxoTime
>>> def my_func(stop=CxoTime.NOW):
...     stop = CxoTime(stop)
...     print(stop)
...
>>> my_func()
2024:006:11:37:41.930

This can also be used in a dataclass to specify an attribute that is optional and defaults to the current time when the object is created:

>>> import time
>>> from dataclasses import dataclass
>>> from cxotime import CxoTime, CxoTimeDescriptor
>>> @dataclass
... class MyData:
...     start: CxoTime = CxoTimeDescriptor(required=True)
...     stop: CxoTime = CxoTimeDescriptor(default=CxoTime.NOW)
...
>>> obj1 = MyData("2022:001")
>>> print(obj1.start)
2022:001:00:00:00.000
>>> time.sleep(2)
>>> obj2 = MyData("2022:001")
>>> dt = obj2.stop - obj1.stop
>>> round(dt.sec, 2)
2.0

Compatibility with DateTime

The key differences between CxoTime and DateTime are:

  • In CxoTime the date ‘2000:001’ is ‘2000:001:00:00:00’ instead of ‘2000:001:12:00:00’ in DateTime (prior to version 4.0). In most cases this interpretation is more rational and expected.

  • In CxoTime the date ‘2001-01-01T00:00:00’ is UTC by default, while in DateTime that is interpreted as TT by default. This is triggered by the T in the middle. A date like ‘2001-01-01 00:00:00’ defaults to UTC in both CxoTime and DateTime.

  • In CxoTime the difference of two dates is a TimeDelta object which is transformable to any time units. In DateTime the difference of two dates is a floating point value in days.

  • Conversely, starting with CxoTime one can add or subtract a TimeDelta or any quantity with time units.

API docs

Cxotime

class cxotime.cxotime.CxoTime(*args, **kwargs)[source]

Time class for Chandra analysis that is based on astropy.time.Time.

The CXO-specific time formats which are added to the astropy Time class are shown in the table below. Like DateTime, the CxoTime class default is to interpret any numerical values as secs (aka cxcsec in the native Time class).

All of these formats use the UTC scale.

Format

Description

secs

Seconds since 1998-01-01T00:00:00 (TT) (float)

date

YYYY:DDD:hh:mm:ss.ss.. (string)

frac_year

YYYY.ffffff = date as a floating point year

greta

YYYYDDD.hhmmsss (string)

muade

YYYDDDhhmmsss (integer)

Important differences:

  • In CxoTime the date ‘2000:001’ is ‘2000:001:00:00:00’ instead of ‘2000:001:12:00:00’ in DateTime. In most cases this interpretation is more rational and expected.

  • In CxoTime the date ‘2001-01-01T00:00:00’ is UTC by default, while in DateTime that is interpreted as TT by default. This is triggered by the T in the middle. A date like ‘2001-01-01 00:00:00’ defaults to UTC in both CxoTime and DateTime.

The standard built-in Time formats that are available in CxoTime are:

Format

Example

byear

1950.0

byear_str

‘B1950.0’

cxcsec

63072064.184

datetime

datetime(2000, 1, 2, 12, 0, 0)

decimalyear

2000.45

fits

‘2000-01-01T00:00:00.000(TAI)’

gps

630720013.0

iso

‘2000-01-01 00:00:00.000’

isot

‘2000-01-01T00:00:00.000’

jd

2451544.5

jyear

2000.0

jyear_str

‘J2000.0’

mjd

51544.0

plot_date

730120.0003703703

unix

946684800.0

yday

2000:001:00:00:00.000

get_conversions()[source]

Get a dict of conversions to a standard set of formats.

Example:

>>> from cxotime import CxoTime
>>> t = CxoTime('2010:001:00:00:00')
>>> t.get_conversions()
{'local': '2009 Thu Dec 31 07:00:00 PM EST',
'iso_local': '2009-12-31T19:00:00-05:00',
'date': '2010:001:00:00:00.000',
'cxcsec': 378691266.184,
'decimalyear': 2010.0,
'iso': '2010-01-01 00:00:00.000',
'unix': 1262304000.0}
classmethod linspace(start: CxoTime | str | float | int | ndarray | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | complex | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None, stop: CxoTime | str | float | int | ndarray | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | complex | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None, num: int | None = None, step_max: Quantity | None = None)[source]

Get a uniform time series that covers the given time range.

Output times either divide the time range into num intervals or are uniformly spaced by up to step_max, and cover the time range from start to stop.

Note that returned intervals may be larger than step_max by floating point error. If calling code requires that all the intervals be less than a value, step_max should be set to a value at least slightly smaller than the desired maximum value.

Parameters:
startCxoTimeLike

Start time of the time range.

stopCxoTimeLike

Stop time of the time range.

numint | None

Number of time bins.

step_maxu.Quantity (timelike)

Maximum time interval step. Should be positive nonzero.

Returns:
CxoTime

CxoTime with time bin edges for each interval.

classmethod now()[source]

Creates a new object corresponding to the instant in time this method is called.

Note

“Now” is determined using the ~datetime.datetime.now function, so its accuracy and precision is determined by that function. Generally that means it is set by the accuracy of your system clock. The timezone is set to UTC.

Returns:
nowtimeTime

A new Time object (or a subclass of Time if this is called from such a subclass) at the current time.

print_conversions(file=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)[source]

Print a table of conversions to a standard set of formats.

Example:

>>> from cxotime import CxoTime
>>> t = CxoTime('2010:001:00:00:00')
>>> t.print_conversions()
local       2009 Thu Dec 31 07:00:00 PM EST
iso_local   2009-12-31T19:00:00-05:00
date        2010:001:00:00:00.000
cxcsec      378691266.184
decimalyear 2010.00000
iso         2010-01-01 00:00:00.000
unix        1262304000.000
Parameters:

file – file-like, optional File-like object to write output (default=sys.stdout).

class cxotime.cxotime.CxoTimeDescriptor(*, default=None, required=False, cls=None)[source]

Descriptor for an attribute that is CxoTime (in date format) or None if not set.

This allows setting the attribute with any CxoTimeLike value.

Note that setting this descriptor to None will set the attribute to None, which is different than CxoTime(None) which returns the current time.

To set an attribute to the current time, use CxoTime.NOW, either as the default or when setting the attribute.

Parameters:
defaultCxoTimeLike, optional

Default value for the attribute which is provide to the CxoTime constructor. If not specified or None, the default for the attribute is None.

requiredbool, optional

If True, the attribute is required to be set explicitly when the object is created. If False the default value is used if the attribute is not set.

Examples

>>> from dataclasses import dataclass
>>> from cxotime import CxoTime, CxoTimeDescriptor
>>> @dataclass
... class MyClass:
...     start: CxoTime | None = CxoTimeDescriptor()
...     stop: CxoTime = CxoTimeDescriptor(default=CxoTime.NOW)
...
>>> obj = MyClass("2023:100")  # Example run at 2024:006:12:02:35
>>> obj.start
<CxoTime object: scale='utc' format='date' value=2023:100:00:00:00.000>
>>> obj.stop
<CxoTime object: scale='utc' format='date' value=2024:006:12:02:35.000>
cls

alias of CxoTime

Converters

cxotime.convert.convert_time_format(val, fmt_out, *, fmt_in=None)[source]

Convert a time to a different format.

Parameters:
valCxoTimeLike

Time value

fmt_outstr

Output format

fmt_instr

Input format (default is to guess)

Returns:
val_outstr

Time string in output format

cxotime.convert.date2greta(date)

Convert Date (Year, day-of-year, time) to GRETA date.

This is equivalent to CxoTime(date, format='date').greta but potentially 10x faster.

Format in: - YYYY:DDD:HH:MM:SS.sss - YYYY:DDD:HH:MM:SS - YYYY:DDD:HH:MM - YYYY:DDD Format out: YYYYDDD.HHMMSSsss (str)

Parameters:
datestr, bytes, float, list, ndarray

Date (Year, day-of-year, time)

Returns:
datestr, np.ndarray[str]

GRETA date

cxotime.convert.date2jd(date)

Convert Date (Year, day-of-year, time) to Julian Date.

This is equivalent to CxoTime(date, format='date').jd but potentially 10x faster.

Format in: - YYYY:DDD:HH:MM:SS.sss - YYYY:DDD:HH:MM:SS - YYYY:DDD:HH:MM - YYYY:DDD Format out: Julian Date (numeric)

Parameters:
datestr, bytes, float, list, ndarray

Date (Year, day-of-year, time)

Returns:
jdfloat, ndarray[float]

Julian Date

cxotime.convert.date2maude(date)

Convert Date (Year, day-of-year, time) to MAUDE date.

This is equivalent to CxoTime(date, format='date').maude but potentially 10x faster.

Format in: - YYYY:DDD:HH:MM:SS.sss - YYYY:DDD:HH:MM:SS - YYYY:DDD:HH:MM - YYYY:DDD Format out: YYYYDDD.HHMMSSsss (int)

Parameters:
datestr, bytes, float, list, ndarray

Date (Year, day-of-year, time)

Returns:
dateint, ndarray[int]

MAUDE date

cxotime.convert.date2secs(date)

Convert Date (Year, day-of-year, time) to CXC seconds.

This is equivalent to CxoTime(date, format='date').secs but potentially 10x faster.

Format in: - YYYY:DDD:HH:MM:SS.sss - YYYY:DDD:HH:MM:SS - YYYY:DDD:HH:MM - YYYY:DDD Format out: CXC seconds (numeric)

Parameters:
datestr, bytes, float, list, ndarray

Date (Year, day-of-year, time)

Returns:
timefloat, ndarray[float]

CXC seconds

cxotime.convert.greta2date(date)

Convert GRETA date to Date (Year, day-of-year, time).

This is equivalent to CxoTime(date, format='greta').date but potentially 10x faster.

Format in: YYYYDDD.HHMMSSsss (str or float) Format out: YYYY:DDD:HH:MM:SS.sss

Parameters:
datestr, bytes, float, list, np.ndarray

GRETA date

Returns:
datestr, ndarray[str]

Date (Year, day-of-year, time)

cxotime.convert.greta2jd(date)

Convert GRETA date to Julian Date.

This is equivalent to CxoTime(date, format='greta').jd but potentially 10x faster.

Format in: YYYYDDD.HHMMSSsss (str or float) Format out: Julian Date (numeric)

Parameters:
datestr, bytes, float, list, np.ndarray

GRETA date

Returns:
jdfloat, ndarray[float]

Julian Date

cxotime.convert.greta2maude(date)

Convert GRETA date to MAUDE date.

This is equivalent to CxoTime(date, format='greta').maude but potentially 10x faster.

Format in: YYYYDDD.HHMMSSsss (str or float) Format out: YYYYDDD.HHMMSSsss (int)

Parameters:
datestr, bytes, float, list, np.ndarray

GRETA date

Returns:
dateint, ndarray[int]

MAUDE date

cxotime.convert.greta2secs(date)

Convert GRETA date to CXC seconds.

This is equivalent to CxoTime(date, format='greta').secs but potentially 10x faster.

Format in: YYYYDDD.HHMMSSsss (str or float) Format out: CXC seconds (numeric)

Parameters:
datestr, bytes, float, list, np.ndarray

GRETA date

Returns:
timefloat, ndarray[float]

CXC seconds

cxotime.convert.jd2date(jd)

Convert Julian Date to Date (Year, day-of-year, time).

This is equivalent to CxoTime(jd, format='jd').date but potentially 10x faster.

Format in: Julian Date (numeric) Format out: YYYY:DDD:HH:MM:SS.sss

Parameters:
jdfloat, int, list, ndarray

Julian Date

Returns:
datestr, ndarray[str]

Date (Year, day-of-year, time)

cxotime.convert.jd2greta(jd)

Convert Julian Date to GRETA date.

This is equivalent to CxoTime(jd, format='jd').greta but potentially 10x faster.

Format in: Julian Date (numeric) Format out: YYYYDDD.HHMMSSsss (str)

Parameters:
jdfloat, int, list, ndarray

Julian Date

Returns:
datestr, np.ndarray[str]

GRETA date

cxotime.convert.jd2maude(jd)

Convert Julian Date to MAUDE date.

This is equivalent to CxoTime(jd, format='jd').maude but potentially 10x faster.

Format in: Julian Date (numeric) Format out: YYYYDDD.HHMMSSsss (int)

Parameters:
jdfloat, int, list, ndarray

Julian Date

Returns:
dateint, ndarray[int]

MAUDE date

cxotime.convert.jd2secs(jd)

Convert Julian Date to CXC seconds.

This is equivalent to CxoTime(jd, format='jd').secs but potentially 10x faster.

Format in: Julian Date (numeric) Format out: CXC seconds (numeric)

Parameters:
jdfloat, int, list, ndarray

Julian Date

Returns:
timefloat, ndarray[float]

CXC seconds

cxotime.convert.maude2date(date)

Convert MAUDE date to Date (Year, day-of-year, time).

This is equivalent to CxoTime(date, format='maude').date but potentially 10x faster.

Format in: YYYYDDDHHMMSSsss (str or int) Format out: YYYY:DDD:HH:MM:SS.sss

Parameters:
datestr, bytes, int, list, ndarray

MAUDE date

Returns:
datestr, ndarray[str]

Date (Year, day-of-year, time)

cxotime.convert.maude2greta(date)

Convert MAUDE date to GRETA date.

This is equivalent to CxoTime(date, format='maude').greta but potentially 10x faster.

Format in: YYYYDDDHHMMSSsss (str or int) Format out: YYYYDDD.HHMMSSsss (str)

Parameters:
datestr, bytes, int, list, ndarray

MAUDE date

Returns:
datestr, np.ndarray[str]

GRETA date

cxotime.convert.maude2jd(date)

Convert MAUDE date to Julian Date.

This is equivalent to CxoTime(date, format='maude').jd but potentially 10x faster.

Format in: YYYYDDDHHMMSSsss (str or int) Format out: Julian Date (numeric)

Parameters:
datestr, bytes, int, list, ndarray

MAUDE date

Returns:
jdfloat, ndarray[float]

Julian Date

cxotime.convert.maude2secs(date)

Convert MAUDE date to CXC seconds.

This is equivalent to CxoTime(date, format='maude').secs but potentially 10x faster.

Format in: YYYYDDDHHMMSSsss (str or int) Format out: CXC seconds (numeric)

Parameters:
datestr, bytes, int, list, ndarray

MAUDE date

Returns:
timefloat, ndarray[float]

CXC seconds

cxotime.convert.print_time_conversions()[source]

Interface to entry_point script cxotime to print time conversions

cxotime.convert.secs2date(time)

Convert CXC seconds to Date (Year, day-of-year, time).

This is equivalent to CxoTime(time, format='secs').date but potentially 10x faster.

Format in: CXC seconds (numeric) Format out: YYYY:DDD:HH:MM:SS.sss

Parameters:
timefloat, int, list, ndarray

CXC seconds

Returns:
datestr, ndarray[str]

Date (Year, day-of-year, time)

cxotime.convert.secs2greta(time)

Convert CXC seconds to GRETA date.

This is equivalent to CxoTime(time, format='secs').greta but potentially 10x faster.

Format in: CXC seconds (numeric) Format out: YYYYDDD.HHMMSSsss (str)

Parameters:
timefloat, int, list, ndarray

CXC seconds

Returns:
datestr, np.ndarray[str]

GRETA date

cxotime.convert.secs2jd(time)

Convert CXC seconds to Julian Date.

This is equivalent to CxoTime(time, format='secs').jd but potentially 10x faster.

Format in: CXC seconds (numeric) Format out: Julian Date (numeric)

Parameters:
timefloat, int, list, ndarray

CXC seconds

Returns:
jdfloat, ndarray[float]

Julian Date

cxotime.convert.secs2maude(time)

Convert CXC seconds to MAUDE date.

This is equivalent to CxoTime(time, format='secs').maude but potentially 10x faster.

Format in: CXC seconds (numeric) Format out: YYYYDDD.HHMMSSsss (int)

Parameters:
timefloat, int, list, ndarray

CXC seconds

Returns:
dateint, ndarray[int]

MAUDE date