diff --git a/pixi.lock b/pixi.lock index 0cf1c0d..5bac123 100644 --- a/pixi.lock +++ b/pixi.lock @@ -6168,7 +6168,7 @@ packages: - pypi: ./ name: timescale version: 0.1.0 - sha256: 6848dd3bbd16908a462e07186a11c01aae144ebf95918004baa9b7f40f061641 + sha256: 0e1de33f9f4acd8cd9b14772328653d4e8357c57a8993adc7c1f1c23dd8b5200 requires_dist: - lxml - numpy diff --git a/pyproject.toml b/pyproject.toml index 8509d6a..a34e85c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,7 +129,7 @@ cwd = "doc" description = "Create HTML documentation with sphinx" [tool.pixi.feature.dev.tasks.test] -args = [ "flags", { "arg" = "test", "default" = "." } ] +args = [ { "arg" = "flags", "default" = "" }, { "arg" = "test", "default" = "." } ] cmd = "pytest {{ flags }} {{ test }}" cwd = "test" description = "Run the pytest suite" diff --git a/test/test_time.py b/test/test_time.py index aad84ea..cd77b9b 100644 --- a/test/test_time.py +++ b/test/test_time.py @@ -160,7 +160,7 @@ def test_timescale(): assert np.all(ATLAS.MJD == 58119) assert np.all(ATLAS.tide == 9497) assert np.all(ATLAS.gps_week == 1982) - delta_time_epochs = (ATLAS.to_datetime() - atlas_sdp_epoch) + delta_time_epochs = (ATLAS.to_datetime(unit='us') - atlas_sdp_epoch) assert np.all(delta_time_epochs/np.timedelta64(1, 'ns') == 0) SHORTCUT = timescale.from_datetime(atlas_sdp_epoch) assert np.all(ATLAS.MJD == SHORTCUT.MJD) @@ -171,7 +171,7 @@ def test_timescale(): ATLAS = timescale.time.Timescale().from_deltatime(0, epoch=(2018,1,1)) assert np.all(ATLAS.MJD == 58119) assert np.all(ATLAS.tide == 9497) - delta_time_epochs = (ATLAS.to_datetime() - atlas_sdp_epoch) + delta_time_epochs = (ATLAS.to_datetime(unit='us') - atlas_sdp_epoch) assert np.all(delta_time_epochs/np.timedelta64(1, 'ns') == 0) SHORTCUT = timescale.from_deltatime(0, epoch=(2018,1,1)) assert np.all(ATLAS.MJD == SHORTCUT.MJD) @@ -185,7 +185,7 @@ def test_timescale(): # from MJD hourly array delta_time = np.arange(0, 365, 1.0/24.0) ATLAS = timescale.time.Timescale(MJD=58119 + delta_time) - delta_time_epochs = (ATLAS.to_datetime() - atlas_sdp_epoch) + delta_time_epochs = (ATLAS.to_datetime(unit='us') - atlas_sdp_epoch) assert np.allclose(delta_time_epochs/np.timedelta64(1, 'D'), delta_time) assert np.allclose(ATLAS.to_deltatime(epoch=atlas_sdp_epoch), delta_time) assert np.allclose(ATLAS.to_deltatime(epoch='2018-01-01'), delta_time) diff --git a/timescale/time.py b/timescale/time.py index dbe4311..e080a8c 100755 --- a/timescale/time.py +++ b/timescale/time.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" time.py -Written by Tyler Sutterley (08/2025) +Written by Tyler Sutterley (12/2025) Utilities for calculating time operations PYTHON DEPENDENCIES: @@ -16,6 +16,7 @@ utilities.py: download and management utilities for syncing files UPDATE HISTORY: + Updated 12/2025: allow conversion to datetime be in different units Updated 08/2025: add nominal years (365.25 days long) to Timescale class Updated 07/2025: verify Bulletin-A entries are not already in merged file add Besselian year conversion to Timescale class @@ -80,8 +81,11 @@ import timescale.utilities # conversion factors between time units and seconds -_to_sec = {'microseconds': 1e-6, 'microsecond': 1e-6, - 'microsec': 1e-6, 'microsecs': 1e-6, +_to_sec = {'nanoseconds': 1e-9, 'nanosecond': 1e-9, + 'nanosec': 1e-9, 'nanosecs': 1e-9, + 'nsec': 1e-9, 'nsecs': 1e-9, 'ns': 1e-9, + 'microseconds': 1e-6, 'microsecond': 1e-6, + 'microsec': 1e-6, 'microsecs': 1e-6, 'us': 1e-6, 'milliseconds': 1e-3, 'millisecond': 1e-3, 'millisec': 1e-3, 'millisecs': 1e-3, 'msec': 1e-3, 'msecs': 1e-3, 'ms': 1e-3, @@ -91,7 +95,8 @@ 'min': 60.0, 'mins': 60.0, 'hours': 3600.0, 'hour': 3600.0, 'hr': 3600.0, 'hrs': 3600.0, 'h': 3600.0, - 'day': 86400.0, 'days': 86400.0, 'd': 86400.0} + 'day': 86400.0, 'days': 86400.0, 'd': 86400.0, + 'D': 86400.0} # approximate conversions for longer periods _to_sec['mon'] = 30.0 * 86400.0 _to_sec['month'] = 30.0 * 86400.0 @@ -892,7 +897,7 @@ def to_deltatime(self, # return the date in time (default days) since epoch return scale*np.array(self.MJD - delta_time_epochs, dtype=np.float64) - def to_datetime(self): + def to_datetime(self, unit='ns'): """ Convert a ``Timescale`` object to a ``datetime`` array @@ -901,12 +906,15 @@ def to_datetime(self): dtime: np.ndarray ``numpy.datetime64`` array """ + # verify that units are numpy datetime compatible + assert unit in ['D','h','m','s','ms','us','ns'] # convert Modified Julian Day epoch to datetime variable epoch = np.datetime64(datetime.datetime(*_mjd_epoch)) - # use nanoseconds to keep as much precision as possible - delta_time = np.atleast_1d(self.MJD*self.day*1e9).astype(np.int64) + # calculate the delta time in the specified units + scale = self.day*_from_sec[unit] + delta_time = np.atleast_1d(self.MJD*scale).astype(np.int64) # return the datetime array - return np.array(epoch + delta_time.astype('timedelta64[ns]')) + return np.array(epoch + delta_time.astype(f'timedelta64[{unit}]')) def to_string(self, unit: str = 's', **kwargs): """ @@ -919,7 +927,11 @@ def to_string(self, unit: str = 's', **kwargs): **kwargs: dict keyword arguments for datetime formatting """ - return np.datetime_as_string(self.to_datetime(), unit=unit, **kwargs) + return np.datetime_as_string( + self.to_datetime(unit=unit), + unit=unit, + **kwargs + ) # PURPOSE: calculate the sum of a polynomial function of time def polynomial_sum(self, coefficients: list | np.ndarray, t: np.ndarray):