2 package datum;
3
4 import java.util.Calendar;
5 import java.util.Scanner;
6 import java.util.regex.Pattern;
7
8 /**
9 * Datum ist ein Bauplan für Datumswerte.
10 * Version mit vollständiger Konsistenzprüfung
11 * und weiteren Verbesserungen.
12 * Beispielprogramm zur Programmiertechnik 1, Teil 4.
13 * @author H.Drachenfels
14 * @version 28.11.2024
15 */
16 public final class Datum {
17 private final int tag;
18 private final int monat;
19 private final int jahr;
20
21 private Datum(int tag, int monat, int jahr) {
22 this.tag = tag;
23 this.monat = monat;
24 this.jahr = jahr;
25 }
26
27 /**
28 * Fabrikmethode, die ein value object mit dem angegebenen Datum liefert.
29 * @param tag ist der Tag im Monat als Zahl zwischen 1 und 31
30 * @param monat ist der Monat im Jahr als Zahl zwischen 1 und 12
31 * @param jahr ist das Jahr
32 * @return Referenz auf das value object
33 */
34 public static Datum valueOf(int tag, int monat, int jahr) {
35 // Datum pruefen
36 int maxTag;
37 switch (monat) {
38 case 2:
39 if (jahr % 4 == 0 && (jahr % 100 != 0 || jahr % 400 == 0)) {
40 maxTag = 29; // Schaltjahr
41 } else {
42 maxTag = 28; // kein Schaltjahr
43 }
44 break;
45 case 4, 6, 9, 11:
46 maxTag = 30;
47 break;
48 default:
49 maxTag = 31;
50 break;
51 }
52
53 if (tag < 1 || tag > maxTag || monat < 1 || monat > 12) {
54 throw new IllegalArgumentException("ungueltiges Datum");
55 }
56
57 // value object erzeugen
58 return new Datum(tag, monat, jahr);
59 }
60
61 /**
62 * Fabrikmethode, die ein value object mit dem angegebenen Datum liefert.
63 * @param s ist ein datum im ISO-Format (siehe toString)
64 * @return Referenz auf das value object
65 */
66 public static Datum valueOf(String s) {
67 Scanner sc = new Scanner(s);
68 if (!sc.hasNext(FORMAT)) {
69 throw new IllegalArgumentException(s);
70 }
71
72 // value object erzeugen
73 sc.useDelimiter("-");
74 int jahr = sc.nextInt();
75 int monat = sc.nextInt();
76 int tag = sc.nextInt();
77
78 if (s.charAt(0) == '-') {
79 jahr = -jahr;
80 }
81
82 return valueOf(tag, monat, jahr);
83 }
84
85 private static final Pattern FORMAT
86 = Pattern.compile("^-?\\d+-\\d{2}-\\d{2}$");
87
88 /**
89 * Fabrikmethode, die ein value object mit dem aktuellen Datum liefert.
90 * @return Referenz auf das value object
91 */
92 public static Datum heute() {
93 // Systemkalender ablesen
94 Calendar c = Calendar.getInstance();
95
96 // value object erzeugen
97 return new Datum(c.get(Calendar.DAY_OF_MONTH),
98 c.get(Calendar.MONTH) + 1,
99 c.get(Calendar.YEAR));
100 }
101
102 /**
103 * Instanzmethode, die den Tag des Datums liefert.
104 * @return Tag des Datums als Zahl zwischen 1 und 31
105 */
106 public int tag() {
107 return this.tag;
108 }
109
110 /**
111 * Instanzmethode, die den Monat des Datums liefert.
112 * @return Monat des Datums als Zahl zwischen 1 und 12
113 */
114 public int monat() {
115 return this.monat;
116 }
117
118 /**
119 * Instanzmethode, die das Jahr des Datums liefert.
120 * @return Jahr des Datums
121 */
122 public int jahr() {
123 return this.jahr;
124 }
125
126 @Override
127 public String toString() {
128 if (this.jahr < 0) {
129 return String.format("%05d-%02d-%02d",
130 this.jahr, this.monat, this.tag);
131 }
132
133 return String.format("%04d-%02d-%02d",
134 this.jahr, this.monat, this.tag);
135 }
136
137 @Override
138 public boolean equals(Object o) {
139 if (this == o) {
140 return true;
141 }
142
143 if (o instanceof Datum) {
144 Datum that = (Datum) o;
145 return this.tag == that.tag
146 && this.monat == that.monat
147 && this.jahr == that.jahr;
148 }
149
150 return false;
151 }
152
153 @Override
154 public int hashCode() {
155 return (this.jahr << 9) + (this.monat << 5) + this.tag;
156 }
157 }
158