103 lines
2.4 KiB
Python
103 lines
2.4 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
# This file is part of convertdate.
|
||
|
# http://github.com/fitnr/convertdate
|
||
|
|
||
|
# Licensed under the MIT license:
|
||
|
# http://opensource.org/licenses/MIT
|
||
|
# Copyright (c) 2016, fitnr <fitnr@fakeisthenewreal>
|
||
|
from math import trunc
|
||
|
from .utils import ceil, jwday, monthcalendarhelper
|
||
|
from . import gregorian
|
||
|
|
||
|
EPOCH = 1948320.5
|
||
|
WEEKDAYS = ("Doshanbeh", "Seshhanbeh",
|
||
|
"Chaharshanbeh", "Panjshanbeh",
|
||
|
"Jomeh", "Shanbeh", "Yekshanbeh")
|
||
|
|
||
|
HAS_31_DAYS = (1, 2, 3, 4, 5, 6)
|
||
|
HAS_30_DAYS = (7, 8, 9, 10, 11)
|
||
|
|
||
|
|
||
|
def leap(year):
|
||
|
'''Is a given year a leap year in the Persian calendar ?'''
|
||
|
if year > 0:
|
||
|
y = 474
|
||
|
else:
|
||
|
y = 473
|
||
|
|
||
|
return ((((((year - y % 2820) + 474) + 38) * 682) % 2816) < 682)
|
||
|
|
||
|
|
||
|
def to_jd(year, month, day):
|
||
|
'''Determine Julian day from Persian date'''
|
||
|
|
||
|
if year >= 0:
|
||
|
y = 474
|
||
|
else:
|
||
|
y = 473
|
||
|
epbase = year - y
|
||
|
epyear = 474 + (epbase % 2820)
|
||
|
|
||
|
if month <= 7:
|
||
|
m = (month - 1) * 31
|
||
|
else:
|
||
|
m = (month - 1) * 30 + 6
|
||
|
|
||
|
return day + m + trunc(((epyear * 682) - 110) / 2816) + (epyear - 1) * 365 + trunc(epbase / 2820) * 1029983 + (EPOCH - 1)
|
||
|
|
||
|
|
||
|
def from_jd(jd):
|
||
|
'''Calculate Persian date from Julian day'''
|
||
|
jd = trunc(jd) + 0.5
|
||
|
|
||
|
depoch = jd - to_jd(475, 1, 1)
|
||
|
cycle = trunc(depoch / 1029983)
|
||
|
cyear = (depoch % 1029983)
|
||
|
|
||
|
if cyear == 1029982:
|
||
|
ycycle = 2820
|
||
|
else:
|
||
|
aux1 = trunc(cyear / 366)
|
||
|
aux2 = cyear % 366
|
||
|
ycycle = trunc(((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1
|
||
|
|
||
|
year = ycycle + (2820 * cycle) + 474
|
||
|
|
||
|
if (year <= 0):
|
||
|
year -= 1
|
||
|
|
||
|
yday = (jd - to_jd(year, 1, 1)) + 1
|
||
|
|
||
|
if yday <= 186:
|
||
|
month = ceil(yday / 31)
|
||
|
else:
|
||
|
month = ceil((yday - 6) / 30)
|
||
|
|
||
|
day = int(jd - to_jd(year, month, 1)) + 1
|
||
|
|
||
|
return (year, month, day)
|
||
|
|
||
|
|
||
|
def from_gregorian(year, month, day):
|
||
|
return from_jd(gregorian.to_jd(year, month, day))
|
||
|
|
||
|
|
||
|
def to_gregorian(year, month, day):
|
||
|
return gregorian.from_jd(to_jd(year, month, day))
|
||
|
|
||
|
|
||
|
def month_length(year, month):
|
||
|
if month in HAS_30_DAYS or (month == 12 and leap(year)):
|
||
|
return 30
|
||
|
elif month in HAS_31_DAYS:
|
||
|
return 31
|
||
|
|
||
|
return 29
|
||
|
|
||
|
|
||
|
def monthcalendar(year, month):
|
||
|
start_weekday = jwday(to_jd(year, month, 1))
|
||
|
monthlen = month_length(year, month)
|
||
|
return monthcalendarhelper(start_weekday, monthlen)
|