1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.datatype.adapter;
28
29 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
30
31 import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter;
32 import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
33 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
34
35 import java.time.ZonedDateTime;
36 import java.time.format.DateTimeParseException;
37 import java.util.List;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40
41 import edu.umd.cs.findbugs.annotations.NonNull;
42
43 public class DateWithTZAdapter
44 extends AbstractDataTypeAdapter<ZonedDateTime, IDateItem> {
45 @NonNull
46 private static final List<String> NAMES = ObjectUtils.notNull(
47 List.of(
48 "date-with-timezone"));
49 private static final Pattern DATE_TIMEZONE = Pattern.compile("^("
50 + "^(?:(?:2000|2400|2800|(?:19|2[0-9](?:0[48]|[2468][048]|[13579][26])))-02-29)"
51 + "|(?:(?:(?:19|2[0-9])[0-9]{2})-02-(?:0[1-9]|1[0-9]|2[0-8]))"
52 + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[13578]|10|12)-(?:0[1-9]|[12][0-9]|3[01]))"
53 + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30))"
54 + ")"
55 + "(Z|[+-][0-9]{2}:[0-9]{2})$");
56
57 DateWithTZAdapter() {
58 super(ZonedDateTime.class);
59 }
60
61 @Override
62 public List<String> getNames() {
63 return NAMES;
64 }
65
66 @Override
67 public JsonFormatTypes getJsonRawType() {
68 return JsonFormatTypes.STRING;
69 }
70
71 @SuppressWarnings("null")
72 @Override
73 public ZonedDateTime parse(String value) {
74 Matcher matcher = DATE_TIMEZONE.matcher(value);
75 if (!matcher.matches()) {
76 throw new IllegalArgumentException("Invalid date: " + value);
77 }
78 String parseValue = String.format("%sT00:00:00%s", matcher.group(1), matcher.group(2));
79 try {
80 return ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(parseValue));
81 } catch (DateTimeParseException ex) {
82 throw new IllegalArgumentException(ex.getLocalizedMessage(), ex);
83 }
84 }
85
86 @SuppressWarnings("null")
87 @Override
88 public String asString(Object value) {
89 return DateFormats.DATE_WITH_TZ.format((ZonedDateTime) value);
90 }
91
92 @SuppressWarnings("null")
93 @Override
94 public ZonedDateTime copy(Object obj) {
95 return ZonedDateTime.from((ZonedDateTime) obj);
96 }
97
98 @Override
99 public Class<IDateItem> getItemClass() {
100 return IDateItem.class;
101 }
102
103 @Override
104 public IDateItem newItem(Object value) {
105 ZonedDateTime item = toValue(value);
106 return IDateItem.valueOf(item);
107 }
108 }