Skip to content

Commit 08d1103

Browse files
author
Jesse Wayde Brandão
committed
First commit of Silaty's code
1 parent 3a77f02 commit 08d1103

24 files changed

+3019
-0
lines changed

README

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
To install this Application Run:
2+
3+
sudo python setup.py install

hijra.py

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
#! /usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Hijri Islamic Calendar converting functions,
5+
Copyright (c) 2006-2008 Muayyad Saleh Alsadi<[email protected]>
6+
Based on an enhanced algorithm designed by me
7+
the algorithm is discussed in a book titled "حتى لا ندخل جحور الضباب"
8+
(not yet published)
9+
10+
This file can be used to implement apps, gdesklets or karamba ..etc
11+
12+
This algorithm is based on integer operations
13+
which that there is no round errors (given accurate coefficients)
14+
the accuracy of this algorithm is based on 3 constants (p,q and a)
15+
where p/q is the full months percentage [ gcd(p,q) must be 1 ]
16+
currently it's set to 191/360 which mean that there is 191 months
17+
having 30 days in a span of 360 years, other months are 29 days.
18+
and a is just a shift.
19+
20+
21+
Released under terms on Waqf Public License.
22+
This program is free software; you can redistribute it and/or modify
23+
it under the terms of the latest version Waqf Public License as
24+
published by Ojuba.org.
25+
26+
This program is distributed in the hope that it will be useful,
27+
but WITHOUT ANY WARRANTY; without even the implied warranty of
28+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
29+
30+
The Latest version of the license can be found on
31+
"http://www.ojuba.org/wiki/doku.php/waqf/license"
32+
33+
34+
Portions of this algorithm is based on that found on GNU EMACS
35+
the difference is that this algorithm does not set
36+
all months to a fixed number of days (in the original algorithm
37+
first month always have 30 days)
38+
39+
40+
The original GNU Emacs LISP algorithm
41+
Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc.
42+
Edward M. Reingold <[email protected]>
43+
Technical details of all the calendrical calculations can be found in
44+
``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
45+
Cambridge University Press (1997).
46+
Comments, corrections, and improvements should be sent to
47+
Edward M. Reingold Department of Computer Science
48+
(217) 333-6733 University of Illinois at Urbana-Champaign
49+
[email protected] 1304 West Springfield Avenue
50+
"""
51+
__p_const=191
52+
__q_const=360
53+
__a_const=48
54+
__hijri_epoch=227015; # = Julian 0622-7-16 = gregorian 0759-6-11 (I think it should be 622, 7, 19)
55+
# TODO: Why does the the hijri_epoch 227015 does not give the expected value when converted to gregorian
56+
57+
def get_consts():
58+
"""Return a tuple of the 3 constants (p,q,a) used by this algothim, for debuging"""
59+
return (__p_const, __q_const, __a_const)
60+
def get_epoch():
61+
"""Return Hijri epoch, number of days since gregorian epoch, (should be Julian 0622-7-16 (ie. 227015 days)"""
62+
return __hijri_epoch
63+
64+
def hijri_month_days(Y,M):
65+
"""Return the number of days in a given hijri month M in a given Y"""
66+
Mc = ( Y -1) *12 + M
67+
if (((Mc+ __a_const) * __p_const) % __q_const) < __p_const : return 30
68+
else: return 29
69+
70+
# NOTE: trivial implementation
71+
#def hijri_days_before_month_(Y,M): # simple mothod, optimization is possible by reusing Mc ..etc.
72+
# """Return the number of days before a given moth M in a given year Y"""
73+
# sum=0
74+
# for i in range(1,M): sum+=hijri_month_days(Y,i);
75+
# return sum
76+
77+
def hijri_days_before_month(Y,M):
78+
"""Return the number of days before a given moth M in a given year Y (0 for M=1)"""
79+
Mc = (Y -1) *12 + 1 + __a_const
80+
McM=Mc * __p_const
81+
sum=0
82+
for i in range(1,M):
83+
if (McM % __q_const) < __p_const : sum+=30
84+
else: sum+=29
85+
McM+=__p_const
86+
return sum
87+
88+
#TEST: PASSED
89+
# test that the faster hijri_days_before_month is ok
90+
#def test_hijri_days_before_month():
91+
# l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
92+
# for y,m in l:
93+
# d1=hijri_days_before_month(y,m)
94+
# d2=hijri_days_before_month_(y,m)
95+
# if d1!=d2: print y,m,d1,d2
96+
97+
98+
def hijri_year_days(Y):
99+
"""Return the number of days in a given year Y"""
100+
return hijri_days_before_month(Y,13)
101+
102+
def hijri_day_number (Y, M, D):
103+
"""Return the day number within the year of the Islamic date (Y, M, D), 1 for 1/1 in any year"""
104+
return hijri_days_before_month(Y,M)+D
105+
106+
107+
# BAD fast implementation
108+
#def hijri_to_absolute_ (Y, M, D):
109+
# """Return absolute date of Hijri (Y,M,D), eg. ramadan (9),1,1427 -> 732578 """
110+
# Mc=(Y-1)*12
111+
# # days before Hijra + days in the years before + days from the begining of that year
112+
# return __hijri_epoch + \
113+
# Mc*29 + Mc*__p_const/__q_const + \ # this line should involve __a_const
114+
# hijri_day_number (Y, M, D) - 1
115+
116+
# correct implementation # TODO: optimize it more and test that after optimization
117+
def hijri_to_absolute (Y, M, D):
118+
"""Return absolute date of Hijri (Y,M,D), eg. ramadan (9),1,1427 -> 732578 """
119+
Mc=(Y-1)*12
120+
# day count=days before Hijra plus (...)
121+
dc=__hijri_epoch
122+
# plus days in the years before till first multiples of q plus (...)
123+
Mc-=Mc % __q_const
124+
y=Y-Mc//12
125+
dc+=Mc*29 + Mc*__p_const//__q_const
126+
# plus those after the multiples plus (...)
127+
for i in range(1,y): dc += hijri_year_days(i)
128+
# plus days from the begining of that year
129+
dc+=hijri_day_number (Y, M, D) - 1
130+
return dc
131+
132+
def hijri_month_days_(y,m):
133+
"""Return the number of days in a given hijri month M in a given Y"""
134+
return hijri_to_absolute(y+m//12,m%12+1,1)-hijri_to_absolute(y,m,1)
135+
136+
# TEST: PASSED
137+
#def test_hijri_to_absolute_v_month_days():
138+
# #l=[(y,m) for y in range(1,31) for m in range(1,13)]
139+
# l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
140+
# for y,m in l:
141+
# d1=hijri_month_days(y,m)
142+
# d2=hijri_to_absolute(y+m/12,m%12+1,1)-hijri_to_absolute(y,m,1)
143+
# if d1!=d2: print y,m,y+m/12,m%12+1,'d1=',d1,", d2=",d2
144+
145+
# round then move to exact, very slow perfect implementation
146+
#def absolute_to_hijri_ (date): # TODO: check if it's always compatible with absolute_from_hijri
147+
# """Return Hijri date (Y,M,D) corresponding to the given absolute number of days."""
148+
# if date < __hijri_epoch: return None; # pre-Islamic date
149+
# dd=date-__hijri_epoch
150+
# Mc=dd/(29*(__q_const-__p_const)+ 30*__p_const)*__q_const # mounth count till multibles of q
151+
# Y=y=Mc/12+1; M=m=(Mc%12)+1
152+
# while(date > hijri_to_absolute(Y,M,1)):
153+
# y,m=Y,M
154+
# M+=1
155+
# if M>12: M=1; Y+=1
156+
# Y=y; M=m
157+
# D=1 + date - hijri_to_absolute(Y,M,1)
158+
# if D>hijri_month_days(Y,M):
159+
# M+=1
160+
# if M>12: M=1; Y+=1
161+
# D=1 + date - hijri_to_absolute(Y,M,1)
162+
# return (Y,M,D)
163+
164+
165+
# direct way, test PASSED
166+
def absolute_to_hijri (date):
167+
"""Return Hijri date (Y,M,D) corresponding to the given absolute number of days."""
168+
if date < __hijri_epoch: return None; # pre-Islamic date
169+
Mc=(date-__hijri_epoch+1)*__q_const//(29*__q_const+__p_const)
170+
Y=Mc//12+1; M=(Mc%12)+1
171+
# consistency check
172+
d=hijri_to_absolute(Y,M,1) # TODO: this is an expensive call
173+
if (date < d): # go one month back if needed
174+
M-=1
175+
if M==0: Y-=1; M=12
176+
d-=hijri_month_days(Y,M) # this call is fast
177+
#
178+
D=1 + date - d
179+
return (Y,M,D)
180+
181+
# TEST: PASSED
182+
#def test_c():
183+
# l=[(y,m) for y in range(1400,1499) for m in range(1,13)]
184+
# for y,m in l:
185+
# d=hijri_month_days(y,m)
186+
# if absolute_to_hijri(hijri_to_absolute(y,m,1))!=(y,m,1): print y,m,1, absolute_to_hijri(hijri_to_absolute(y,m,1))
187+
# if absolute_to_hijri(hijri_to_absolute(y,m,d))!=(y,m,d): print y,m,d, absolute_to_hijri(hijri_to_absolute(y,m,d))
188+
189+
def hijri_day_of_week (Y, M, D):
190+
"""Return the day-of-the-week index of hijri (Y,M,D) Date, 0 for Sunday, 1 for Monday, etc."""
191+
return hijri_to_absolute (Y,M, D) % 7
192+
# ///////////////////////////////
193+
# high level converting functions
194+
195+
def hijri_to_gregorian (year, month, day):
196+
"""Return gregorian (year, month, day) converted from Islamic Hijri calender"""
197+
return absolute_to_gregorian( hijri_to_absolute (year, month, day))
198+
199+
def gregorian_to_hijri (year, month, day):
200+
"""Return Hijri (year, month, day) converted from gregorian calender"""
201+
return absolute_to_hijri( gregorian_to_absolute (year, month, day))
202+
203+
#///////////////////////////////////
204+
# Gregorian functions
205+
#///////////////////////////////////
206+
# This Portions of is based on that found on GNU EMACS
207+
208+
#The original GNU Emacs LISP algorithm
209+
#Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc.
210+
# Edward M. Reingold <[email protected]>
211+
# Technical details of all the calendrical calculations can be found in
212+
# ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,
213+
# Cambridge University Press (1997).
214+
# Comments, corrections, and improvements should be sent to
215+
# Edward M. Reingold Department of Computer Science
216+
# (217) 333-6733 University of Illinois at Urbana-Champaign
217+
# [email protected] 1304 West Springfield Avenue
218+
219+
days_in_month=( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
220+
def gregorian_leap_year_p (year):
221+
"""Return 1 (True) if YEAR is a Gregorian leap year."""
222+
if ((year % 4) == 0 and ((year % 100) or (year % 400) == 0)): return 1;
223+
return 0;
224+
225+
def gregorian_month_days (year, month):
226+
"""The last day in MONTH during YEAR."""
227+
if (month == 2 and gregorian_leap_year_p (year)): return 29;
228+
return days_in_month[month-1];
229+
230+
def gregorian_day_number (year, month, day):
231+
"""Return the day number within the year of the date (year,month, day)"""
232+
if month<3: return day + (31 * (month - 1))
233+
return day + (31 * (month - 1)) - \
234+
((month << 2) + 23) // 10 + (gregorian_leap_year_p (year) & 1);
235+
236+
def gregorian_to_absolute (year, month, day):
237+
prior_years = year - 1
238+
return gregorian_day_number (year, month, day) + \
239+
(365 * prior_years + (prior_years >> 2)) - \
240+
(prior_years // 100) + (prior_years // 400)
241+
242+
def absolute_to_gregorian(date):
243+
"""return (year month day) corresponding to the absolute DATE.
244+
The absolute date is the number of days elapsed since the (imaginary)
245+
Gregorian date Sunday, December 31, 1 BC."""
246+
247+
# See the footnote on page 384 of ``Calendrical Calculations, Part II:
248+
# Three Historical Calendars'' by E. M. Reingold, N. Dershowitz, and S. M.
249+
# Clamen, Software--Practice and Experience, Volume 23, Number 4
250+
# (April, 1993), pages 383-404 for an explanation.
251+
d0 = date - 1;
252+
n400 = d0 // 146097;
253+
d1 = d0 % 146097;
254+
n100 = d1 // 36524;
255+
d2 = d1 % 36524;
256+
n4 = d2 // 1461;
257+
d3 = d2 % 1461;
258+
n1 = d3 // 365;
259+
dd = (d3 % 365) + 1;
260+
yy = ((400 * n400) + (100 * n100) + (n4 * 4) + n1);
261+
if (n100 == 4) or (n1 == 4): return (yy, 12, 31);
262+
yy=yy+1;
263+
mm = 1;
264+
while(date >= gregorian_to_absolute (yy,mm, 1)): mm+=1;
265+
d=gregorian_to_absolute (yy, mm-1, 1);
266+
return (yy, mm-1,date-d+1);
267+
# d = calendar_absolute_from_gregorian (1, 1, yy);
268+
# mm=1;
269+
# while(mm <= 12):
270+
# dd = date - d + 1;
271+
# dm = calendar_last_day_of_month (mm, yy);
272+
# if dd <= dm: return (mm,dd+1,yy);
273+
# d += dm;
274+
# mm=mm+1;
275+
# return 0; # should not happened
276+
def gregorian_day_of_week (yy, mm, dd):
277+
"""Return the day-of-the-week index of gregorian (yy, mm, dd) DATE, 0 for Sunday, 1 for Monday, etc."""
278+
return gregorian_to_absolute (yy,mm, dd) % 7;
279+
# ///////////////////////////////
280+
# some tests for debuging to be removed
281+
282+
def test1():
283+
global __a_const;
284+
__a_const=48
285+
for __a_const in range(0,100): unmatched=0; from_y=1; to_y=4001
286+
for y in range(from_y,to_y):
287+
if hijri_days(y)!=emacs_hijri_days(y): unmatched+=1
288+
print ("%d years (%g %%) unmatched when a=%d", (unmatched, float(float(unmatched)/(to_y-from_y)), __a_const))
289+
__a_const=48
290+
sum=0.0
291+
for y in range(1,4001): sum+=hijri_days(y)
292+
print ("year len=%f ", float(float(sum)/4000.0*100.0))
293+
__a_const=47
294+
sum=0.0
295+
for y in range(1,4001): sum+=hijri_days(y)
296+
print ("year len=%f ", float(float(sum)/4000.0*100.0))
297+
##########################
298+
if __name__ == "__main__":
299+
# conclusion
300+
# 0% for a=16 48 65
301+
# 7% for a=1 31 33 50 80 82 97 99
302+
# 13% for a=14 18 46 63 67 95
303+
# 20% for a=12 29 3 35 52 78 84
304+
# ...
305+
# 73% for a=45 47 49 ..etc.
306+
##########################
307+
__a_const=16
308+
print ("for a=%d", __a_const)
309+
sum=0.0
310+
for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
311+
print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
312+
sum=0.0
313+
for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
314+
print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
315+
316+
__a_const=48
317+
print ("for a=%d", __a_const)
318+
sum=0.0
319+
for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
320+
print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
321+
sum=0.0
322+
for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
323+
print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
324+
325+
__a_const=65
326+
print ("for a=%d", __a_const)
327+
sum=0.0
328+
for y in range(1,4001): sum+= float(hijri_month_days(y,12)==30)
329+
print ("perfect thu-hijja months is %f %% ", float(float(sum)/4000.0*100.0))
330+
sum=0.0
331+
for y in range(1,4001): sum+= float(hijri_month_days(y,9)==30)
332+
print ("perfect Ramadan months is %f %% ", float(float(sum)/4000.0*100.0))
333+
334+
__a_const=48
335+
print ("for a=%d", __a_const)
336+
for m in range(1,13):
337+
sum=0.0
338+
for y in range(1,4001): sum+= float(hijri_month_days(y,m)==30)
339+
print ("perfect %d months is %f %% ", (m,float(float(sum)/4000.0*100.0)))

hijra.pyc

9.8 KB
Binary file not shown.

0 commit comments

Comments
 (0)