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 12.8.2019
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:
46 case 6:
47 case 9:
48 case 11:
49 maxTag = 30;
50 break;
51 default:
52 maxTag = 31;
53 break;
54 }
55
56 if (tag < 1 || tag > maxTag || monat < 1 || monat > 12) {
57 throw new IllegalArgumentException("ungueltiges Datum");
58 }
59
60 // value object erzeugen
61 return new Datum(tag, monat, jahr);
62 }
63
64 /**
65 * Fabrikmethode, die ein value object mit dem angegebenen Datum liefert.
66 * @param s ist ein datum im ISO-Format (siehe toString)
67 * @return Referenz auf das value object
68 */
69 public static Datum valueOf(String s) {
70 Scanner sc = new Scanner(s);
71 if (!sc.hasNext(FORMAT)) {
72 throw new IllegalArgumentException(s);
73 }
74
75 // value object erzeugen
76 sc.useDelimiter("-");
77 int jahr = sc.nextInt();
78 int monat = sc.nextInt();
79 int tag = sc.nextInt();
80
81 if (s.charAt(0) == '-') {
82 jahr = -jahr;
83 }
84
85 return valueOf(tag, monat, jahr);
86 }
87
88 private static final Pattern FORMAT
89 = Pattern.compile("^-?\\d+-\\d{2}-\\d{2}$");
90
91 /**
92 * Fabrikmethode, die ein value object mit dem aktuellen Datum liefert.
93 * @return Referenz auf das value object
94 */
95 public static Datum heute() {
96 // Systemkalender ablesen
97 Calendar c = Calendar.getInstance();
98
99 // value object erzeugen
100 return new Datum(c.get(Calendar.DAY_OF_MONTH),
101 c.get(Calendar.MONTH) + 1,
102 c.get(Calendar.YEAR));
103 }
104
105 /**
106 * Instanzmethode, die den Tag des Datums liefert.
107 * @return Tag des Datums als Zahl zwischen 1 und 31
108 */
109 public int getTag() {
110 return this.tag;
111 }
112
113 /**
114 * Instanzmethode, die den Monat des Datums liefert.
115 * @return Monat des Datums als Zahl zwischen 1 und 12
116 */
117 public int getMonat() {
118 return this.monat;
119 }
120
121 /**
122 * Instanzmethode, die das Jahr des Datums liefert.
123 * @return Jahr des Datums
124 */
125 public int getJahr() {
126 return this.jahr;
127 }
128
129 @Override
130 public String toString() {
131 if (this.jahr < 0) {
132 return String.format("%05d-%02d-%02d",
133 this.jahr, this.monat, this.tag);
134 }
135
136 return String.format("%04d-%02d-%02d",
137 this.jahr, this.monat, this.tag);
138 }
139
140 @Override
141 public boolean equals(Object o) {
142 if (this == o) {
143 return true;
144 }
145
146 if (o instanceof Datum) {
147 Datum that = (Datum) o;
148 return this.tag == that.tag
149 && this.monat == that.monat
150 && this.jahr == that.jahr;
151 }
152
153 return false;
154 }
155
156 @Override
157 public int hashCode() {
158 return (this.jahr << 9) + (this.monat << 5) + this.tag;
159 }
160 }
161