-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjddate.py
305 lines (238 loc) · 6.83 KB
/
jddate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# -*- encoding: iso-8859-1 -*-
# Date class for Python
# Copyright 1997, 1998, 2000 Kent Engström.
# Released under the GNU GPL.
import time
import string
import re
#
# AUXILIARY ROUTINES
#
# Most important algorithms are from:
# Meeus, Jean, Astronomical Formulae for Calculators, 2 ed
#
# Convert JD -> YMD
def jd_to_ymd(jd):
alpha = int((100*jd - 186721625L)/3652425L)
a = jd + 1 + alpha - alpha/4
b = a + 1524
c = int(100*b - 12210)/36525
d = int((36525L*c)/100)
e = int((10000L*b-10000L*d)/306001L)
res_d = b - d - int((306001L*e)/10000L)
if e<14:
res_m=e-1
else:
res_m=e-13
if res_m<3:
res_y=c-4715
else:
res_y=c-4716
return (res_y,res_m,res_d)
# Convert YMD -> JD
def ymd_to_jd(y,m,d):
if m<3: y=y-1; m=m+12
a = y/100;
return 1720995 + d + 2 - a + (a/4) + (36525*y)/100 + (306001*(m+1))/10000;
# Get weekday from JD (Monday = 1, ..., Sunday = 7)
def jd_to_weekday(jd):
return jd%7+1
# Convert YMD -> YWD
def ymd_to_ywd(y,m,d):
jd=ymd_to_jd(y,m,d)
jd1jan=ymd_to_jd(y,1,1)
wd1jan=jd_to_weekday(jd1jan)
if wd1jan<=4:
jd1mon=jd1jan+1-wd1jan
else:
jd1mon=jd1jan+8-wd1jan
if jd<jd1mon:
res_y=y-1
if jd_to_weekday(ymd_to_jd(y-1,1,1))<=4:
res_w=53
else:
res_w=52
else:
res_y=y
res_w=(jd-jd1mon)/7+1
if m==12 and d>=29:
wd1jannext=jd_to_weekday(ymd_to_jd(y+1,1,1))
if wd1jannext<=4 and wd1jannext+d>=33:
res_y=y+1
res_w=1
return (res_y,res_w,jd_to_weekday(jd))
# Convert YWD -> JD
def ywd_to_jd(y,w,d):
jd1jan = ymd_to_jd(y,1,1)
wd1jan = jd_to_weekday(jd1jan)
if wd1jan <= 4:
jd1mon = jd1jan + 1 - wd1jan
else:
jd1mon = jd1jan + 8 - wd1jan;
return jd1mon + w * 7 + d - 8
# Convert YWD -> YMD (internally via JD)
def ywd_to_ymd(y,w,d):
return jd_to_ymd(ywd_to_jd(y,w,d))
#
# THE DATE CLASS
#
class Date:
# Initializing and printing
def __init__(self): # New instances should be invalid!
self.__valid = 0
def __repr__(self):
if self.__valid:
return "<Date %04d-%02d-%02d>"%(self.__y, self.__m, self.__d)
else:
return "<Date invalid>"
def __hash__(self):
if self.__valid:
return ymd_to_jd(self.__y, self.__m, self.__d)
else:
return 0
def IsValid(self):
return self.__valid
# Setting the date in different formats
def SetJD(self, jd): # Julian date
if type(jd) == type(0):
(self.__y, self.__m, self.__d) = jd_to_ymd(jd)
self.__valid = 1
else:
self.__valid = 0
def SetYMD(self, y, m, d): # Year, month, date
# Controversial issue: how are we to handle two-digit dates?
# For the moment being, we choose the same approach as in
# the Fuego module.
if y >= 0 and y < 80:
y = y + 2000
elif y >= 80 and y < 100:
y = y + 1900
# Check this date by converting to JD and back.
# This could be done faster but not simpler :-)
jd = ymd_to_jd(y, m, d)
(y2, m2, d2) = jd_to_ymd(jd)
if y == y2 and m == m2 and d == d2:
(self.__y, self.__m, self.__d) = (y, m, d)
self.__valid = 1
else:
self.__valid = 0
def SetYWD(self, y, w, d): # Year, week, (week)day
(y2, m2, d2) = ywd_to_ymd(y, w, d)
self.SetYMD(y2, m2, d2)
# Check validity by convering back to YWD
if self.__valid:
(y3, w3, d3) = self.GetYWD()
if y3 <> y or w3 <> w or d3 <> d:
self.__valid = 0
# Getting (parts of) the date in different formats
def GetJD(self): # Julian date
if self.__valid:
return ymd_to_jd(self.__y, self.__m, self.__d)
else:
raise ValueError
def GetYMD(self): # Year, month, date
if self.__valid:
return (self.__y, self.__m, self.__d)
else:
raise ValueError
def GetYWD(self): # Year, week, (week)day
if self.__valid:
return ymd_to_ywd(self.__y, self.__m, self.__d)
else:
raise ValueError
# Getting some common string formats
def GetString_YYYY_MM_DD(self):
return "%04d-%02d-%02d"%(self.GetYMD())
def GetString_YYYYMMDD(self):
return "%04d%02d%02d"%(self.GetYMD())
def GetString_YY_MM_DD(self):
(y, m, d) = self.GetYMD()
return "%02d-%02d-%02d"%(y % 100, m, d)
def GetString_YYMMDD(self):
(y, m, d) = self.GetYMD()
return "%02d%02d%02d"%(y % 100, m, d)
# Getting some other dates from the current
def GetYearStart(self):
return FromYMD(self.__y, 1, 1)
def GetYearEnd(self):
return FromYMD(self.__y + 1, 12, 31)
def GetMonthStart(self):
return FromYMD(self.__y, self.__m, 1)
def GetMonthEnd(self):
m = self.__m + 1
if m > 12:
m = m - 12
y = self.__y + 1
else:
y = self.__y
return FromYMD(y, m, 1) - 1
def GetWeekStart(self):
# Monday is the first day of the week
(y, w, d) = self.GetYWD()
return self - d + 1
def GetWeekEnd(self):
# Sunday is the last day of the week
(y, w, d) = self.GetYWD()
return self + 7 - d
# Adding an integer: step that many days into the future
def __add__(self, days):
return FromJD(self.GetJD() + days)
def __radd__(self, days):
return FromJD(self.GetJD() + days)
# Subtracting an integer: step that many days into the past
# Subtracting two dates: get difference in days
def __sub__(self, other):
if type(other) == type(0):
return FromJD(self.GetJD() - other)
else:
return self.GetJD()-other.GetJD()
# Comparison between two dates: compare the JDs
def __cmp__(self, other):
return cmp(self.GetJD(), other.GetJD())
#
# INITIALIZERS FOR THE DATE CLASS
#
# These are the functions you should call to get new instances of
# the Date class
def FromJD(jd):
newdate = Date()
newdate.SetJD(jd)
return newdate
def FromYMD(y, m, d):
newdate = Date()
newdate.SetYMD(y, m, d)
return newdate
def FromYWD(y, w, d):
newdate = Date()
newdate.SetYWD(y, w, d)
return newdate
def FromToday():
(dy,dm,dd,th,tm,ts,wd,dayno,ds)=time.localtime(time.time())
return FromYMD(dy,dm,dd)
def FromUnixTime(t):
(dy,dm,dd,th,tm,ts,wd,dayno,ds)=time.localtime(t)
return FromYMD(dy,dm,dd)
rx_dashed=re.compile("^([0-9]+)-([0-9]+)-([0-9]+)$")
rx_yyyymmdd=re.compile("^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])$")
rx_yymmdd=re.compile("^([0-9][0-9])([0-9][0-9])([0-9][0-9])$")
def FromString(str):
newdate = Date() # Allocates an invalid date
m = rx_dashed.match(str)
if m:
newdate.SetYMD(string.atoi(m.group(1)),
string.atoi(m.group(2)),
string.atoi(m.group(3)))
return newdate
m = rx_yyyymmdd.match(str)
if m:
newdate.SetYMD(string.atoi(m.group(1)),
string.atoi(m.group(2)),
string.atoi(m.group(3)))
return newdate
m = rx_yymmdd.match(str)
if m:
newdate.SetYMD(string.atoi(m.group(1)),
string.atoi(m.group(2)),
string.atoi(m.group(3)))
return newdate
return newdate