1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.datamodel.common;
20
21 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
22 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
23 import static java.time.temporal.ChronoField.YEAR;
24
25 import java.time.ZoneOffset;
26 import java.time.chrono.IsoChronology;
27 import java.time.format.DateTimeFormatter;
28 import java.time.format.DateTimeFormatterBuilder;
29 import java.time.format.ResolverStyle;
30 import java.time.temporal.ChronoField;
31 import java.util.Locale;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34
35
36
37
38
39
40
41
42
43 public final class MCRISO8601FormatChooser {
44
45 public static final DateTimeFormatter YEAR_FORMAT = ISODateTimeFormat.year();
46
47 public static final DateTimeFormatter YEAR_MONTH_FORMAT = ISODateTimeFormat.yearMonth();
48
49 public static final DateTimeFormatter COMPLETE_FORMAT = ISODateTimeFormat.date();
50
51 public static final DateTimeFormatter COMPLETE_HH_MM_FORMAT = ISODateTimeFormat.dateHourMinute();
52
53 public static final DateTimeFormatter COMPLETE_HH_MM_SS_FORMAT = ISODateTimeFormat.dateTimeNoMillis();
54
55 public static final DateTimeFormatter COMPLETE_HH_MM_SS_SSS_FORMAT = ISODateTimeFormat.dateTime();
56
57 private static final Pattern MILLI_CHECK_PATTERN = Pattern.compile("\\.\\d{4,}\\+");
58
59 private static final boolean USE_UTC = true;
60
61
62
63
64
65
66
67
68
69
70
71
72
73 public static DateTimeFormatter getFormatter(String isoString, MCRISO8601Format isoFormat) {
74 DateTimeFormatter df;
75 if (isoFormat != null) {
76 df = getFormatterForFormat(isoFormat);
77 } else if (isoString != null && isoString.length() != 0) {
78 df = getFormatterForDuration(isoString);
79 } else {
80 df = COMPLETE_HH_MM_SS_SSS_FORMAT;
81 }
82 if (USE_UTC) {
83 df = df.withZone(ZoneOffset.UTC);
84 }
85 return df;
86 }
87
88 private static DateTimeFormatter getFormatterForFormat(MCRISO8601Format isoFormat) {
89 switch (isoFormat) {
90 case YEAR:
91 return YEAR_FORMAT;
92 case YEAR_MONTH:
93 return YEAR_MONTH_FORMAT;
94 case COMPLETE:
95 return COMPLETE_FORMAT;
96 case COMPLETE_HH_MM:
97 return COMPLETE_HH_MM_FORMAT;
98 case COMPLETE_HH_MM_SS:
99 return COMPLETE_HH_MM_SS_FORMAT;
100 case COMPLETE_HH_MM_SS_SSS:
101 return COMPLETE_HH_MM_SS_SSS_FORMAT;
102 case YEAR_ERA:
103 return YEAR_FORMAT;
104 case YEAR_MONTH_ERA:
105 return YEAR_MONTH_FORMAT;
106 case COMPLETE_ERA:
107 return COMPLETE_FORMAT;
108 case COMPLETE_HH_MM_ERA:
109 return COMPLETE_HH_MM_FORMAT;
110 case COMPLETE_HH_MM_SS_ERA:
111 return COMPLETE_HH_MM_SS_FORMAT;
112 case COMPLETE_HH_MM_SS_SSS_ERA:
113 return COMPLETE_HH_MM_SS_SSS_FORMAT;
114 default:
115 return COMPLETE_HH_MM_SS_SSS_FORMAT;
116 }
117 }
118
119 private static DateTimeFormatter getFormatterForDuration(String isoString) {
120 boolean test = false;
121 switch (isoString.length()) {
122 case 1:
123 case 2:
124 case 3:
125 case 4:
126 case 5:
127 return YEAR_FORMAT;
128 case 6:
129 case 7:
130 case 8:
131 return YEAR_MONTH_FORMAT;
132 case 10:
133 case 11:
134 return COMPLETE_FORMAT;
135 case 17:
136 test = true;
137 case 22:
138 if (test || !isoString.endsWith("Z")) {
139
140 return COMPLETE_HH_MM_FORMAT;
141 }
142
143 return COMPLETE_HH_MM_SS_SSS_FORMAT;
144 case 20:
145 case 25:
146 return COMPLETE_HH_MM_SS_FORMAT;
147 case 23:
148 case 24:
149 case 27:
150 case 28:
151 case 29:
152 return COMPLETE_HH_MM_SS_SSS_FORMAT;
153 default:
154 return COMPLETE_HH_MM_SS_SSS_FORMAT;
155 }
156 }
157
158
159
160
161
162
163
164
165
166 public static String cropSecondFractions(String isoString) {
167 Matcher matcher = MILLI_CHECK_PATTERN.matcher(isoString);
168 boolean result = matcher.find();
169 if (result) {
170 return matcher.replaceFirst(isoString.substring(matcher.start(), matcher.start() + 4) + "+");
171 }
172 return isoString;
173 }
174
175 private static class ISODateTimeFormat {
176
177 public static DateTimeFormatter year() {
178 return DateTimeFormatter.ofPattern("uuuu", Locale.ROOT);
179 }
180
181 public static DateTimeFormatter yearMonth() {
182 return DateTimeFormatter.ofPattern("uuuu-MM", Locale.ROOT);
183 }
184
185 public static DateTimeFormatter date() {
186 return DateTimeFormatter.ISO_LOCAL_DATE;
187 }
188
189 public static DateTimeFormatter dateHourMinute() {
190 return new DateTimeFormatterBuilder().parseCaseInsensitive()
191 .appendValue(YEAR, 4)
192 .appendLiteral('-')
193 .appendValue(MONTH_OF_YEAR, 2)
194 .appendLiteral('-')
195 .appendValue(DAY_OF_MONTH, 2)
196 .appendLiteral('T')
197 .appendValue(ChronoField.HOUR_OF_DAY, 2)
198 .appendLiteral(':')
199 .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
200 .appendOffset("+HH:MM", "Z")
201 .toFormatter(Locale.ROOT)
202 .withChronology(IsoChronology.INSTANCE)
203 .withResolverStyle(ResolverStyle.STRICT);
204 }
205
206 public static DateTimeFormatter dateTimeNoMillis() {
207 return new DateTimeFormatterBuilder().parseCaseInsensitive()
208 .appendValue(YEAR, 4)
209 .appendLiteral('-')
210 .appendValue(MONTH_OF_YEAR, 2)
211 .appendLiteral('-')
212 .appendValue(DAY_OF_MONTH, 2)
213 .appendLiteral('T')
214 .appendValue(ChronoField.HOUR_OF_DAY, 2)
215 .appendLiteral(':')
216 .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
217 .appendLiteral(':')
218 .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
219 .appendOffset("+HH:MM", "Z")
220 .toFormatter(Locale.ROOT)
221 .withChronology(IsoChronology.INSTANCE)
222 .withResolverStyle(ResolverStyle.STRICT);
223 }
224
225 public static DateTimeFormatter dateTime() {
226 return new DateTimeFormatterBuilder().parseCaseInsensitive()
227 .appendValue(YEAR, 4)
228 .appendLiteral('-')
229 .appendValue(MONTH_OF_YEAR, 2)
230 .appendLiteral('-')
231 .appendValue(DAY_OF_MONTH, 2)
232 .appendLiteral('T')
233 .appendValue(ChronoField.HOUR_OF_DAY, 2)
234 .appendLiteral(':')
235 .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
236 .appendLiteral(':')
237 .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
238 .appendFraction(ChronoField.NANO_OF_SECOND, 3, 3, true)
239 .appendOffset("+HH:MM", "Z")
240 .toFormatter(Locale.ROOT)
241 .withChronology(IsoChronology.INSTANCE)
242 .withResolverStyle(ResolverStyle.STRICT);
243 }
244 }
245
246 }