Bestimmung der Zeitpunkte von Ereignissen
ulrich
2023-03-23 d20d989f5495492f1258c8313db7c19b429111a3
commit | author | age
66d68b 1 /*
U 2   Zeitrechnung - a class library to determine calendar events
3   Copyright (c) 1984-2022 Ulrich Hilger, http://uhilger.de
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU Affero General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package de.uhilger.zeitrechnung.kalender;
19
20 import de.uhilger.zeitrechnung.Datum;
21 import de.uhilger.zeitrechnung.Definition;
22
23 /**
24  * Die Klasse ISOKalender implementiert einen Wandler fuer das gregorianische 
25  * Kalendersystem gem&auml;&szlig; ISO 8601 
26  * 
27  * @author Ulrich Hilger
28  * @version 2, 1.10.2022
29  */
30 public class ISOKalender extends BasisKalender implements Wandler {
31
32   public static final long STARTTAG = 1;
33   
34   /**
35    * Das Datum im gregorianischen Kalendersystem fuer ein generisches Datum 
36    * ermitteln.
37    * 
38    * @param generischesDatum Anzahl der Tage zwischen 1. Januar 1 im gregorianischen 
39    * Kalender und dem Tag, dessen Datum im gregorianischen Kalendersystem 
40    * ermittelt werden soll
41    * @return das Datum im gregorianischen Kalendersystem
42    */
43   @Override
44   public Datum vonTagen(long generischesDatum) {
45     long jahr = jahrVonTagen(generischesDatum);
46     long tageVorJan1 = generischesDatum - zuTagen(jahr, Definition.JANUAR, 1);
47     int schalttag = generischesDatum < zuTagen(jahr, Definition.MAERZ, 1) ? 0 :
48             (schaltjahr(jahr) ? 1 : 2);
49     int monat = (int) ganzzahlQuotient(12 * (tageVorJan1 + schalttag) + 373, 367);
50     int tag = (int) (generischesDatum - zuTagen(jahr, monat, 1) + 1);
51     return new Datum(jahr, monat, tag);
52   }
53   
54   public long jahrVonTagen(long generischesDatum) {
55     long l0 = generischesDatum - STARTTAG;
56     long n400 = ganzzahlQuotient(l0, 146097);
57     long d1 = modulo(l0, 146097);
58     long n100 = ganzzahlQuotient(d1, 36524);
59     long d2 = modulo(d1, 36524);
60     long n4 = ganzzahlQuotient(d2, 1461);
61     long d3 = modulo(d2, 1461);
62     long n1 = ganzzahlQuotient(d3, 365);
63     long year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
64     return n100 == 4 || n1 == 4 ? year : year + 1;
65   }
66
67   /**
68    * Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum 
69    * des gregorianischen Kalendersystems und dem Tag liegen, der im
70    * gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
71    * 
72    * @param isoDatum das Datum im gregorianischen Kalendersystem
73    * 
74    * @return Anzahl Tage, die zwischen dem gegebenen Datum 
75    * eines bestimmten Kalendersystems und dem Tag liegen, der im 
76    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist. 
77    * Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird 
78    * eine negative Zahl zurueckgegeben. 
79    */  
80   @Override
81   public long zuTagen(Datum isoDatum) {
82     return zuTagen(isoDatum.getJahr(), isoDatum.getMonat(), isoDatum.getTag());
83   }
84
85   /**
86    * Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum 
87    * des gregorianischen Kalendersystems und dem Tag liegen, der im
88    * gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.
89    * 
90    * @param isoJahr das Jahr im gregorianischen Kalendersystem
91    * @param isoMonat der Monat im gregorianischen Kalendersystem
92    * @param tag der Tag im Monat des gregorianischen Kalendersysem
93    * 
94    * @return Anzahl Tage, die zwischen dem gegebenen Datum 
95    * eines bestimmten Kalendersystems und dem Tag liegen, der im 
96    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist. 
97    * Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird 
98    * eine negative Zahl zurueckgegeben. 
99    */  
100   @Override
101   public long zuTagen(long isoJahr, int isoMonat, int tag) {
102     return STARTTAG - 1
103             + 365 * (isoJahr - 1)
104             + ganzzahlQuotient(isoJahr - 1, 4)
105             - ganzzahlQuotient(isoJahr - 1, 100)
106             + ganzzahlQuotient(isoJahr - 1, 400)
107             + ganzzahlQuotient(367 * isoMonat - 362, 12)
108             + (isoMonat <= 2 ? 0 : (schaltjahr(isoJahr) ? -1 : -2))
109             + tag;
110   }
111
112   private boolean schaltjahr(long isoJahr) {
113     boolean ergebnis = false;
114     if (modulo(isoJahr, 4) == 0) {
115       long n = modulo(isoJahr, 400);
116       if (n != 100 && n != 200 && n != 300) {
117         ergebnis = true;
118       }
119     }
120     return ergebnis;
121   }
122   
123   public int letzterDesMonats(long isoJahr, int isoMonat) {
124     switch (isoMonat) {
125       case Definition.FEBRUAR:
126         if (schaltjahr(isoJahr)) {
127           return 29;
128         } else {
129           return 28;
130         }
131       case Definition.APRIL:
132       case Definition.JUNI:
133       case Definition.SEPTEMBER:
134       case Definition.NOVEMBER:
135         return 30;
136       default:
137         return 31;
138     }
139   }  
140 }