Source code for soltrack.time

# -*- coding: utf-8 -*-
# SPDX-License-Identifier: EUPL-1.2
#  
#  Copyright (c) 2019-2022  Marc van der Sluys - marc.vandersluys.nl
#  
#  This file is part of the SolTrack Python package,
#  see: http://soltrack.sf.net
#  
#  This is free software: you can redistribute it and/or modify it under the terms of the
#  European Union Public Licence 1.2 (EUPL 1.2).
#  
#  This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
#  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#  See the EU Public Licence for more details.
#  
#  You should have received a copy of the European Union Public Licence along with this code.
#  If not, see <https://www.eupl.eu/1.2/en/>.


from dataclasses import dataclass
import numpy as np
import pandas as pd
import datetime as dt


[docs]@dataclass class Time: """Class containing the date and time (in UTC) to compute the Sun position for."""
[docs] def setDateAndTime(self, year=2000,month=1,day=1, hour=12,minute=0,second=0.0): """This function is obsolescent and will be removed in a future version. Use set_date_and_time() instead.""" _warn_obsolescent('setDateAndTime', 'set_date_and_time', rename=True) return self.set_date_and_time(year,month,day, hour,minute,second)
[docs] def set_date_and_time(self, year=2000,month=1,day=1, hour=12,minute=0,second=0.0): """Set the SolTrack date and time using UTC year, month, day, hour, minute and second. Parameters: year (int): year of date. month (int): month of date. day (int): day of date. hour (int): hour of day (default=0). minute (int): minute of time (default=0). second (float): second of time (default=0). Note: Use set_date_time() instead if you have a Python datetime object. """ # Combine the date/time values into a single "2D" array with a single row and the original values as # columns, and convert it to a Pandas df: df = pd.DataFrame(np.vstack([year,month,day, hour,minute,second]).transpose(), columns=['year','month','day', 'hour','minute','second']) df = pd.DataFrame(data=pd.to_datetime(df), columns=['UTC']) # Convert the date+time columns into a single datetime column self.utc = df.loc[:, 'UTC'] utc_dt = self.utc.dt self.year = utc_dt.year.to_numpy() self.month = utc_dt.month.to_numpy() self.day = utc_dt.day.to_numpy() self.hour = utc_dt.hour.to_numpy() self.minute = utc_dt.minute.to_numpy() self.second = utc_dt.second.to_numpy() + utc_dt.microsecond.to_numpy()/1e6 return
[docs] def setDateTime(self, dt_obj, utc=False): """This function is obsolescent and will be removed in a future version. Use setDateTime() instead.""" _warn_obsolescent('setDateTime', 'set_date_time', rename=True) return self.set_date_time(dt_obj, utc)
[docs] def set_date_time(self, dt_obj, utc=False): """Set the SolTrack date and time using a (local) Python datetime object. Parameters: dt_obj (datetime(64)): Date and time in a Python datetime object (UTC if timezone naive). Returns: Time: Date and time in a SolTrack time object. Note: Use set_date_and_time() instead if you have year, month,day, hour, minute and second as separate variables. """ if utc: # up to ~29% faster if datetimes are known to be UTC. Create DatetimeIndex with UTC times directly: if np.ndim(dt_obj) == 0: # Scalar, needs to be converted using [array]: self.utc = pd.to_datetime(np.asarray([dt_obj])) # DatetimeIndex else: self.utc = pd.to_datetime(np.asarray(dt_obj)) # DatetimeIndex else: # Create DatetimeIndex with local times, then convert to UTC: if np.ndim(dt_obj) == 0: # Scalar, needs to be converted using [array]: self.lt = pd.to_datetime(np.asarray([dt_obj])) # DatetimeIndex else: self.lt = pd.to_datetime(np.asarray(dt_obj)) # DatetimeIndex # Ensure timestamps are in UTC: self.utc = pd.to_datetime(self.lt, utc=True) # utc=True: make timezone aware (if not already), and set TZ=UTC (converting if needed). self.utc = self.utc.tz_convert(None) # 8±2% faster if left out. Convert to UTC tz naive (i.e. convert to UTC and remove tz info) # Note: the six lines below increase the cpu time of a compute_position() by a factor of 2.7! The # .to_numpy() method parts have a negligable contribution to that. # CHECK1: using .utc.to_julian_date() would not require self.year-second here, but is slightly slower # and gives wrong results in computeRiseSet(). See CHECK1 in those places. self.year = self.utc.year.to_numpy() self.month = self.utc.month.to_numpy() self.day = self.utc.day.to_numpy() self.hour = self.utc.hour.to_numpy() self.minute = self.utc.minute.to_numpy() self.second = self.utc.second.to_numpy() + self.utc.microsecond.to_numpy()/1e6 return
[docs] def now(self): """Return the current system time as a SolTrack time object. Returns: Current system date and time in a SolTrack time object. """ self.set_date_time(dt.datetime.now()) return
def _warn_obsolescent(old_name, new_name, rename=False, extra=False): """Warn that a function is obsolescent and will be removed. Indicate whether this concerns a simple rename, possibly with extra features.""" import sys sys.stderr.write('\nWarning: the SolTrack function '+old_name+'() is obsolescent and will be removed in a future version.') sys.stderr.write(' Use '+new_name+'() instead.') if rename: if extra: sys.stderr.write(' The interface has not changed much; a simple search and replace for the function names should suffice, but some dummy variables and class members have also be renamed, so please see the documentation in case a simple rename does not work and for new features.\n\n') else: sys.stderr.write(' The interface has not changed; a simple search and replace for the function names may suffice, but some dummy variables and class members have also be renamed, so please see the documentation in case a simple rename does not work.\n\n') else: sys.stderr.write(' Please see the documentation for details.\n\n') return