Re: glib time functions



* Robert Brady (robert suse co uk) wrote at 22:08 on 29/11/00:
> On Wed, 29 Nov 2000, David Benson wrote:
> 
> > I have code for rfc 822, rfc 850 and ansi c's asctime format
> > date/time printers/parsers -- but they just use `struct tm'
> > and a time zone offset, rather than inventing their own structure
> > as would be the glib policy.
> > 
> > They might be helpful though and I'd be happy to adapt them to
> > GDateTime or whatever if that is invented.
> 
> I plan to investigate the possibility of having support for non-Gregorian
> calendars.  Some calendars, like the Islamic calendar are very difficult
> due to them being non-determenistic, but other calendars, e.g. the
> pre-Gregorian western calendar, and the Persian calendar are nice enough
> that we can support them.

Dude!!! You're kind of wrong :) Islamic calendar is difficult and is not based
on an "algorithm" - but there /IS/ an implementation for it :)

I have functions for Islamic calendar support  in a small sample
application that I have. It was basically coded to convert
absolute -> islamic, islamic -> absoute, time_t -> islamic, and islamic ->
time_t. 

JWZ pointed to me to this PDF file that explained calendaring algorithms.
Basically though it was showing/explaining the lisp calendaring functions in
Emacs. Emacs/lisp obviously do not have the time_t -> islamic, and islamic ->
time_t functions

I basically just converted them into C. And it works :) Today is the 3rd day
of Ramadan (9th month I believe), and checking my application:
time_t 975543023 (RIGHT NOW!) in islamic is: 9 3 1421

(that time_t value is Wed, Nov. 29 sometime around 10:10 PM) (note: this is in
month, day, year) format.

Anyway, enough of my shameless plug ;) 

Honestly, I thought this implementation would be "semi-broken" because the
calendar is based on the /SIGHTING/ of the moon and not any algorithmic
approach. In fact, it is broken in some places, for example in Iran (and some
other country), on Tues Nov. 29, it was 1st of Ramadan (9th month). In most
other Islamic countries 1st of Ramadan was on Mon Nov. 28 (which my functions
remarkably get right).

I think the Islamic calendars are somehow "auto-correcting", because all the
Islamic calendars I know stay "in-sync" (so next year, Iran and all other
Islamic countries will determine the Moon sighting at the exact same time
(instead of Iran doing it one day later).

Also, some years, the muslim world is "divided" on the ramadan times. By
definition, the Islamic calendar can never be 100% accurate, but it can be
damn close (as proved by the lisp algorithm that was devised).

I have made one premise though (which I believe is safe to make) and that is
we don't determine new days based on sunset/sunrise (too difficult, not
essential, not used in the Islamic world anyway). 

I'm attaching the cal-islamic.c and Makefile below because they are very slow.
It is very rough. I will also attach a notes.txt file that may provide some
useful notes (although not much).

I wanted to use these functions as a basis for working on an Islamic 'view'
for Evolution's calendar, but the project was dropped.

If people want this for glib, I can try to work up a patch (if you tell me
what kind of functions you want (i.e. do you want just the conversion
functions? Should we add other things? etc.))

Regards,
Ali

/* Islamic calendar utility functions
 *
 * Copyright (C) 1999 Ali Abdin <aliabdin aucegypt edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
#include <stdlib.h>

#include <glib.h>
#include <time.h>


static int
last_day_of_gregorian_month (int month, int year) {
	int monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	/* Last day of gregorian month during year */
	if ((month == 2) && ((year % 4) == 0) && ((year % 400) != 100) &&
	    ((year % 400) != 200) && ((year % 400)  != 300))
		return 29;
	else
		return monthdays[month-1];
}	

#if 1 
glong
absolute_from_gregorian (int month, int day, int year) {
	/* WARNING: This uses 1/1/1 == '1' as the absolute date */
	/* Absolute date given gregorian */
	long absolutedays, monthdays;
	int m;
        long dayyears;
	div_t tmpdiv;

	absolutedays = day; /* Days so far this month */
	monthdays = 0;
	for (m = 1; m < month; m++)
		monthdays =
		       monthdays + last_day_of_gregorian_month (m, year);
		/* Days in prior months /this/ year */
	dayyears = 365.0 * (year-1); /* days in prior years */
/*	g_print ("dayyears is: %d\n", dayyears); */
	tmpdiv = div (year-1, 4);
	dayyears = dayyears + tmpdiv.quot;
/*	g_print ("dayyears is: %d\n", dayyears); */
       		/* add julian leap days in prior years */
	tmpdiv = div(year-1, 100);
	dayyears = dayyears - (tmpdiv.quot); /* minus prior century
						       years */
	tmpdiv = div(year-1, 400);
	dayyears = dayyears + (tmpdiv.quot); /* Add back the years
						       divisible by 400 */
/*	g_print ("days is: %d\ndayyears is: %d\n",absolutedays,dayyears); */
	return (absolutedays + dayyears + monthdays);
}
#endif


static gboolean
islamic_leap_year (gint year) {
	/* Given Islamic year return TRUE if it is a leap year */
	if ((((year * 11) + 14) % 30) < 11)
		return TRUE;
	else
		return FALSE;
}

static gint
last_day_of_islamic_month (gint month, gint year) {
	/* Given the islamic month/year it returns the size of the month */
	
	if (((month % 2) == 1) || ((month == 12) && islamic_leap_year (year)))
		return 30; /* Odd months and 12th month of a leap year are
			      both 30 days */
	else
		return 29;
}

static glong
absolute_from_islamic (gint month, gint day, gint year) {
	glong absolutedays;
	div_t tmpdiv;

	/* Add days so far this month + days so far this year excluding leap
	 * years */
	absolutedays = day + (29 * (month-1));
	tmpdiv = div (month,2);
	absolutedays = absolutedays + tmpdiv.quot; /* Number of days this year
						    */
	absolutedays = absolutedays + ((year-1) * 354); /* non-leap days in
							   prior years */
	tmpdiv = div(((11 * year) + 3), 30);
	absolutedays = absolutedays + 
		             tmpdiv.quot; /* leap days in prior years */
//	g_print ("absolutedays is %d\n",absolutedays);
	/* you have to subtract an extra '1' since you pass over '0' */
		absolutedays = absolutedays + (-492148) - 1;
	/* The above is the 'magic' number since '0' is the epoch (1/1/1970)
	 * and 7/19/622 is the first day of the Islamic calendar (-492148 or
	 * 492,148 days before the epoch)
	 */
	return absolutedays;
}

static void
islamic_from_absolute (glong absolute, gint *month, gint *day, gint *year) {
	
	if (absolute < -492148) {
		/* This is before Islam */
		*month = 0;
		*day = 0;
		*year = 0;
	}
	else {
		gint y,m;
		gint tmpsum = 0;
		div_t tmpdiv;
		glong tmplong; /* We need a temp 'long' value for the day */
		
		/* Approximate the islamic year from the absolute date */
		tmpdiv = div ( absolute - (-492148), 355);
		*year = tmpdiv.quot;
		for (y = tmpdiv.quot;
		     absolute >= absolute_from_islamic (1, 1, y+1);
		     y++) {
			tmpsum = tmpsum++;
		}	/* Forward search for the exact islamic year */
		*year = *year + tmpsum;
		tmpsum = 0;
		for (m = 1;
	  	     absolute > 
		     	absolute_from_islamic (m, 
				last_day_of_islamic_month (m, *year), *year);
		     m++) {
			tmpsum = tmpsum++;
		}
		*month = 1 + tmpsum;
		/* Calculate the days by subtraction */
		tmplong = absolute - (1 - (absolute_from_islamic (*month, 1, *year)));
		*day = absolute + (1 - (absolute_from_islamic (*month, 1, *year)));
	}
}


time_t
time_from_islamic_date (int imonth, int iday, int iyear)
{
	struct tm tm;
	glong totaldays;
	gint addyears, month, day;
	gint y;

	memset (&tm, 0, sizeof (tm));
	
	totaldays = absolute_from_islamic (imonth, iday, iyear);
//	if (totaldays > 0) {
		

		addyears = (gint) totaldays / 366;
		g_print ("addyears is: %d\n",addyears);
		for (y = addyears; totaldays >= absolute_from_gregorian (1,1, 1970 + y) ;y++);

		addyears = y; /* Number of years to add to 1970 */

		for (month = 1;
			totaldays > (absolute_from_gregorian (month,
         	       	     last_day_of_gregorian_month (month, addyears + 1970), addyears + 1970)) -
			absolute_from_gregorian (1,1,1970);
					month++);
		g_print ("totaldays = %d - %d - %d;\n",totaldays, absolute_from_gregorian (month,1, 1970 + addyears), absolute_from_gregorian (1,1,1970));

		day = totaldays + (1 - (absolute_from_gregorian (month, 1, 1970 + addyears) - 
					absolute_from_gregorian (1,2,1970)));

		g_print ("addyears is %d\nmonth is %d\nday is %d\n",addyears, month, day);

		tm.tm_year = 70 + addyears;
		tm.tm_mon = month-1;
		tm.tm_mday = day;
//	}

	return mktime (&tm);
}

void
islamic_from_time (time_t time, gint *month, gint *day, gint *year) {
	glong absolute;

	absolute = (gint) time / (60*60*24); /* Turn from seconds into days */

	islamic_from_absolute (absolute, month, day, year);
}


int
main (int argc, char **argv) {
	gint month,day,year,x;
	gboolean failed = FALSE;
	time_t temptime;

	g_print ("1/1/1970 is %d and it is a %d\n", absolute_from_gregorian (1,1,1970), absolute_from_gregorian (1,1,1970) % 7);
	g_print ("07/19/622 is %d it is a %d\n", absolute_from_gregorian (7,19,622), absolute_from_gregorian (7,19,622) % 7);
	g_print ("4/6/2000 is %d\n", absolute_from_gregorian (4,6,2000));
	g_print ("4/13/2000 is %d\n", absolute_from_gregorian (4,13,2000));
	g_print ("Islamic date 1/1/1 is %d in absolute time_t\n", absolute_from_islamic (1,1,1));
	g_print ("Islamic date 1/2/1 is %d in absolute time_t\n", absolute_from_islamic (1,2,1));
	g_print ("Islamic date 1/1/1421 is %d in absolute time_t\n", absolute_from_islamic (1,1,1421));
	islamic_from_absolute (-492148,&month,&day,&year);
	g_print ("Given absolute -492148 the islam stuff is: %d %d %d\n",month,day,year);
	islamic_from_absolute(11053,&month,&day,&year);
	g_print ("Given absolute 11053 the islam stuff is: %d %d %d\n",month,day,year);
	islamic_from_absolute (-492147,&month,&day,&year);
        g_print ("Given absolute -492147 the islam stuff is: %d %d %d\n",month,day,year);
	islamic_from_absolute (11060,&month,&day,&year);
	g_print ("Given absolute 11060 the islam stuff is: %d %d %d\n",month,day,year);	
	islamic_from_absolute (-492149,&month,&day,&year);
        g_print ("Given absolute -492149 the islam stuff is: %d %d %d\n",month,day,year);

	temptime = time_from_islamic_date (1,1,1421);
	g_print ("time_from_islamic_date(1,1,1421) is %d\n", temptime);
	islamic_from_time (temptime, &month,&day, &year);
	g_print ("time_t %d in islamic is: %d %d %d\n",temptime,month,day,year);

	temptime = time_from_islamic_date (1,8,1421);
	g_print ("time_from_islamic_date(1,8,1421) is %d\n", temptime);
	islamic_from_time (temptime, &month,&day, &year);
	g_print ("time_t %d in islamic is: %d %d %d\n",temptime,month,day,year);
	islamic_from_time (time (NULL), &month,&day,&year);
	g_print ("time_t %d (RIGHT NOW!) in islamic is: %d %d %d\n",time(NULL),month,day,year);

		
/*	g_print ("Running Islamic Stress Test: ");
	for (x = -492148; x <= 492148; x++) {
		islamic_from_absolute(x, &month, &day, &year);
		if ((absolute_from_islamic (month,day,year)) != x)
			failed = TRUE;
	}
	if (failed)
		g_print ("FAILED");
	else
		g_print ("PASSED"); */
	return 0;
}
# Makefile

CC = gcc
OBJS = cal-islamic.o
CFLAGS = -I/usr/include -I/usr/lib/glib/include
LDLIBS = -L/usr/lib -lglib

all: main

clean: 
	rm -f *.o cal-islamic

cal-islamic.o:cal-islamic.c
	$(CC) -c $(CFLAGS) $^ -o $@ -Wall

main:cal-islamic.o
	$(CC) $(LDLIBS) $(CFLAGS) $^ -o cal-islamic -Wall

.SUFFIXES: .c .o

.PHONE: install
Using absolute date as 1/1/1:
the epoch is: 1/1/1970 is 719163 - it is a thursday 
1st day of Islamic calendar is: 07/19/622 is 227015 - it is a friday

epoch is the 'absolute' date and will be referenced as '0'. That means we subtract 719163 from both sides as follows:

     719163              227015
   - 719163              719163
---------------------------------
     0                   -492148


So the epoch is '0' and the 1st day of the Islamic calendar is -492148.

The months are as follows:
(1) Muharram	30 days		(7) Rajab		30 days
(2) Safar	29 days		(8) Sha'ban		29 days
(3) Rabi I	30 days		(9) Ramadan		30 days
(4) Rabi II	29 days		(10) Shawwal		29 days
(5) Jumada I	30 days		(11) Dhu al-Qada 	30 days
(6) Jumada II	30 days		(12) Dhu al-Hijjah	29 {30} days

* This is a very 'convoluted' way in order to approximate the Islamic year (to give an average month of 29.530555 days).

An Islamic leap year occurs (giving 30 days to Dhu al-Hijjah)  if and only if (11y +14) mod 30 < 11 (yes its obfuscated - but according to the book i'm working from thats how it is)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]