/*
Zeitrechnung - a class library to determine calendar events
Copyright (c) 1984-2023 Ulrich Hilger, http://uhilger.de
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
package de.uhilger.zeitrechnung.kalender;
import de.uhilger.zeitrechnung.Datum;
import de.uhilger.zeitrechnung.Definition;
/**
* Die Klasse HebraeischerKalender dient zu Umwandlung von generischem
* Datum zu hebraeischem Datum und umgekehrt.
*
* @author Ulrich Hilger
*/
public class HebraeischerKalender extends BasisKalender implements Wandler {
public static final int NISAN = 1;
public static final int IYYAR = 2;
public static final int SIVAN = 3;
public static final int TAMMUZ = 4;
public static final int AV = 5;
public static final int ELUL = 6;
public static final int TISCHRI = 7;
public static final int MARESHVAN = 8;
public static final int KISLEV = 9;
public static final int TEVET = 10;
public static final int SHEVAT = 11;
public static final int ADAR = 12;
public static final int ADAR2 = 13;
/**
*
Monatsnamen
*
* z.B.
*
* String nameTischri = HebraeischerKalender.monatsnamen[HebraeischerKalender.TISCHRI];
*
*/
public static final String[] monatsnamen = new String[] {
"Nisan",
"Iyyar",
"Sivan",
"Tammuz",
"Av",
"Elul",
"Tishri",
"Marheshvan",
"Kislev",
"Tevet",
"Shevat",
"Adar",
"Adar 2"};
/**
* Das generische Datum des Starttages des hebraeischen Kalenders
* wird im Konstruktor gesetzt.
*/
private final long STARTTAG;
/**
* Ein Objekt der Klasse HebraeischerKalender erzeugen
*
* Der hebraeische Kalender beginnt mit 1 Tischri 1 anno mundi (A.M.).
* Historiker datieren diesen Tag mit Montag 7. September -3760 des
* gregorianischen Kalenders (3761 v. u. Z.), was
* gleichbedeutend ist mit dem 7. Oktober 3761 v.u.Z. (vor unserer
* Zeit; engl. bce, before common era) des julianischen
* Kalenders. Der Datumswechsel vollzieht sich im julianischen und
* gregorianischen Kalender um Mitternacht, weshalb nach hebraeischer
* Tageszaehlung unter Beruecksichtigung des Datumswechsels am Vorabend
* bereits der 7. Oktober des julianischen bzw. der 7. September des
* gregorianischen Kalenders begonnen hatte.
*/
public HebraeischerKalender() {
super();
JulianischerKalender j = new JulianischerKalender();
STARTTAG = j.zuTagen(j.BCE(3761), Definition.OKTOBER, 7);
}
/* ------- Schnittstelle Wandler -------------- */
/**
* Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum
* des hebraeischen Kalendersystems und dem Tag liegen, der im
* Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
*
* @param jahr das Jahr im hebraeischen Kalendersystem
* @param monat der Monat im hebraeischen Kalendersystem
* @param tag der Tag im hebraeischen Kalendersysem
*
* @return Anzahl Tage, die zwischen dem gegebenen Datum
* und dem Tag liegen, der im
* Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
* Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird
* eine negative Zahl zurueckgegeben.
*/
@Override
public long zuTagen(long jahr, int monat, int tag) {
long datum =
neujahr(jahr)
+ tag - 1;
if(monat < TISCHRI) {
for(int m = TISCHRI; m <= letzterMonatImJahr(jahr); ++m)
datum += letzterTagImMonat(m, jahr);
for(int m = NISAN; m < monat; ++m)
datum += letzterTagImMonat(m, jahr);
} else {
for(int m = TISCHRI; m < monat; ++m)
datum += letzterTagImMonat(m, jahr);
}
return datum;
}
/**
* Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum
* des hebraeischen Kalendersystems und dem Tag liegen, der im
* Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
*
* @param hDatum das Datum im hebraeischen Kalendersystem
*
* @return Anzahl Tage, die zwischen dem gegebenen Datum
* und dem Tag liegen, der im
* Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
* Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird
* eine negative Zahl zurueckgegeben.
*/
@Override
public long zuTagen(Datum hDatum) {
return zuTagen(hDatum.getJahr(), hDatum.getMonat(), hDatum.getTag());
}
/**
* Das Datum im hebraeischen Kalendersystem fuer ein generisches Datum
* ermitteln.
*
* @param tage Anzahl der Tage zwischen 1. Januar 1 im gregorianischen
* Kalender und dem Tag, dessen Datum im betreffenden Kalendersystem
* ermittelt werden soll
* @return das Datum im hebraeischen Kalendersystem
*/
@Override
public Datum vonTagen(long tage) {
long annaeherung = 1 + ganzzahlQuotient(tage - STARTTAG, 35975351d/98496);
long jahr;
for(jahr = annaeherung - 1; neujahr(jahr) <= tage; ++jahr);
jahr--;
int monat;
int start = tage < zuTagen(jahr, 1, 1) ? TISCHRI : NISAN;
for(monat = start; !(tage <= zuTagen(jahr, monat, letzterTagImMonat(monat, jahr))); ++monat);
int tag = (int)(1 + tage - zuTagen(jahr, monat, 1));
return new Datum(jahr, monat, tag);
}
/* ------ Besondere Tage des hebraeischen Kalenders ----- */
/*
Die Feiertage sind hier noch vermischt mit unterschiedlichen Verschieberegeln.
TODO: Diese noch in einen separaten Verschiebe-Mechanismus ueberfuehren
*/
public long passah(long isoJahr) {
ISOKalender w = new ISOKalender();
long hYear = isoJahr - w.jahrVonTagen(STARTTAG);
return zuTagen(hYear, NISAN, 15);
}
public long purim(long isoJahr) {
ISOKalender w = new ISOKalender();
long hYear = isoJahr - w.jahrVonTagen(STARTTAG);
int lastMonth = letzterMonatImJahr(hYear);
return zuTagen(hYear, lastMonth, 14);
}
public long taAnitEsther(long isoJahr) {
long purimDate = purim(isoJahr);
return wochentagVonGenerisch(purimDate) == Definition.SONNTAG ? purimDate - 3 : purimDate - 1;
}
public long tishahBeAv(long isoJahr) {
ISOKalender w = new ISOKalender();
long hYear = isoJahr - w.jahrVonTagen(STARTTAG);
long ninthOfAv = zuTagen(hYear, 5, 9);
return wochentagVonGenerisch(ninthOfAv) == Definition.SAMSTAG ? ninthOfAv + 1 : ninthOfAv;
}
public long yomHaZikkaron(long isoJahr) {
ISOKalender w = new ISOKalender();
long hYear = isoJahr - w.jahrVonTagen(STARTTAG);
long iyar4 = zuTagen(hYear, 2, 4);
return Definition.MITTWOCH < wochentagVonGenerisch(iyar4) ? tagVor(iyar4, Definition.MITTWOCH) : iyar4;
}
/* ------ Besonderheiten des hebraeischen Kalenders ----- */
public long tageszaehlung(long hJahr) {
long monate = ganzzahlQuotient(235 * hJahr - 234, 19);
double teile = 12084 + 13753d * monate;
long day = 29 * monate + ganzzahlQuotient(teile, 25920);
return modulo(3 * (day + 1), 7) < 3 ? day + 1 : day;
}
public long neujahr(long hJahr) {
return STARTTAG
+ tageszaehlung(hJahr)
+ neujahrVerzug(hJahr);
}
public int neujahrVerzug(long hJahr) {
long ny0 = tageszaehlung(hJahr - 1);
long ny1 = tageszaehlung(hJahr);
long ny2 = tageszaehlung(hJahr + 1);
if(ny2 - ny1 == 356)
return 2;
else if(ny1 - ny0 == 382)
return 1;
else
return 0;
}
public boolean schaltjahr(long hJahr) {
return modulo(1 + 7 * hJahr, 19) < 7;
}
public int letzterMonatImJahr(long hJahr) {
return schaltjahr(hJahr) ? 13 : 12;
}
public int letzterTagImMonat(int hMonat, long hJahr) {
return ( (hMonat == 2 || hMonat == 4 || hMonat == 6 || hMonat == 10 || hMonat == 13)
|| (hMonat == 12 && !schaltjahr(hJahr))
|| (hMonat == 8 && !marheshvanLang(hJahr))
|| (hMonat == 9 && kislevKurz(hJahr)) ) ? 29 : 30;
}
public boolean marheshvanLang(long hJahr) {
int days = tageImJahr(hJahr);
return days == 355 || days == 385;
}
public boolean kislevKurz(long hJahr) {
int tage = tageImJahr(hJahr);
return tage == 353 || tage == 383;
}
public int tageImJahr(long hYear) {
return (int)(neujahr(hYear + 1) - neujahr(hYear));
}
}