/*
|
Zeitrechnung - a class library to determine calendar events
|
Copyright (c) 1984-2022 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 <http://www.gnu.org/licenses/>.
|
*/
|
package de.uhilger.zeitrechnung.kalender;
|
|
import de.uhilger.zeitrechnung.Datum;
|
import de.uhilger.zeitrechnung.Definition;
|
|
/**
|
* Die Klasse ISOKalender implementiert einen Wandler fuer das gregorianische
|
* Kalendersystem gemäß ISO 8601
|
*
|
* @author Ulrich Hilger
|
* @version 2, 1.10.2022
|
*/
|
public class ISOKalender extends BasisKalender implements Wandler {
|
|
public static final long STARTTAG = 1;
|
|
/**
|
* Das Datum im gregorianischen Kalendersystem fuer ein generisches Datum
|
* ermitteln.
|
*
|
* @param generischesDatum Anzahl der Tage zwischen 1. Januar 1 im gregorianischen
|
* Kalender und dem Tag, dessen Datum im gregorianischen Kalendersystem
|
* ermittelt werden soll
|
* @return das Datum im gregorianischen Kalendersystem
|
*/
|
@Override
|
public Datum vonTagen(long generischesDatum) {
|
long jahr = jahrVonTagen(generischesDatum);
|
long tageVorJan1 = generischesDatum - zuTagen(jahr, Definition.JANUAR, 1);
|
int schalttag = generischesDatum < zuTagen(jahr, Definition.MAERZ, 1) ? 0 :
|
(schaltjahr(jahr) ? 1 : 2);
|
int monat = (int) ganzzahlQuotient(12 * (tageVorJan1 + schalttag) + 373, 367);
|
int tag = (int) (generischesDatum - zuTagen(jahr, monat, 1) + 1);
|
return new Datum(jahr, monat, tag);
|
}
|
|
public long jahrVonTagen(long generischesDatum) {
|
long l0 = generischesDatum - STARTTAG;
|
long n400 = ganzzahlQuotient(l0, 146097);
|
long d1 = modulo(l0, 146097);
|
long n100 = ganzzahlQuotient(d1, 36524);
|
long d2 = modulo(d1, 36524);
|
long n4 = ganzzahlQuotient(d2, 1461);
|
long d3 = modulo(d2, 1461);
|
long n1 = ganzzahlQuotient(d3, 365);
|
long year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
|
return n100 == 4 || n1 == 4 ? year : year + 1;
|
}
|
|
/**
|
* Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum
|
* des gregorianischen Kalendersystems und dem Tag liegen, der im
|
* gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
|
*
|
* @param isoDatum das Datum im gregorianischen Kalendersystem
|
*
|
* @return Anzahl Tage, die zwischen dem gegebenen Datum
|
* eines bestimmten Kalendersystems 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 isoDatum) {
|
return zuTagen(isoDatum.getJahr(), isoDatum.getMonat(), isoDatum.getTag());
|
}
|
|
/**
|
* Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum
|
* des gregorianischen Kalendersystems und dem Tag liegen, der im
|
* gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
|
*
|
* @param isoJahr das Jahr im gregorianischen Kalendersystem
|
* @param isoMonat der Monat im gregorianischen Kalendersystem
|
* @param tag der Tag im Monat des gregorianischen Kalendersysem
|
*
|
* @return Anzahl Tage, die zwischen dem gegebenen Datum
|
* eines bestimmten Kalendersystems 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 isoJahr, int isoMonat, int tag) {
|
return STARTTAG - 1
|
+ 365 * (isoJahr - 1)
|
+ ganzzahlQuotient(isoJahr - 1, 4)
|
- ganzzahlQuotient(isoJahr - 1, 100)
|
+ ganzzahlQuotient(isoJahr - 1, 400)
|
+ ganzzahlQuotient(367 * isoMonat - 362, 12)
|
+ (isoMonat <= 2 ? 0 : (schaltjahr(isoJahr) ? -1 : -2))
|
+ tag;
|
}
|
|
private boolean schaltjahr(long isoJahr) {
|
boolean ergebnis = false;
|
if (modulo(isoJahr, 4) == 0) {
|
long n = modulo(isoJahr, 400);
|
if (n != 100 && n != 200 && n != 300) {
|
ergebnis = true;
|
}
|
}
|
return ergebnis;
|
}
|
|
public int letzterDesMonats(long isoJahr, int isoMonat) {
|
switch (isoMonat) {
|
case Definition.FEBRUAR:
|
if (schaltjahr(isoJahr)) {
|
return 29;
|
} else {
|
return 28;
|
}
|
case Definition.APRIL:
|
case Definition.JUNI:
|
case Definition.SEPTEMBER:
|
case Definition.NOVEMBER:
|
return 30;
|
default:
|
return 31;
|
}
|
}
|
}
|