Package gen :: Package lib :: Module calendar
[frames] | no frames]

Source Code for Module gen.lib.calendar

  1  # 
  2  # Gramps - a GTK+/GNOME based genealogy program 
  3  # 
  4  # Copyright (C) 2000-2006  Donald N. Allingham 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 19  # 
 20   
 21  # $Id: calendar.py 10103 2008-02-24 13:55:55Z acraphae $ 
 22   
 23  """ 
 24  Provide calendar to sdn (serial date number) conversion. 
 25  """ 
 26   
 27  #------------------------------------------------------------------------- 
 28  # 
 29  # Python modules 
 30  # 
 31  #------------------------------------------------------------------------- 
 32  import math 
 33   
 34  #------------------------------------------------------------------------- 
 35  # 
 36  # Constants 
 37  # 
 38  #------------------------------------------------------------------------- 
 39  _GRG_SDN_OFFSET         = 32045 
 40  _GRG_DAYS_PER_5_MONTHS  = 153 
 41  _GRG_DAYS_PER_4_YEARS   = 1461 
 42  _GRG_DAYS_PER_400_YEARS = 146097 
 43   
 44  _JLN_SDN_OFFSET            = 32083 
 45  _JLN_DAYS_PER_5_MONTHS     = 153 
 46  _JLN_DAYS_PER_4_YEARS      = 1461 
 47   
 48  _HBR_HALAKIM_PER_DAY           = 25920 
 49  _HBR_HALAKIM_PER_LUNAR_CYCLE   = 765433 
 50  _HBR_HALAKIM_PER_METONIC_CYCLE = 179876755 
 51  _HBR_SDN_OFFSET                = 347997 
 52  _HBR_NEW_MOON_OF_CREATION      = 31524 
 53  _HBR_NOON                      = 19440 
 54  _HBR_AM3_11_20                 = 9924 
 55  _HBR_AM9_32_43                 = 16789 
 56   
 57  _HBR_SUNDAY    = 0 
 58  _HBR_MONDAY    = 1 
 59  _HBR_TUESDAY   = 2 
 60  _HBR_WEDNESDAY = 3 
 61  _HBR_FRIDAY    = 5 
 62   
 63  _HBR_MONTHS_PER_YEAR = [ 
 64      12, 12, 13, 12, 12, 13, 12, 13, 12, 12, 
 65      13, 12, 12, 13, 12, 12, 13, 12, 13 
 66      ] 
 67   
 68  _HBR_YEAR_OFFSET = [ 
 69      0, 12, 24, 37, 49, 61, 74, 86, 99, 111, 123, 
 70      136, 148, 160, 173, 185, 197, 210, 222 
 71      ] 
 72   
 73  _FR_SDN_OFFSET         = 2375474 
 74  _FR_DAYS_PER_4_YEARS   = 1461 
 75  _FR_DAYS_PER_MONTH     = 30 
 76  _PRS_EPOCH             = 1948320.5 
 77  _ISM_EPOCH             = 1948439.5 
 78   
79 -def _tishri1(metonic_year, molad_day, molad_halakim):
80 81 tishri1 = molad_day 82 dow = tishri1 % 7 83 leap_year = metonic_year in [ 2, 5, 7, 10, 13, 16, 18] 84 last_was_leap_year = metonic_year in [ 3, 6, 8, 11, 14, 17, 0] 85 86 # Apply rules 2, 3 and 4. 87 if ((molad_halakim >= _HBR_NOON) or 88 ((not leap_year) and dow == _HBR_TUESDAY and 89 molad_halakim >= _HBR_AM3_11_20) or 90 (last_was_leap_year and dow == _HBR_MONDAY 91 and molad_halakim >= _HBR_AM9_32_43)) : 92 tishri1 += 1 93 dow += 1 94 if dow == 7: 95 dow = 0 96 97 # Apply rule 1 after the others because it can cause an additional 98 # delay of one day 99 if dow == _HBR_WEDNESDAY or dow == _HBR_FRIDAY or dow == _HBR_SUNDAY: 100 tishri1 += 1 101 102 return tishri1
103
104 -def _tishri_molad(input_day):
105 """ 106 Estimate the metonic cycle number. 107 108 Note that this may be an under estimate because there are 6939.6896 days 109 in a metonic cycle not 6940, but it will never be an over estimate. The 110 loop below will correct for any error in this estimate. 111 """ 112 113 metonic_cycle = (input_day + 310) / 6940 114 115 # Calculate the time of the starting molad for this metonic cycle. */ 116 117 (molad_day, molad_halakim) = _molad_of_metonic_cycle(metonic_cycle) 118 119 # If the above was an under estimate, increment the cycle number until 120 # the correct one is found. For modern dates this loop is about 98.6% 121 # likely to not execute, even once, because the above estimate is 122 # really quite close. 123 124 while molad_day < (input_day - 6940 + 310): 125 metonic_cycle = metonic_cycle + 1 126 molad_halakim = molad_halakim + _HBR_HALAKIM_PER_METONIC_CYCLE 127 molad_day = molad_day + ( molad_halakim / _HBR_HALAKIM_PER_DAY) 128 molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY 129 130 # Find the molad of Tishri closest to this date. 131 132 for metonic_year in range(0, 18): 133 if molad_day > input_day - 74: 134 break 135 136 molad_halakim = molad_halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE 137 * _HBR_MONTHS_PER_YEAR[metonic_year]) 138 molad_day = molad_day + (molad_halakim / _HBR_HALAKIM_PER_DAY) 139 molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY 140 else: 141 metonic_year += 1 142 return (metonic_cycle, metonic_year, molad_day, molad_halakim)
143
144 -def _molad_of_metonic_cycle(metonic_cycle):
145 """ 146 Start with the time of the first molad after creation. 147 """ 148 149 r1 = _HBR_NEW_MOON_OF_CREATION 150 151 # Calculate metonic_cycle * HALAKIM_PER_METONIC_CYCLE. The upper 32 152 # bits of the result will be in r2 and the lower 16 bits will be 153 # in r1. 154 155 r1 = r1 + (metonic_cycle * (_HBR_HALAKIM_PER_METONIC_CYCLE & 0xFFFF)) 156 r2 = r1 >> 16 157 r2 = r2 + (metonic_cycle * ((_HBR_HALAKIM_PER_METONIC_CYCLE >> 16)&0xFFFF)) 158 159 # Calculate r2r1 / HALAKIM_PER_DAY. The remainder will be in r1, the 160 # upper 16 bits of the quotient will be in d2 and the lower 16 bits 161 # will be in d1. 162 163 d2 = r2 / _HBR_HALAKIM_PER_DAY 164 r2 = r2 - (d2 * _HBR_HALAKIM_PER_DAY) 165 r1 = (r2 << 16) | (r1 & 0xFFFF) 166 d1 = r1 / _HBR_HALAKIM_PER_DAY 167 r1 = r1 - ( d1 * _HBR_HALAKIM_PER_DAY) 168 169 molad_day = (d2 << 16) | d1 170 molad_halakim = r1 171 172 return (molad_day, molad_halakim)
173
174 -def _start_of_year(year):
175 """ 176 Calculate the start of the year. 177 """ 178 metonic_cycle = (year - 1) / 19 179 metonic_year = (year - 1) % 19 180 (molad_day, molad_halakim) = _molad_of_metonic_cycle(metonic_cycle) 181 182 molad_halakim = molad_halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE 183 * _HBR_YEAR_OFFSET[metonic_year]) 184 molad_day = molad_day + (molad_halakim / _HBR_HALAKIM_PER_DAY) 185 molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY 186 187 pTishri1 = _tishri1(metonic_year, molad_day, molad_halakim) 188 189 return (metonic_cycle, metonic_year, molad_day, molad_halakim, pTishri1)
190
191 -def hebrew_sdn(year, month, day):
192 """Convert a Jewish calendar date to an SDN number.""" 193 194 if month == 1 or month == 2: 195 # It is Tishri or Heshvan - don't need the year length. 196 (metonic_cycle, metonic_year, 197 molad_day, molad_halakim, tishri1) = _start_of_year(year) 198 if month == 1: 199 sdn = tishri1 + day - 1 200 else: 201 sdn = tishri1 + day + 29 202 elif month == 3: 203 # It is Kislev - must find the year length. 204 205 # Find the start of the year. 206 (metonic_cycle, metonic_year, 207 molad_day, molad_halakim, tishri1) = _start_of_year(year) 208 209 # Find the end of the year. 210 molad_halakim = molad_halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE 211 *_HBR_MONTHS_PER_YEAR[metonic_year]) 212 molad_day = molad_day + (molad_halakim / _HBR_HALAKIM_PER_DAY) 213 molad_halakim = molad_halakim % _HBR_HALAKIM_PER_DAY 214 tishri1_after = _tishri1((metonic_year + 1) 215 % 19, molad_day, molad_halakim) 216 217 year_length = tishri1_after - tishri1 218 219 if year_length == 355 or year_length == 385: 220 sdn = tishri1 + day + 59 221 else: 222 sdn = tishri1 + day + 58 223 elif month == 4 or month == 5 or month == 6: 224 # It is Tevet, Shevat or Adar I - don't need the year length 225 226 (metonic_cycle, metonic_year, 227 molad_day, molad_halakim, tishri1_after) = _start_of_year(year+1) 228 229 if _HBR_MONTHS_PER_YEAR[(year - 1) % 19] == 12: 230 length_of_adarI_andII = 29 231 else: 232 length_of_adarI_andII = 59 233 234 if month == 4: 235 sdn = tishri1_after + day - length_of_adarI_andII - 237 236 elif month == 5: 237 sdn = tishri1_after + day - length_of_adarI_andII - 208 238 else: 239 sdn = tishri1_after + day - length_of_adarI_andII - 178 240 else: 241 # It is Adar II or later - don't need the year length. 242 (metonic_cycle, metonic_year, 243 molad_day, molad_halakim, tishri1_after) = _start_of_year(year+1) 244 245 if month == 7: 246 sdn = tishri1_after + day - 207 247 elif month == 8: 248 sdn = tishri1_after + day - 178 249 elif month == 9: 250 sdn = tishri1_after + day - 148 251 elif month == 10: 252 sdn = tishri1_after + day - 119 253 elif month == 11: 254 sdn = tishri1_after + day - 89 255 elif month == 12: 256 sdn = tishri1_after + day - 60 257 elif month == 13: 258 sdn = tishri1_after + day - 30 259 else: 260 return 0 261 return sdn + _HBR_SDN_OFFSET
262
263 -def hebrew_ymd(sdn):
264 """Convert an SDN number to a Julian calendar date.""" 265 266 input_day = sdn - _HBR_SDN_OFFSET 267 268 (metonic_cycle, metonic_year, day, halakim) = _tishri_molad(input_day) 269 tishri1 = _tishri1(metonic_year, day, halakim) 270 271 if input_day >= tishri1: 272 # It found Tishri 1 at the start of the year 273 274 year = (metonic_cycle * 19) + metonic_year + 1 275 if input_day < tishri1 + 59: 276 if input_day < tishri1 + 30: 277 month = 1 278 day = input_day - tishri1 + 1 279 else: 280 month = 2 281 day = input_day - tishri1 - 29 282 return (year, month, day) 283 284 # We need the length of the year to figure this out, so find 285 # Tishri 1 of the next year. */ 286 287 halakim = halakim + (_HBR_HALAKIM_PER_LUNAR_CYCLE 288 * _HBR_MONTHS_PER_YEAR[metonic_year]) 289 day = day + (halakim / _HBR_HALAKIM_PER_DAY) 290 halakim = halakim % _HBR_HALAKIM_PER_DAY 291 tishri1_after = _tishri1((metonic_year + 1) % 19, day, halakim) 292 else: 293 # It found Tishri 1 at the end of the year. 294 295 year = metonic_cycle * 19 + metonic_year 296 if input_day >= tishri1 - 177: 297 # It is one of the last 6 months of the year. 298 if input_day > tishri1 - 30: 299 month = 13 300 day = input_day - tishri1 + 30 301 elif input_day > tishri1 - 60: 302 month = 12 303 day = input_day - tishri1 + 60 304 elif input_day > tishri1 - 89: 305 month = 11 306 day = input_day - tishri1 + 89 307 elif input_day > tishri1 - 119: 308 month = 10 309 day = input_day - tishri1 + 119 310 elif input_day > tishri1 - 148: 311 month = 9 312 day = input_day - tishri1 + 148 313 else: 314 month = 8 315 day = input_day - tishri1 + 178 316 return (year, month, day) 317 else: 318 if _HBR_MONTHS_PER_YEAR[(year - 1) % 19] == 13: 319 month = 7 320 day = input_day - tishri1 + 207 321 if day > 0: 322 return (year, month, day) 323 month = month - 1 324 day = day + 30 325 if day > 0: 326 return (year, month, day) 327 month = month - 1 328 day = day + 30 329 else: 330 month = 6 331 day = input_day - tishri1 + 207 332 if day > 0: 333 return (year, month, day) 334 month = month - 1 335 day = day + 30 336 337 if day > 0: 338 return (year, month, day) 339 month = month - 1 340 day = day + 29 341 if day > 0: 342 return (year, month, day) 343 344 # We need the length of the year to figure this out, so find 345 # Tishri 1 of this year 346 tishri1_after = tishri1 347 (metonic_cycle, metonic_year, day, halakim) = _tishri_molad(day-365) 348 tishri1 = _tishri1(metonic_year, day, halakim) 349 350 year_length = tishri1_after - tishri1 351 cday = input_day - tishri1 - 29 352 if year_length == 355 or year_length == 385 : 353 # Heshvan has 30 days 354 if day <= 30: 355 month = 2 356 day = cday 357 return (year, month, day) 358 day = day - 30 359 else: 360 # Heshvan has 29 days 361 if day <= 29: 362 month = 2 363 day = cday 364 return (year, month, day) 365 366 cday = cday - 29 367 368 # It has to be Kislev 369 return (year, 3, cday)
370
371 -def julian_sdn(year, month, day):
372 """Convert a Julian calendar date to an SDN number.""" 373 374 if year < 0: 375 year += 4801 376 else: 377 year += 4800 378 379 # Adjust the start of the year 380 if month > 2: 381 month -= 3 382 else: 383 month += 9 384 year -= 1 385 386 return (year * _JLN_DAYS_PER_4_YEARS)/4 \ 387 + (month * _JLN_DAYS_PER_5_MONTHS+2)/5 \ 388 + day - _JLN_SDN_OFFSET
389
390 -def julian_ymd(sdn):
391 """Convert an SDN number to a Julian date.""" 392 temp = (sdn + _JLN_SDN_OFFSET) * 4 - 1 393 394 # Calculate the year and day of year (1 <= day_of_year <= 366) 395 year = temp / _JLN_DAYS_PER_4_YEARS 396 day_of_year = (temp % _JLN_DAYS_PER_4_YEARS) / 4 + 1 397 398 # Calculate the month and day of month 399 temp = day_of_year * 5 - 3 400 month = temp / _JLN_DAYS_PER_5_MONTHS 401 day = (temp % _JLN_DAYS_PER_5_MONTHS) / 5 + 1 402 403 # Convert to the normal beginning of the year 404 if month < 10: 405 month += 3 406 else: 407 year += 1 408 month -= 9 409 410 # Adjust to the B.C./A.D. type numbering 411 year -= 4800 412 if year <= 0: 413 year -= 1 414 415 return (year, month, day)
416
417 -def gregorian_sdn(year, month, day):
418 """Convert a gregorian date to an SDN number.""" 419 if year < 0: 420 year += 4801 421 else: 422 year += 4800 423 424 # Adjust the start of the year 425 if month > 2: 426 month -= 3 427 else: 428 month += 9 429 year -= 1 430 431 return(((year / 100) * _GRG_DAYS_PER_400_YEARS) / 4 432 + ((year % 100) * _GRG_DAYS_PER_4_YEARS) / 4 433 + (month * _GRG_DAYS_PER_5_MONTHS + 2) / 5 434 + day 435 - _GRG_SDN_OFFSET )
436
437 -def gregorian_ymd(sdn):
438 """Convert an SDN number to a gregorian date.""" 439 temp = (_GRG_SDN_OFFSET + sdn) * 4 - 1 440 441 # Calculate the century (year/100) 442 century = temp / _GRG_DAYS_PER_400_YEARS 443 444 # Calculate the year and day of year (1 <= day_of_year <= 366) 445 temp = ((temp % _GRG_DAYS_PER_400_YEARS) / 4) * 4 + 3 446 year = (century * 100) + (temp / _GRG_DAYS_PER_4_YEARS) 447 day_of_year = (temp % _GRG_DAYS_PER_4_YEARS) / 4 + 1 448 449 # Calculate the month and day of month 450 temp = day_of_year * 5 - 3 451 month = temp / _GRG_DAYS_PER_5_MONTHS 452 day = (temp % _GRG_DAYS_PER_5_MONTHS) / 5 + 1 453 454 # Convert to the normal beginning of the year 455 if month < 10 : 456 month = month + 3 457 else: 458 year = year + 1 459 month = month - 9 460 461 # Adjust to the B.C./A.D. type numbering 462 year = year - 4800 463 if year <= 0: 464 year = year - 1 465 return (year, month, day)
466
467 -def french_sdn(year, month, day):
468 """Convert a French Republican Calendar date to an SDN number.""" 469 return (year*_FR_DAYS_PER_4_YEARS)/4 + \ 470 (month-1)*_FR_DAYS_PER_MONTH + \ 471 day + _FR_SDN_OFFSET
472
473 -def french_ymd(sdn):
474 """Convert an SDN number to a French Republican Calendar date.""" 475 temp = (sdn-_FR_SDN_OFFSET)*4 - 1 476 year = temp/_FR_DAYS_PER_4_YEARS 477 day_of_year = (temp%_FR_DAYS_PER_4_YEARS)/4 478 month = (day_of_year/_FR_DAYS_PER_MONTH)+1 479 day = (day_of_year%_FR_DAYS_PER_MONTH)+1 480 return (year, month, day)
481
482 -def persian_sdn(year, month, day):
483 """Convert a Persian date to an SDN number.""" 484 if year >= 0: 485 epbase = year - 474 486 else: 487 epbase = year - 473 488 489 epyear = 474 + epbase % 2820 490 491 if month <= 7: 492 v1 = (month - 1) * 31 493 else: 494 v1 = ((month - 1) * 30) + 6 495 v2 = math.floor(((epyear * 682) - 110) / 2816) 496 v3 = (epyear - 1) * 365 + day 497 v4 = math.floor(epbase / 2820) * 1029983 498 499 return int(math.ceil(v1 + v2 + v3 + v4 + _PRS_EPOCH - 1))
500
501 -def persian_ymd(sdn):
502 """Convert an SDN number to a Persian calendar date.""" 503 sdn = math.floor(sdn) + 0.5 504 505 depoch = sdn - 2121446 506 cycle = math.floor(depoch / 1029983) 507 cyear = depoch % 1029983 508 if cyear == 1029982: 509 ycycle = 2820 510 else: 511 aux1 = math.floor(cyear / 366) 512 aux2 = cyear % 366 513 ycycle = math.floor(((2134*aux1)+(2816*aux2)+2815)/1028522) + aux1 + 1 514 515 year = ycycle + (2820 * cycle) + 474 516 if year <= 0: 517 year = year - 1 518 519 yday = sdn - persian_sdn(year, 1, 1) + 1 520 if yday < 186: 521 month = math.ceil(yday / 31) 522 else: 523 month = math.ceil((yday - 6) / 30) 524 day = (sdn - persian_sdn(year, month, 1)) + 1 525 return (int(year), int(month), int(day))
526
527 -def islamic_sdn(year, month, day):
528 """Convert an Islamic date to an SDN number.""" 529 v1 = math.ceil(29.5 * (month - 1)) 530 v2 = (year - 1) * 354 531 v3 = math.floor((3 + (11 *year)) / 30) 532 533 return int(math.ceil((day + v1 + v2 + v3 + _ISM_EPOCH) - 1))
534
535 -def islamic_ymd(sdn):
536 """Convert an SDN number to an Islamic calendar date.""" 537 sdn = math.floor(sdn) + 0.5 538 year = int(math.floor(((30*(sdn-_ISM_EPOCH))+10646)/10631)) 539 month = int(min(12, math.ceil((sdn-(29+islamic_sdn(year, 1, 1)))/29.5) + 1)) 540 day = int((sdn - islamic_sdn(year, month, 1)) + 1) 541 return (year, month, day)
542