Source code for pyobs.utils.time

"""
TODO: write doc
"""

__title__ = "Time"

from datetime import UTC, date, datetime, time, timedelta
from typing import cast

import astropy.time
import astropy.units as u
from astroplan import Observer


[docs] class Time(astropy.time.Time): """Hashable Time class.""" _now_offset = astropy.time.TimeDelta(0 * u.second) def __hash__(self) -> int: if self.ndim != 0: raise TypeError(f"unhashable type: '{self.__class__.__name__}'") return hash((self.jd1, self.jd2, self.scale))
[docs] @classmethod def set_offset_to_now(cls, delta: astropy.time.TimeDelta) -> None: """Shifts what :meth:`now` returns by ``delta``, without affecting the system clock. For simulation/testing scenarios that need to run at an arbitrary point in time. """ cls._now_offset = delta
[docs] @classmethod def now(cls) -> "Time": """ Creates a new object corresponding to the instant in time this method is called. .. note:: "Now" is determined using the `~datetime.datetime.utcnow` function, so its accuracy and precision is determined by that function. Generally that means it is set by the accuracy of your system clock. Returns: A new `Time` object (or a subclass of `Time` if this is called from such a subclass) at the current time. """ # call `utcnow` immediately to be sure it's ASAP dtnow = datetime.now(UTC) return cast(Time, Time(val=dtnow, format="datetime", scale="utc") + Time._now_offset)
[docs] def night_obs(self, observer: Observer) -> date: """Returns the night for this time, i.e. the date of the start of the current night. The boundary is local civil noon in the observer's timezone. All times from noon until the next noon use the local date of the sunset after that opening noon, keeping evening exposures and morning calibrations on the same night. If no sunset is found (e.g. polar day/night), use the query's local calendar date instead; that fallback can change at midnight. Args: observer: Observer object to use. Returns: Night for this time. """ timezone = observer.timezone local_time = self.to_datetime(timezone=timezone) noon_date = local_time.date() if local_time.hour < 12: noon_date -= timedelta(days=1) noon = datetime.combine(noon_date, time(12)) # Localize the anchor independently: the query may have crossed a DST change # since that noon. pytz requires localize(), while other tzinfo uses replace(). if hasattr(timezone, "localize"): noon = timezone.localize(noon) else: noon = noon.replace(tzinfo=timezone) sunset = observer.sun_set_time(Time(noon), which="next") if sunset.masked: # sun doesn't cross the horizon within the search window, e.g. polar day/night, # so fall back to the observer's local calendar date return cast(date, local_time.date()) return sunset.to_datetime(timezone=timezone).date()
__all__ = ["Time"]