/* 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 . */ 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; } } }