timeconversions.py
427 lines
| 13.5 KiB
| text/x-python
|
PythonLexer
|
r208 | """ | ||
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_year<min_calendar) or (max_year>max_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)*0) + ((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)*0) + ((mins_1>=mins_2)*mins_1) | ||||
secs_2 = dom*0 + 0 | ||||
secs_1 = (fraction - mins/1440.0)*86400.0 | ||||
secs = ((secs_1<secs_2)*0) + ((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 | ||||