~bayazee/pycalverter/pycalverter-0.1

« back to all changes in this revision

Viewing changes to Calverter.py

  • Committer: Bayazee
  • Date: 2008-08-16 15:17:23 UTC
  • Revision ID: bayazee@mbs-20080816151723-ubyt91n86lodjilg
init

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
##   Calverter.py  (2007/07/01)
 
3
##
 
4
##   Copyright (C) 2007 Mehdi Bayazee (Bayazee@Gmail.com)
 
5
##
 
6
##   Iranian (Jalali) calendar: 
 
7
##           http://en.wikipedia.org/wiki/Iranian_calendar
 
8
##   Islamic (Hijri) calendar:
 
9
##           http://en.wikipedia.org/wiki/Islamic_calendar
 
10
##   Gregorian calendar:
 
11
##           http://en.wikipedia.org/wiki/Gregorian_calendar
 
12
##
 
13
##   This program is free software; you can redistribute it and/or modify
 
14
##   it under the terms of the GNU General Public License as published by
 
15
##   the Free Software Foundation; either version 2, or (at your option)
 
16
##   any later version.
 
17
##
 
18
##   This program is distributed in the hope that it will be useful,
 
19
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
##   GNU General Public License for more details.
 
22
 
 
23
 
 
24
__author__ = "Mehdi Bayazee"
 
25
__copyright__ = "Copyright (C) 2007 Mehdi Bayazee"
 
26
 
 
27
__revision__ = "$Id$"
 
28
__version__ = "0.1"
 
29
import math
 
30
 
 
31
class Calverter:
 
32
          
 
33
     def __init__(self):
 
34
          self.J0000 = 1721424.5                # Julian date of Gregorian epoch: 0000-01-01
 
35
          self.J1970 = 2440587.5                # Julian date at Unix epoch: 1970-01-01
 
36
          self.JMJD  = 2400000.5                # Epoch of Modified Julian Date system
 
37
          self.J1900 = 2415020.5                # Epoch (day 1) of Excel 1900 date system (PC)
 
38
          self.J1904 = 2416480.5                # Epoch (day 0) of Excel 1904 date system (Mac)
 
39
          
 
40
          self.NormLeap = ("Normal year", "Leap year")
 
41
          
 
42
          self.GREGORIAN_EPOCH = 1721425.5
 
43
          self.GREGORIAN_WEEKDAYS = ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
 
44
          
 
45
          self.ISLAMIC_EPOCH = 1948439.5;
 
46
          self.ISLAMIC_WEEKDAYS = ("al-ahad", "al-'ithnayn", "ath-thalatha'", "al-arbia`aa'", "al-khamis", "al-jumu`a", "as-sabt")
 
47
          
 
48
          self.JALALI_EPOCH = 1948320.5;
 
49
          self.JALALI_WEEKDAYS = ("Yekshanbeh", "Doshanbeh", "Seshhanbeh", "Chaharshanbeh", "Panjshanbeh", "Jomeh", "Shanbeh")
 
50
     
 
51
     
 
52
     def jwday(self, j):
 
53
          "JWDAY: Calculate day of week from Julian day"
 
54
          return int(math.floor((j + 1.5))) % 7     
 
55
     
 
56
     def weekday_before(self, weekday, jd):
 
57
         """WEEKDAY_BEFORE: Return Julian date of given weekday (0 = Sunday)
 
58
                            in the seven days ending on jd."""
 
59
         return jd - self.jwday(jd - weekday)
 
60
     
 
61
     
 
62
     def search_weekday(self, weekday, jd, direction, offset):
 
63
         """SEARCH_WEEKDAY: Determine the Julian date for: 
 
64
     
 
65
                                weekday      Day of week desired, 0 = Sunday
 
66
                                jd           Julian date to begin search
 
67
                                direction    1 = next weekday, -1 = last weekday
 
68
                                offset       Offset from jd to begin search"""
 
69
                 
 
70
         return self.weekday_before(weekday, jd + (direction * offset))
 
71
     
 
72
     #  Utility weekday functions, just wrappers for search_weekday
 
73
     
 
74
     def nearest_weekday(self, weekday, jd):
 
75
         return self.search_weekday(weekday, jd, 1, 3)
 
76
     
 
77
     def next_weekday(self, weekday, jd):
 
78
         return self.search_weekday(weekday, jd, 1, 7)
 
79
     
 
80
     def next_or_current_weekday(self, weekday, jd):
 
81
         return self.search_weekday(weekday, jd, 1, 6)
 
82
     
 
83
     def previous_weekday(self, weekday, jd):
 
84
         return self.search_weekday(weekday, jd, -1, 1)
 
85
     
 
86
     def previous_or_current_weekday(self, weekday, jd):
 
87
         return self.search_weekday(weekday, jd, 1, 0)
 
88
     
 
89
     
 
90
     def TestSomething(self):
 
91
         pass
 
92
     
 
93
     def leap_gregorian(self, year):
 
94
         "LEAP_GREGORIAN: Is a given year in the Gregorian calendar a leap year ?"
 
95
         return ((year % 4) == 0) and (not(((year % 100) == 0) and ((year % 400) != 0)))
 
96
     
 
97
     def gregorian_to_jd(self, year, month, day):
 
98
         "GREGORIAN_TO_JD: Determine Julian day number from Gregorian calendar date"
 
99
         
 
100
         # Python <= 2.5
 
101
         if month <= 2 :
 
102
             tm = 0
 
103
         elif self.leap_gregorian(year):
 
104
             tm = -1
 
105
         else:
 
106
             tm = -2
 
107
             
 
108
         # Python 2.5
 
109
         #tm = 0 if month <= 2 else (-1 if self.leap_gregorian(year) else -2)
 
110
             
 
111
         return (self.GREGORIAN_EPOCH - 1) + (365 * (year - 1)) + math.floor((year - 1) / 4) +  (-math.floor((year - 1) / 100)) + \
 
112
                math.floor((year - 1) / 400) + math.floor((((367 * month) - 362) / 12) + tm + day)
 
113
     
 
114
     
 
115
     def jd_to_gregorian(self, jd) :
 
116
         "JD_TO_GREGORIAN: Calculate Gregorian calendar date from Julian day"
 
117
     
 
118
         wjd = math.floor(jd - 0.5) + 0.5
 
119
         depoch = wjd - self.GREGORIAN_EPOCH
 
120
         quadricent = math.floor(depoch / 146097)
 
121
         dqc = depoch % 146097
 
122
         cent = math.floor(dqc / 36524)
 
123
         dcent = dqc % 36524
 
124
         quad = math.floor(dcent / 1461)
 
125
         dquad = dcent % 1461
 
126
         yindex = math.floor(dquad / 365)
 
127
         year = int((quadricent * 400) + (cent * 100) + (quad * 4) + yindex)
 
128
         if not((cent == 4) or (yindex == 4)) :
 
129
             year += 1
 
130
     
 
131
         yearday = wjd - self.gregorian_to_jd(year, 1, 1)
 
132
         
 
133
         # Python <= 2.5
 
134
         if wjd < self.gregorian_to_jd(year, 3, 1):
 
135
             leapadj = 0
 
136
         elif self.leap_gregorian(year):
 
137
             leapadj = 1
 
138
         else:
 
139
             leapadj = 2
 
140
             
 
141
         # Python 2.5
 
142
         #leapadj = 0 if wjd < self.gregorian_to_jd(year, 3, 1) else (1 if self.leap_gregorian(year) else 2)
 
143
        
 
144
         month = int(math.floor((((yearday + leapadj) * 12) + 373) / 367))
 
145
         day = int(wjd - self.gregorian_to_jd(year, month, 1)) + 1
 
146
     
 
147
         return year, month, day
 
148
     
 
149
     def n_weeks(self, weekday, jd, nthweek):
 
150
         
 
151
         j = 7 * nthweek
 
152
         if nthweek > 0 :
 
153
             j += self.previous_weekday(weekday, jd)
 
154
         else :
 
155
             j += next_weekday(weekday, jd)
 
156
         return j
 
157
     
 
158
     
 
159
     def iso_to_julian(self, year, week, day):
 
160
          "ISO_TO_JULIAN: Return Julian day of given ISO year, week, and day"
 
161
          return day + self.n_weeks(0, self.gregorian_to_jd(year - 1, 12, 28), week)
 
162
     
 
163
     
 
164
     def jd_to_iso(self, jd):
 
165
         "JD_TO_ISO: Return array of ISO (year, week, day) for Julian day"
 
166
         year = self.jd_to_gregorian(jd - 3)[0]
 
167
         if jd >= self.iso_to_julian(year + 1, 1, 1) :
 
168
             year += 1
 
169
         
 
170
         week = int(math.floor((jd - self.iso_to_julian(year, 1, 1)) / 7) + 1)
 
171
         day = self.jwday(jd)
 
172
         if day == 0 :
 
173
             day = 7
 
174
         
 
175
         return year, week, day
 
176
     
 
177
     def iso_day_to_julian(self, year, day):
 
178
         "ISO_DAY_TO_JULIAN: Return Julian day of given ISO year, and day of year"
 
179
         return (day - 1) + self.gregorian_to_jd(year, 1, 1)
 
180
     
 
181
     def jd_to_iso_day(self, jd):
 
182
         "JD_TO_ISO_DAY: Return array of ISO (year, day_of_year) for Julian day"
 
183
         year = self.jd_to_gregorian(jd)[0]
 
184
         day = int(math.floor(jd - self.gregorian_to_jd(year, 1, 1))) + 1
 
185
         return year, day
 
186
     
 
187
     def pad(self, Str, howlong, padwith) :
 
188
         "PAD: Pad a string to a given length with a given fill character. "
 
189
         s = str(Str)
 
190
     
 
191
         while s.length < howlong :
 
192
             s = padwith + s
 
193
         return s
 
194
     
 
195
     
 
196
     def leap_islamic(self, year):
 
197
         "LEAP_ISLAMIC: Is a given year a leap year in the Islamic calendar ?"
 
198
         return (((year * 11) + 14) % 30) < 11
 
199
     
 
200
     
 
201
     def islamic_to_jd(self, year, month, day):
 
202
         "ISLAMIC_TO_JD: Determine Julian day from Islamic date"
 
203
         return (day + \
 
204
                 math.ceil(29.5 * (month - 1)) + \
 
205
                 (year - 1) * 354 + \
 
206
                 math.floor((3 + (11 * year)) / 30) + \
 
207
                 self.ISLAMIC_EPOCH) - 1
 
208
     
 
209
     def jd_to_islamic(self, jd):
 
210
         "JD_TO_ISLAMIC: Calculate Islamic date from Julian day"
 
211
         
 
212
         jd = math.floor(jd) + 0.5
 
213
         year = int(math.floor(((30 * (jd - self.ISLAMIC_EPOCH)) + 10646) / 10631))
 
214
         month = int(min(12, math.ceil((jd - (29 + self.islamic_to_jd(year, 1, 1))) / 29.5) + 1))
 
215
         day = int(jd - self.islamic_to_jd(year, month, 1)) + 1;
 
216
         return year, month, day
 
217
     
 
218
     def leap_jalali(self, year):
 
219
         "LEAP_jalali: Is a given year a leap year in the Jalali calendar ?"
 
220
     
 
221
         # Python <= 2.5
 
222
         if year > 0:
 
223
             rm = 474
 
224
         else:
 
225
             rm = 473
 
226
     
 
227
         # Python 2.5
 
228
         #return ((((((year - 474 if year > 0 else 473 ) % 2820) + 474) + 38) * 682) % 2816) < 682
 
229
     
 
230
         return ((((((year - rm) % 2820) + 474) + 38) * 682) % 2816) < 682
 
231
     
 
232
     def jalali_to_jd(self, year, month, day):
 
233
         "JALALI_TO_JD: Determine Julian day from Jalali date"
 
234
         # Python <= 2.5
 
235
         if year >=0 :
 
236
             rm = 474
 
237
         else:
 
238
             rm = 473
 
239
         epbase = year - (rm)
 
240
         
 
241
         # Python 2.5
 
242
         #epbase = year - 474 if year>=0 else 473
 
243
         epyear = 474 + (epbase % 2820)
 
244
         
 
245
            
 
246
         if month <= 7 :
 
247
             mm = (month - 1) * 31
 
248
         else:
 
249
             mm = ((month - 1) * 30) + 6
 
250
     
 
251
         return day + mm + \
 
252
                 math.floor(((epyear * 682) - 110) / 2816) + \
 
253
                 (epyear - 1) * 365 + \
 
254
                 math.floor(epbase / 2820) * 1029983 + \
 
255
                 (self.JALALI_EPOCH - 1)
 
256
     
 
257
     def jd_to_jalali(self, jd):
 
258
         "JD_TO_JALALI: Calculate Jalali date from Julian day"
 
259
     
 
260
         jd = math.floor(jd) + 0.5
 
261
         depoch = jd - self.jalali_to_jd(475, 1, 1)
 
262
         cycle = math.floor(depoch / 1029983)
 
263
         cyear = depoch % 1029983
 
264
         if cyear == 1029982 :
 
265
             ycycle = 2820
 
266
         else :
 
267
             aux1 = math.floor(cyear / 366)
 
268
             aux2 = cyear % 366
 
269
             ycycle = math.floor(((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1
 
270
         
 
271
         year = int(ycycle + (2820 * cycle) + 474)
 
272
         if year <= 0 :
 
273
             year -= 1
 
274
         
 
275
         yday = (jd - self.jalali_to_jd(year, 1, 1)) + 1
 
276
         if yday <= 186:
 
277
             month = int(math.ceil(yday / 31))
 
278
         else:
 
279
             month = int(math.ceil((yday - 6) / 30))
 
280
             
 
281
         day = int(jd - self.jalali_to_jd(year, month, 1)) + 1
 
282
         return year, month, day
 
283
     
 
284