libhdate
Version:
A pure Javascript implementation of libhdate
417 lines (352 loc) • 12.4 kB
text/typescript
/* libhdate - Hebrew calendar library
*
* Copyright (C) 2015 Yaacov Zamir <kobi.zamir@gmail.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
export class Hdate {
/** The number of day in the hebrew month (1..31). */
public hd_day:number = 0;
/** The number of the hebrew month 1..14 (1 - tishre, 13 - adar 1, 14 - adar 2). */
public hd_mon:number = 0;
/** The number of the hebrew year. */
public hd_year:number = 0;
/** The number of the day in the month. (1..31) */
public gd_day:number = 0;
/** The number of the month 1..12 (1 - jan). */
public gd_mon:number = 0;
/** The number of the year. */
public gd_year:number = 0;
/** The day of the week 1..7 (1 - sunday). */
public hd_dw:number = 0;
/** The length of the year in days. */
public hd_size_of_year:number = 0;
/** The week day of Hebrew new year. */
public hd_new_year_dw:number = 0;
/** The number type of year. */
public hd_year_type:number = 0;
/** The Julian day number */
public hd_jd:number = 0;
/** The number of days passed since 1 tishrey */
public hd_days:number = 0;
/** The number of weeks passed since 1 tishrey */
public hd_weeks:number = 0;
/**
Days since bet (?) Tishrey 3744
Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2015
@param hebrew_year The Hebrew year
@returns number of days since 3,1,3744
*/
private
hdate_days_from_3744 (hebrew_year:number):number
{
/** constants */
const HOUR = 1080;
const DAY = 24*HOUR;
const WEEK = 7*DAY;
const MONTH = DAY+HOUR*12+793; /* Tikun for regular month */
var years_from_3744:number = 0;
var molad_3744:number = 0;
var leap_months:number = 0;
var leap_left:number = 0;
var months:number = 0;
var parts:number = 0;
var days:number = 0;
var parts_left_in_week:number = 0;
var parts_left_in_day:number = 0;
var week_day:number = 0;
/* Start point for calculation is Molad new year 3744 (16BC) */
years_from_3744 = hebrew_year - 3744;
molad_3744 = (1 + 6)*HOUR+779; /* Molad 3744 + 6 hours in parts */
/* Time in months */
leap_months = Math.floor((years_from_3744 * 7 + 1) / 19); /* number of leap months */
leap_left = (years_from_3744 * 7 + 1) % 19; /* Months left of leap cycle */
months = years_from_3744 * 12 + leap_months; /* Total number of months */
/* Time in parts and days */
parts = months * MONTH + molad_3744; /* Molad This year + Molad 3744 - corections */
days = months * 28 + Math.floor(parts / DAY) - 2; /* 28 days in month + corections */
/* Time left for round date in corections */
parts_left_in_week = parts % WEEK; /* 28 % 7 = 0 so only corections counts */
parts_left_in_day = parts % DAY;
week_day = Math.floor(parts_left_in_week / DAY);
/* Special cases of Molad Zaken */
if ((leap_left < 12 && week_day == 3
&& parts_left_in_day >= (9 + 6)*HOUR+204) ||
(leap_left < 7 && week_day == 2
&& parts_left_in_day >= (15 + 6)*HOUR+589))
{
days++; week_day++;
}
/* ADU */
if (week_day == 1 || week_day == 4 || week_day == 6)
{
days++;
}
return days;
}
/**
Size of Hebrew year in days
@param hebrew_year The Hebrew year
@returns Size of Hebrew year
*/
private
hdate_get_size_of_hebrew_year (hebrew_year:number):number
{
return this.hdate_days_from_3744 (hebrew_year + 1) -
this.hdate_days_from_3744 (hebrew_year);
}
/**
Return Hebrew year type based on size and first week day of year.
year type | year length | Tishery 1 day of week
| 1 | 353 | 2
| 2 | 353 | 7
| 3 | 354 | 3
| 4 | 354 | 5
| 5 | 355 | 2
| 6 | 355 | 5
| 7 | 355 | 7
| 8 | 383 | 2
| 9 | 383 | 5
|10 | 383 | 7
|11 | 384 | 3
|12 | 385 | 2
|13 | 385 | 5
|14 | 385 | 7
@param size_of_year Length of year in days
@param new_year_dw First week day of year
@returns A number for year type (1..14)
*/
private
hdate_get_year_type (size_of_year:number, new_year_dw:number)
{
/* Only 14 combinations of size and week day are posible */
var year_types:number[] =
[1, 0, 0, 2, 0, 3, 4, 0, 5, 0, 6, 7,
8, 0, 9, 10, 0, 11, 0, 0, 12, 0, 13, 14];
var offset:number = 0;
/* convert size and first day to 1..24 number */
/* 2,3,5,7 . 1,2,3,4 */
/* 353, 354, 355, 383, 384, 385 . 0, 1, 2, 3, 4, 5 */
offset = Math.floor((new_year_dw + 1) / 2);
offset = offset + 4 * ((size_of_year % 10 - 3) + Math.floor(size_of_year / 10 - 35));
/* some combinations are imposible */
return year_types[offset - 1];
}
/**
Compute Julian day from Gregorian day, month and year
Algorithm from the wikipedia's julian_day
Yaacov Zamir
@param day Day of month 1..31
@param month Month 1..12
@param year Year in 4 digits e.g. 2001
@returns The julian day number
*/
private
hdate_gdate_to_jd (day:number, month:number, year:number):number
{
var a:number = 0;
var y:number = 0;
var m:number = 0;
var jdn:number = 0;
a = Math.floor((14 - month) / 12);
y = year + 4800 - a;
m = month + 12 * a - 3;
jdn = day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
return jdn;
}
/**
Compute Julian day from Hebrew day, month and year
Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2005
@param day Day of month 1..31
@param month Month 1..14 (13 - Adar 1, 14 - Adar 2)
@param year Hebrew year in 4 digits e.g. 5753
@returns The julian day number
*/
private
hdate_hdate_to_jd (day:number, month:number, year:number):number
{
var length_of_year:number = 0;
var jd:number = 0;
var days_from_3744:number = 0;
/* Adjust for leap year */
if (month == 13)
{
month = 6;
}
if (month == 14)
{
month = 6;
day += 30;
}
/* Calculate days since 1,1,3744 */
days_from_3744 = this.hdate_days_from_3744 (year);
day = days_from_3744 + Math.floor((59 * (month - 1) + 1) / 2) + day;
/* length of year */
length_of_year = this.hdate_days_from_3744 (year + 1) - days_from_3744;
/* Special cases for this year */
if (length_of_year % 10 > 4 && month > 2) /* long Heshvan */
day++;
if (length_of_year % 10 < 4 && month > 3) /* short Kislev */
day--;
if (length_of_year > 365 && month > 6) /* leap year */
day += 30;
/* adjust to julian */
jd = day + 1715118;
return jd;
}
/**
Converting from the Julian day to the Gregorian day
Algorithm from 'Julian and Gregorian Day numbers' by Peter Meyer
Yaacov Zamir ( Algorithm, Henry F. Fliegel and Thomas C. Van Flandern ,1968)
@param jd Julian day
@returns date as d,m,y array
d Return Day of month 1..31
m Return Month 1..12
y Return Year in 4 digits e.g. 2001
*/
private
hdate_jd_to_gdate (jd:number):number[]
{
var l:number, n:number, l:number, i:number, j:number, d:number, m:number, y:number;
l = jd + 68569;
n = Math.floor((4 * l) / 146097);
l = l - Math.floor((146097 * n + 3) / 4);
i = Math.floor((4000 * (l + 1)) / 1461001); /* that's 1,461,001 */
l = l - Math.floor((1461 * i) / 4) + 31;
j = Math.floor((80 * l) / 2447);
d = l - Math.floor((2447 * j) / 80);
l = Math.floor(j / 11);
m = j + 2 - (12 * l);
y = 100 * (n - 49) + i + l; /* that's a lower-case L */
return [d, m, y];
}
/**
Converting from the Julian day to the Hebrew day
Amos Shapir 1984 (rev. 1985, 1992) Yaacov Zamir 2003-2008
@param jd Julian day
@returns date as d,m,y array
d Return Day of month 1..31
m Return Month 1..14 (13 - Adar 1, 14 - Adar 2)
y Return Year in 4 digits e.g. 5761
*/
private
hdate_jd_to_hdate (jd:number):number[]
{
var days:number = 0;
var size_of_year:number = 0;
var jd_tishrey1:number = 0;
var jd_tishrey1_next_year:number = 0;
var day:number;
var month:number;
var year:number;
/* calculate Gregorian date */
[day, month, year] = this.hdate_jd_to_gdate (jd);
/* Guess Hebrew year is Gregorian year + 3760 */
year = year + 3760;
jd_tishrey1 = this.hdate_days_from_3744 (year) + 1715119;
jd_tishrey1_next_year = this.hdate_days_from_3744 (year + 1) + 1715119;
/* Check if computed year was underestimated */
if (jd_tishrey1_next_year <= jd)
{
year = year + 1;
jd_tishrey1 = jd_tishrey1_next_year;
jd_tishrey1_next_year = this.hdate_days_from_3744 (year + 1) + 1715119;
}
size_of_year = jd_tishrey1_next_year - jd_tishrey1;
/* days into this year, first month 0..29 */
days = jd - jd_tishrey1;
/* last 8 months allways have 236 days */
if (days >= (size_of_year - 236)) /* in last 8 months */
{
days = days - (size_of_year - 236);
month = Math.floor(days * 2 / 59);
day = days - Math.floor((month * 59 + 1) / 2) + 1;
month = month + 4 + 1;
/* if leap */
if (size_of_year > 355 && month <=6)
month = month + 8;
}
else /* in 4-5 first months */
{
/* Special cases for this year */
if (size_of_year % 10 > 4 && days == 59) /* long Heshvan (day 30 of Heshvan) */
{
month = 1;
day = 30;
}
else if (size_of_year % 10 > 4 && days > 59) /* long Heshvan */
{
month = Math.floor((days - 1) * 2 / 59);
day = days - Math.floor((month * 59 + 1) / 2);
}
else if (size_of_year % 10 < 4 && days > 87) /* short kislev */
{
month = Math.floor((days + 1) * 2 / 59);
day = days - Math.floor((month * 59 + 1) / 2) + 2;
}
else /* regular months */
{
month = Math.floor(days * 2 / 59);
day = days - Math.floor((month * 59 + 1) / 2) + 1;
}
month = month + 1;
}
return [day, month, year, jd_tishrey1, jd_tishrey1_next_year];
}
/**
compute date structure from the Julian day number
@param jd Julian day number
*/
public
set_jd (jd:number):void
{
var jd_tishrey1:number, jd_tishrey1_next_year:number;
[this.gd_day, this.gd_mon, this.gd_year] = this.hdate_jd_to_gdate (jd);
[this.hd_day, this.hd_mon, this.hd_year, jd_tishrey1, jd_tishrey1_next_year] = this.hdate_jd_to_hdate (jd);
this.hd_dw = (jd + 1) % 7 + 1;
this.hd_size_of_year = jd_tishrey1_next_year - jd_tishrey1;
this.hd_new_year_dw = (jd_tishrey1 + 1) % 7 + 1;
this.hd_year_type = this.hdate_get_year_type (this.hd_size_of_year , this.hd_new_year_dw);
this.hd_jd = jd;
this.hd_days = jd - jd_tishrey1 + 1;
this.hd_weeks = Math.floor(((this.hd_days - 1) + (this.hd_new_year_dw - 1)) / 7) + 1;
return;
}
/**
compute date structure from the Gregorian date
@param d Day of month 1..31
@param m Month 1..12
@param y Year in 4 digits e.g. 2001
*/
public
set_gdate (d:number, m:number, y:number):void
{
var jd:number;
jd = this.hdate_gdate_to_jd (d, m, y);
this.set_jd (jd);
}
/**
compute date structure from the Hebrew date
@param d Day of month 1..31
@param m Month 1..14 (13 - Adar 1, 14 - Adar 2)
@param y Year in 4 digits e.g. 5743
*/
public
set_hdate (d:number, m:number, y:number):void
{
var jd:number;
jd = this.hdate_hdate_to_jd (d, m, y);
this.set_jd (jd);
}
}