|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2003 by Jonathan Singer *
|
|
|
|
* jsinger@leeta.net *
|
|
|
|
* Calendar routines from Hebrew Calendar by Frank Yellin *
|
|
|
|
* *
|
|
|
|
* 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. *
|
|
|
|
***************************************************************************/
|
|
|
|
#include "converter.h"
|
|
|
|
#include <tdelocale.h>
|
|
|
|
|
|
|
|
Converter::Converter()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Converter::~Converter()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
long Converter::absolute_from_gregorian(int year, int month, int day)
|
|
|
|
{
|
|
|
|
int xyear, day_number;
|
|
|
|
|
|
|
|
xyear = year - 1;
|
|
|
|
day_number = day + 31 * (month - 1);
|
|
|
|
if (month > 2)
|
|
|
|
{
|
|
|
|
day_number -= (23 + (4 * month)) / 10;
|
|
|
|
if (gregorian_leap_year_p(year))
|
|
|
|
day_number++;
|
|
|
|
}
|
|
|
|
return day_number + /* the day number within the current year */
|
|
|
|
365L * xyear + /* days in prior years */
|
|
|
|
(xyear / 4) + /* Julian leap years */
|
|
|
|
(-(xyear / 100)) + /* deduct century years */
|
|
|
|
(xyear / 400); /* add Gregorian leap years */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given a Hebrew date, calculate the number of days since
|
|
|
|
* January 0, 0001, Gregorian
|
|
|
|
*/
|
|
|
|
long Converter::absolute_from_hebrew(int year, int month, int day)
|
|
|
|
{
|
|
|
|
long sum = day + hebrew_elapsed_days(year) - 1373429L;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (month < 7)
|
|
|
|
{
|
|
|
|
int months = hebrew_months_in_year(year);
|
|
|
|
|
|
|
|
for (i = 7; i <= months; ++i)
|
|
|
|
sum += hebrew_month_length(year, i);
|
|
|
|
for (i = 1; i < month; ++i)
|
|
|
|
sum += hebrew_month_length(year, i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 7; i < month; ++i)
|
|
|
|
sum += hebrew_month_length(year, i);
|
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given an absolute date, calculate the gregorian date */
|
|
|
|
void
|
|
|
|
Converter::gregorian_from_absolute(long date, int *yearp,
|
|
|
|
int *monthp, int *dayp)
|
|
|
|
{
|
|
|
|
int year, month, day;
|
|
|
|
|
|
|
|
for (year = date / 366;
|
|
|
|
date >= absolute_from_gregorian(year + 1, 1, 1); ++year) ;
|
|
|
|
for (month = 1;
|
|
|
|
(month <= 11)
|
|
|
|
&& (date >= absolute_from_gregorian(year, 1 + month, 1));
|
|
|
|
++month ) ;
|
|
|
|
day = 1 + date - absolute_from_gregorian(year, month, 1);
|
|
|
|
*yearp = year;
|
|
|
|
*monthp = month;
|
|
|
|
*dayp = day;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given an absolute date, calculate the Hebrew date */
|
|
|
|
void
|
|
|
|
Converter::hebrew_from_absolute(long date, int *yearp, int *monthp,
|
|
|
|
int *dayp)
|
|
|
|
{
|
|
|
|
int year, month, day, gyear, gmonth, gday, months;
|
|
|
|
|
|
|
|
gregorian_from_absolute(date, &gyear, &gmonth, &gday);
|
|
|
|
year = gyear + 3760;
|
|
|
|
while (date >= absolute_from_hebrew(1 + year, 7, 1))
|
|
|
|
year++;
|
|
|
|
months = hebrew_months_in_year(year);
|
|
|
|
for (month = 7;
|
|
|
|
date > absolute_from_hebrew(year, month,
|
|
|
|
hebrew_month_length(year, month));
|
|
|
|
month = 1 + (month % months)) ;
|
|
|
|
day = 1 + date - absolute_from_hebrew(year, month, 1);
|
|
|
|
*yearp = year;
|
|
|
|
*monthp = month;
|
|
|
|
*dayp = day;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Number of months in a Hebrew year */
|
|
|
|
int Converter::hebrew_months_in_year(int year)
|
|
|
|
{
|
|
|
|
if (hebrew_leap_year_p(year))
|
|
|
|
return 13;
|
|
|
|
else
|
|
|
|
return 12;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum
|
|
|
|
{ Nissan =
|
|
|
|
1, Iyar, Sivan, Tamuz, Ab, Elul, Tishrei, Cheshvan, Kislev, Tevet,
|
|
|
|
Shvat, Adar, AdarII, AdarI = 12
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{ January =
|
|
|
|
1, February, March, April, May, June, July, August, September,
|
|
|
|
October, November, December
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Number of days in a Hebrew month */
|
|
|
|
int Converter::hebrew_month_length(int year, int month)
|
|
|
|
{
|
|
|
|
switch (month)
|
|
|
|
{
|
|
|
|
case Tishrei:
|
|
|
|
case Shvat:
|
|
|
|
case Nissan:
|
|
|
|
case Sivan:
|
|
|
|
case Ab:
|
|
|
|
return 30;
|
|
|
|
|
|
|
|
case Tevet:
|
|
|
|
case Iyar:
|
|
|
|
case Tamuz:
|
|
|
|
case Elul:
|
|
|
|
case AdarII:
|
|
|
|
return 29;
|
|
|
|
|
|
|
|
case Cheshvan:
|
|
|
|
// 29 days, unless it's a long year.
|
|
|
|
if ((hebrew_year_length(year) % 10) == 5)
|
|
|
|
return 30;
|
|
|
|
else
|
|
|
|
return 29;
|
|
|
|
|
|
|
|
case Kislev:
|
|
|
|
// 30 days, unless it's a short year.
|
|
|
|
if ((hebrew_year_length(year) % 10) == 3)
|
|
|
|
return 29;
|
|
|
|
else
|
|
|
|
return 30;
|
|
|
|
|
|
|
|
case Adar:
|
|
|
|
// Adar (non-leap year) has 29 days. Adar I has 30 days.
|
|
|
|
if (hebrew_leap_year_p(year))
|
|
|
|
return 30;
|
|
|
|
else
|
|
|
|
return 29;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Number of days in a Julian or gregorian month */
|
|
|
|
int
|
|
|
|
Converter::secular_month_length(int year,
|
|
|
|
int month /*, bool julianp */ )
|
|
|
|
{
|
|
|
|
switch (month)
|
|
|
|
{
|
|
|
|
case January:
|
|
|
|
case March:
|
|
|
|
case May:
|
|
|
|
case July:
|
|
|
|
case August:
|
|
|
|
case October:
|
|
|
|
case December:
|
|
|
|
return 31;
|
|
|
|
case April:
|
|
|
|
case June:
|
|
|
|
case September:
|
|
|
|
case November:
|
|
|
|
return 30;
|
|
|
|
case February:
|
|
|
|
if (gregorian_leap_year_p(year))
|
|
|
|
return 29;
|
|
|
|
else
|
|
|
|
return 28;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is it a Leap year in the gregorian calendar */
|
|
|
|
bool Converter::gregorian_leap_year_p(int year)
|
|
|
|
{
|
|
|
|
if ((year % 4) != 0)
|
|
|
|
return 0;
|
|
|
|
if ((year % 400) == 0)
|
|
|
|
return 1;
|
|
|
|
if ((year % 100) == 0)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Is it a leap year in the Jewish Calendar */
|
|
|
|
bool Converter::hebrew_leap_year_p(int year)
|
|
|
|
{
|
|
|
|
switch (year % 19)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 3:
|
|
|
|
case 6:
|
|
|
|
case 8:
|
|
|
|
case 11:
|
|
|
|
case 14:
|
|
|
|
case 17:
|
|
|
|
return 1;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the number of days from 1 Tishrei 0001 to the beginning of the given year.
|
|
|
|
* Since this routine gets called frequently with the same year arguments, we cache
|
|
|
|
* the most recent values.
|
|
|
|
*/
|
|
|
|
#define MEMORY 5
|
|
|
|
long Converter::hebrew_elapsed_days(int year)
|
|
|
|
{
|
|
|
|
static int saved_year[MEMORY] = { -1, -1, -1, -1, -1 };
|
|
|
|
static long saved_value[MEMORY];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MEMORY; ++i)
|
|
|
|
if (year == saved_year[i])
|
|
|
|
return saved_value[i];
|
|
|
|
for (i = 0; i < MEMORY-1; ++i) {
|
|
|
|
saved_year[i] = saved_year[1 + i];
|
|
|
|
saved_value[i] = saved_value[1 + i];
|
|
|
|
}
|
|
|
|
saved_year[MEMORY - 1] = year;
|
|
|
|
saved_value[MEMORY - 1] = hebrew_elapsed_days2(year);
|
|
|
|
return saved_value[MEMORY - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
long Converter::hebrew_elapsed_days2(int year)
|
|
|
|
{
|
|
|
|
long prev_year = year - 1;
|
|
|
|
long months_elapsed = 235L * (prev_year / 19) /* months in complete cycles so far */
|
|
|
|
+ 12L * (prev_year % 19) /* regular months in this cycle */
|
|
|
|
+ (((prev_year % 19) * 7 + 1) / 19); /* leap months this cycle */
|
|
|
|
long parts_elapsed = 5604 + 13753 * months_elapsed;
|
|
|
|
long day = 1 + 29 * months_elapsed + parts_elapsed / 25920;
|
|
|
|
long parts = parts_elapsed % 25920;
|
|
|
|
int weekday = (day % 7);
|
|
|
|
long alt_day = ((parts >= 19440)
|
|
|
|
|| (weekday == 2 && (parts >= 9924)
|
|
|
|
&& !hebrew_leap_year_p(year)) || (weekday == 1
|
|
|
|
&& (parts >=
|
|
|
|
16789)
|
|
|
|
&&
|
|
|
|
hebrew_leap_year_p
|
|
|
|
(prev_year)))
|
|
|
|
? day + 1 : day;
|
|
|
|
switch (alt_day % 7)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 3:
|
|
|
|
case 5:
|
|
|
|
return 1 + alt_day;
|
|
|
|
default:
|
|
|
|
return alt_day;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Number of days in the given Hebrew year */
|
|
|
|
int Converter::hebrew_year_length(int year)
|
|
|
|
{
|
|
|
|
return hebrew_elapsed_days(1 + year) - hebrew_elapsed_days(year);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill in the DateResult structure based on the given secular date */
|
|
|
|
void
|
|
|
|
Converter::SecularToHebrewConversion(int syear, int smonth,
|
|
|
|
int sday,
|
|
|
|
struct DateResult *result)
|
|
|
|
{
|
|
|
|
int hyear, hmonth, hday;
|
|
|
|
long absolute;
|
|
|
|
|
|
|
|
absolute = absolute_from_gregorian(syear, smonth, sday);
|
|
|
|
|
|
|
|
hebrew_from_absolute(absolute, &hyear, &hmonth, &hday);
|
|
|
|
|
|
|
|
result->year = hyear;
|
|
|
|
result->month = hmonth;
|
|
|
|
result->day = hday;
|
|
|
|
finish_up(absolute, hyear, hmonth, syear, smonth, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill in the DateResult structure based on the given Hebrew date */
|
|
|
|
void
|
|
|
|
Converter::HebrewToSecularConversion(int hyear, int hmonth,
|
|
|
|
int hday,
|
|
|
|
struct DateResult *result)
|
|
|
|
{
|
|
|
|
int syear, smonth, sday;
|
|
|
|
long absolute;
|
|
|
|
|
|
|
|
absolute = absolute_from_hebrew(hyear, hmonth, hday);
|
|
|
|
gregorian_from_absolute(absolute, &syear, &smonth, &sday);
|
|
|
|
result->year = hyear;
|
|
|
|
result->month = hmonth;
|
|
|
|
result->day = hday;
|
|
|
|
finish_up(absolute, hyear, hmonth, syear, smonth, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is common code for filling up the DateResult structure */
|
|
|
|
void
|
|
|
|
Converter::finish_up(long absolute, int hyear, int hmonth,
|
|
|
|
int syear, int smonth,
|
|
|
|
struct DateResult *result)
|
|
|
|
{
|
|
|
|
result->hebrew_month_length = hebrew_month_length(hyear, hmonth);
|
|
|
|
result->secular_month_length = secular_month_length(syear, smonth);
|
|
|
|
result->hebrew_leap_year_p = hebrew_leap_year_p(hyear);
|
|
|
|
result->secular_leap_year_p = gregorian_leap_year_p(syear);
|
|
|
|
result->kvia = (hebrew_year_length(hyear) % 10) - 3;
|
|
|
|
// absolute is -1 on 1/1/0001 Julian
|
|
|
|
result->day_of_week = (7 + absolute) % 7;
|
|
|
|
result->hebrew_day_number =
|
|
|
|
absolute - absolute_from_hebrew(hyear, 7, 1) + 1;
|
|
|
|
|
|
|
|
}
|