""" The TIME_CONVERSIONS.py module gathers classes and functions for time system transformations (e.g. between seconds from 1970 to datetime format). MODULES CALLED: NUMPY, TIME, DATETIME, CALENDAR MODIFICATION HISTORY: Created by Ing. Freddy Galindo (frederickgalindo@gmail.com). ROJ Aug 13, 2009. """ import numpy as np import time as tm import datetime as dt import calendar as cr class Time: """ time(year,month,dom,hour,min,secs) An object represents a date and time of certain event.. Parameters ---------- YEAR = Number of the desired year. Year must be valid values from the civil calendar. Years B.C.E must be represented as negative integers. Years in the common era are repre- sented as positive integers. In particular, note that there is no year 0 in the civil calendar. 1 B.C.E. (-1) is followed by 1 C.E. (1). MONTH = Number of desired month (1=Jan, ..., 12=December). DOM = Number of day of the month. HOUR = Number of the hour of the day. By default hour=0 MINS = Number of the minute of the hour. By default min=0 SECS = Number of the second of the minute. By default secs=0. Examples -------- time_info = time(2008,9,30,12,30,00) time_info = time(2008,9,30) """ def __init__(self,year=None,month=None,dom=None,hour=0,mins=0,secs=0): # If one the first three inputs are not defined, it takes the current date. date = tm.localtime() if year==None:year=date[0] if month==None:month=date[1] if dom==None:dom=date[2] # Converting to arrays year = np.array([year]); month = np.array([month]); dom = np.array([dom]) hour = np.array([hour]); mins = np.array([mins]); secs = np.array([secs]) # Defining time information object. self.year = np.atleast_1d(year) self.month = np.atleast_1d(month) self.dom = np.atleast_1d(dom) self.hour = np.atleast_1d(hour) self.mins = np.atleast_1d(mins) self.secs = np.atleast_1d(secs) def change2julday(self): """ Converts a datetime to Julian days. """ # Defining constants greg = 2299171 # incorrect Julian day for Oct, 25, 1582. min_calendar = -4716 max_calendar = 5000000 min_year = np.nanmin(self.year) max_year = np.nanmax(self.year) if (min_yearmax_calendar): print "Value of Julian date is out of allowed range" return -1 noyear = np.sum(self.year==0) if noyear>0: print "There is no year zero in the civil calendar" return -1 # Knowing if the year is less than 0. bc = self.year<0 # Knowing if the month is less than March. inJanFeb = self.month<=2 jy = self.year + bc - inJanFeb jm = self.month + (1 + 12*inJanFeb) # Computing Julian days. jul= np.floor(365.25*jy) + np.floor(30.6001*jm) + (self.dom+1720995.0) # Test whether to change to Gregorian Calendar if np.min(jul) >= greg: ja = np.int32(0.01*jy) jul = jul + 2 - ja + np.int32(0.25*ja) else: gregchange = np.where(jul >= greg) if gregchange[0].size>0: ja = np.int32(0.01 + jy[gregchange]) jy[grechange] = jy[gregchange] + 2 - ja + np.int32(0.25*ja) # Determining machine-specific parameters affecting floating-point. eps = 0.0 # Replace this line for a function to get precision. eps = abs(jul)*0.0 > eps jul = jul + (self.hour/24. -0.5) + (self.mins/1440.) + (self.secs/86400.) + eps return jul[0] def change2secs(self): """ Converts datetime to number of seconds respect to 1970. """ year = self.year if year.size>1: year = year[0] month = self.month if month.size>1: month = month[0] dom = self.dom if dom.size>1: dom = dom[0] # Resizing hour, mins and secs if it was necessary. hour = self.hour if hour.size>1:hour = hour[0] if hour.size==1:hour = np.resize(hour,year.size) mins = self.mins if mins.size>1:mins = mins[0] if mins.size==1:mins = np.resize(mins,year.size) secs = self.secs if secs.size>1:secs = secs[0] if secs.size==1:secs = np.resize(secs,year.size) # Using time.mktime to compute seconds respect to 1970. secs1970 = np.zeros(year.size) for ii in np.arange(year.size): secs1970[ii] = tm.mktime((int(year[ii]),int(month[ii]),int(dom[ii]),\ int(hour[ii]),int(mins[ii]),int(secs[ii]),0,0,0)) secs1970 = np.int32(secs1970 - tm.timezone) return secs1970 def change2strdate(self,mode=1): """ change2strdate method converts a date and time of certain event to date string. The string format is like localtime (e.g. Fri Oct 9 15:00:19 2009). Parameters ---------- None. Return ------ Modification History -------------------- Created by Freddy R. Galindo, ROJ, 09 October 2009. """ secs = np.atleast_1d(self.change2secs()) strdate = [] for ii in np.arange(np.size(secs)): secs_tmp = tm.localtime(secs[ii] + tm.timezone) if mode==1: strdate.append(tm.strftime("%d-%b-%Y (%j) %H:%M:%S",secs_tmp)) elif mode==2: strdate.append(tm.strftime("%d-%b-%Y (%j)",secs_tmp)) strdate = np.array(strdate) return strdate class Secs: """ secs(secs): An object represents the number of seconds respect to 1970. Parameters ---------- SECS = A scalar or array giving the number of seconds respect to 1970. Example: -------- secs_info = secs(1251241373) secs_info = secs([1251241373,1251241383,1251241393]) """ def __init__(self,secs): self.secs = secs def change2julday(self): """ Convert seconds from 1970 to Julian days. """ secs_1970 = time(1970,1,1,0,0,0).change2julday() julian = self.secs/86400.0 + secs_1970 return julian def change2time(self): """ Converts seconds from 1970 to datetime. """ secs1970 = np.atleast_1d(self.secs) datetime = np.zeros((9,secs1970.size)) for ii in np.arange(secs1970.size): tuple = tm.gmtime(secs1970[ii]) datetime[0,ii] = tuple[0] datetime[1,ii] = tuple[1] datetime[2,ii] = tuple[2] datetime[3,ii] = tuple[3] datetime[4,ii] = tuple[4] datetime[5,ii] = tuple[5] datetime[6,ii] = tuple[6] datetime[7,ii] = tuple[7] datetime[8,ii] = tuple[8] datetime = np.int32(datetime) return datetime class Julian: """ julian(julian): An object represents julian days. Parameters ---------- JULIAN = A scalar or array giving the julina days. Example: -------- julian_info = julian(2454740) julian_info = julian([2454740,2454760,2454780]) """ def __init__(self,julian): self.julian = np.atleast_1d(julian) def change2time(self): """ change2time method converts from julian day to calendar date and time. Return ------ year = An array giving the year of the desired julian day. month = An array giving the month of the desired julian day. dom = An array giving the day of the desired julian day. hour = An array giving the hour of the desired julian day. mins = An array giving the minute of the desired julian day. secs = An array giving the second of the desired julian day. Examples -------- >> jd = 2455119.0 >> [yy,mo,dd,hh,mi,ss] = TimeTools.julian(jd).change2time() >> print [yy,mo,dd,hh,mi,ss] [2009] [10] [ 14.] [ 12.] [ 0.] [ 0.] Modification history -------------------- Translated from "Numerical Recipies in C", by William H. Press, Brian P. Flannery, Saul A. Teukolsky, and William T. Vetterling. Cambridge University Press, 1988. Converted to Python by Freddy R. Galindo, ROJ, 06 October 2009. """ min_julian = -1095 max_julian = 1827933925 if (np.min(self.julian) < min_julian) or (np.max(self.julian) > max_julian): print 'Value of Julian date is out of allowed range.' return None # Beginning of Gregorian calendar igreg = 2299161 julLong = np.floor(self.julian + 0.5) minJul = np.min(julLong) if (minJul >= igreg): # All are Gregorian jalpha = np.int32(((julLong - 1867216) - 0.25)/36524.25) ja = julLong + 1 + jalpha - np.int32(0.25*jalpha) else: ja = julLong gregChange = np.where(julLong >= igreg) if gregChange[0].size>0: jalpha = np.int32(((julLong[gregChange]-1867216) - 0.25)/36524.25) ja[gregChange] = julLong[gregChange]+1+jalpha-np.int32(0.25*jalpha) # clear memory. jalpha = -1 jb = ja + 1524 jc = np.int32(6680. + ((jb-2439870)-122.1)/365.25) jd = np.int32(365.*jc + (0.25*jc)) je = np.int32((jb - jd)/30.6001) dom = jb - jd - np.int32(30.6001*je) month = je - 1 month = ((month - 1) % 12) + 1 month = np.atleast_1d(month) year = jc - 4715 year = year - (month > 2)*1 year = year - (year <= 0)*1 year = np.atleast_1d(year) # Getting hours, minutes, seconds fraction = self.julian + 0.5 - julLong eps_0 = dom*0.0 + 1.0e-12 eps_1 = 1.0e-12*np.abs(julLong) eps = (eps_0>eps_1)*eps_0 + (eps_0<=eps_1)*eps_1 hour_0 = dom*0 + 23 hour_2 = dom*0 + 0 hour_1 = np.floor(fraction*24.0 + eps) hour = ((hour_1>hour_0)*23) + ((hour_1<=hour_0)*hour_1) hour = ((hour_1=hour_2)*hour_1) fraction = fraction - (hour/24.0) mins_0 = dom*0 + 59 mins_2 = dom*0 + 0 mins_1 = np.floor(fraction*1440.0 + eps) mins = ((mins_1>mins_0)*59) + ((mins_1<=mins_0)*mins_1) mins = ((mins_1=mins_2)*mins_1) secs_2 = dom*0 + 0 secs_1 = (fraction - mins/1440.0)*86400.0 secs = ((secs_1=secs_2)*secs_1) return year, month,dom, hour, mins, secs def change2secs(self): """ Converts from Julian days to seconds from 1970. """ jul_1970 = Time(1970,1,1,0,0,0).change2julday() secs = np.int32((self.julian - jul_1970)*86400) return secs def change2lst(self,longitude=-76.8667): """ CT2LST converts from local civil time to local mean sideral time longitude = The longitude in degrees (east of Greenwich) of the place for which the local sideral time is desired, scalar. The Greenwich mean sideral time (GMST) can be found by setting longitude=0. """ # Useful constants, see Meus, p. 84 c = np.array([280.46061837, 360.98564736629, 0.000387933, 38710000.0]) jd2000 = 2451545.0 t0 = self.julian - jd2000 t = t0/36525. # Computing GST in seconds theta = c[0] + (c[1]*t0) + (t**2)*(c[2]-t/c[3]) # Computing LST in hours lst = (theta + longitude)/15.0 neg = np.where(lst < 0.0) if neg[0].size>0:lst[neg] = 24.0 + (lst[neg] % 24) lst = lst % 24.0 return lst class date2doy: def __init__(self,year,month,day): self.year = year self.month = month self.day = day def change2doy(self): if cr.isleap(self.year) == True: tfactor = 1 else: tfactor = 2 day = self.day month = self.month doy = np.floor((275*month)/9.0) - (tfactor*np.floor((month+9)/12.0)) + day - 30 return np.int32(doy) class Doy2Date: def __init__(self,year,doy): self.year = year self.doy = doy def change2date(self): months = np.arange(12) + 1 first_dem = date2doy(self.year,months,1) first_dem = first_dem.change2doy() imm = np.where((self.doy - first_dem) > 0) month = imm[0].size dom = self.doy -first_dem[month - 1] + 1 return month, dom