From a5b42b35fb7829e225981c9678f0b0c1c569ab7c Mon Sep 17 00:00:00 2001 From: Tom Aldcroft Date: Fri, 31 Mar 2023 10:19:10 -0400 Subject: [PATCH 1/2] Improve time conversions helpers --- cxotime/cxotime.py | 65 +++++++++++++++-------- cxotime/scripts/__init__.py | 0 cxotime/scripts/print_time_conversions.py | 34 ++++++++++++ cxotime/tests/test_cxotime.py | 37 +++++++++++++ setup.py | 2 +- 5 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 cxotime/scripts/__init__.py create mode 100644 cxotime/scripts/print_time_conversions.py diff --git a/cxotime/cxotime.py b/cxotime/cxotime.py index c3f1b41..ffcaa29 100644 --- a/cxotime/cxotime.py +++ b/cxotime/cxotime.py @@ -25,13 +25,6 @@ iers.conf.auto_download = False -def print_time_conversions(): - """Interface to entry_point script ``cxotime`` to print time conversions""" - date = None if len(sys.argv) == 1 else sys.argv[1] - date = CxoTime(date) - date.print_conversions() - - def date2secs(date): """Fast conversion from Year Day-of-Year date(s) to CXC seconds @@ -310,9 +303,9 @@ def now(cls): now.__doc__ = Time.now.__doc__ - def print_conversions(self): + def print_conversions(self, file=sys.stdout): """ - Print a table of conversions to other formats. + Print a table of conversions to a standard set of formats. Example:: @@ -326,33 +319,63 @@ def print_conversions(self): decimalyear 2010.00000 iso 2010-01-01 00:00:00.000 unix 1262304000.000 + + :param file: file-like, optional + File-like object to write output (default=sys.stdout). """ from astropy.table import Table - from dateutil import tz formats = { - "date": "s", "cxcsec": ".3f", "decimalyear": ".5f", - "iso": "s", "unix": ".3f", } - dt_utc = self.datetime.replace(tzinfo=tz.tzutc()) - dt_local = dt_utc.astimezone(tz.tzlocal()) - rows = [] - rows.append(["local", dt_local.strftime("%Y %a %b %d %I:%M:%S %p %Z")]) - rows.append(["iso_local", dt_local.isoformat()]) + conversions = self.get_conversions() + + # Format numerical values as strings with specified precision for name, fmt in formats.items(): - row = [name, format(getattr(self, name), fmt)] - rows.append(row) + conversions[name] = format(conversions[name], fmt) - out = Table(rows=rows, names=["format", "value"]) + formats = list(conversions) + values = list(conversions.values()) + out = Table([formats, values], names=["format", "value"]) out["format"].info.format = ">> 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} + """ + from datetime import timezone + + out = {} + + dt_local = self.datetime.replace(tzinfo=timezone.utc).astimezone(tz=None) + out["local"] = dt_local.strftime("%Y %a %b %d %I:%M:%S %p %Z") + out["iso_local"] = dt_local.isoformat() + + for name in ["date", "cxcsec", "decimalyear", "iso", "unix"]: + out[name] = getattr(self, name) + + return out class TimeSecs(TimeCxcSec): diff --git a/cxotime/scripts/__init__.py b/cxotime/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cxotime/scripts/print_time_conversions.py b/cxotime/scripts/print_time_conversions.py new file mode 100644 index 0000000..b1c33dc --- /dev/null +++ b/cxotime/scripts/print_time_conversions.py @@ -0,0 +1,34 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst +import sys + +from cxotime import CxoTime + + +def main(date=None, file=sys.stdout): + """Interface to entry_point script ``cxotime`` to print time conversions. + + :param date: str, float, optional + Date for time conversion if sys.argv[1] is not provided. Mostly for testing. + :param file: file-like, optional + File-like object to write output (default=sys.stdout). Mostly for testing. + """ + if date is None: + if len(sys.argv) > 2: + print("Usage: cxotime [date]") + sys.exit(1) + + if len(sys.argv) == 2: + date = sys.argv[1] + + # If the input can be converted to a float then it is a CXC seconds value + try: + date = float(date) + except Exception: + pass + + date = CxoTime(date) + date.print_conversions(file) + + +if __name__ == "__main__": + main() diff --git a/cxotime/tests/test_cxotime.py b/cxotime/tests/test_cxotime.py index 1c336cc..588fb2b 100644 --- a/cxotime/tests/test_cxotime.py +++ b/cxotime/tests/test_cxotime.py @@ -3,6 +3,7 @@ Simple test of CxoTime. The base Time object is extremely well tested, so this simply confirms that the add-on in CxoTime works. """ +import io import astropy.units as u import numpy as np @@ -11,6 +12,7 @@ from Chandra.Time import DateTime from .. import CxoTime, date2secs, secs2date +from ..scripts import print_time_conversions def test_cxotime_basic(): @@ -274,3 +276,38 @@ def test_secs2date(date): val = secs2date(t_secs) assert isinstance(val, np.ndarray) assert val.dtype.kind == "U" + + +def test_get_conversions(): + t = CxoTime("2010:001:00:00:00") + out = t.get_conversions() + exp = { + "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, + } + assert out == exp + + +@pytest.mark.parametrize( + "date", ["378691266.184", "2010:001", "2010-01-01 00:00:00.000"] +) +def test_print_time_conversions(date): + out = io.StringIO() + print_time_conversions.main(date, file=out) + exp = """\ +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""" + out_str = out.getvalue() + # Strip all trailing whitespace on each line + out_str = "\n".join([line.rstrip() for line in out_str.splitlines()]) + assert out_str == exp diff --git a/setup.py b/setup.py index c4369ed..2372499 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ entry_points = { "console_scripts": [ - "cxotime = cxotime.cxotime:print_time_conversions", + "cxotime = cxotime.scripts.print_time_conversions:main", ] } From 0bd1382ec62bef7f137c1006269801698bdc6048 Mon Sep 17 00:00:00 2001 From: Tom Aldcroft Date: Wed, 5 Apr 2023 13:48:15 -0400 Subject: [PATCH 2/2] Add scripts subpackage to packages --- .pre-commit-config.yaml | 6 +++--- setup.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8b80199..e3e5bcb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,6 +8,6 @@ repos: - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: - - id: isort - name: isort (python) - language_version: python3.10 + - id: isort + name: isort (python) + language_version: python3.10 diff --git a/setup.py b/setup.py index 2372499..b7cec6e 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ use_scm_version=True, setup_requires=["setuptools_scm", "setuptools_scm_git_archive"], zip_safe=False, - packages=["cxotime", "cxotime.tests"], + packages=["cxotime", "cxotime.scripts", "cxotime.tests"], tests_require=["pytest"], cmdclass=cmdclass, entry_points=entry_points,