37
37
import java .text .ParseException ;
38
38
import java .text .SimpleDateFormat ;
39
39
import java .util .Date ;
40
+ import java .util .TimeZone ;
40
41
41
42
/**
42
- * {@link CustomDateDeserializer} is a Jackson JSON deserializer for parsing {@link Date} objects
43
+ * {@link CustomDateDeserializer} is a Jackson JSON deserializer for parsing
44
+ * {@link Date} objects
43
45
* from custom date formats used in Xen-API responses.
44
46
*/
45
47
public class CustomDateDeserializer extends StdDeserializer <Date > {
46
48
47
49
/**
48
- * Array of {@link SimpleDateFormat} objects representing the custom date formats
49
- * used in XenServer API responses.
50
+ * Array of {@link SimpleDateFormat} objects representing the date formats
51
+ * used in xen-api responses.
52
+ *
53
+ * RFC-3339 date formats can be returned in either Zulu or time zone agnostic.
54
+ * This list is not an exhaustive list of formats supported by RFC-3339, rather
55
+ * a set of formats that will enable the deserialization of xen-api dates.
56
+ * Formats are listed in order of decreasing precision. When adding
57
+ * to this list, please ensure the order is kept.
50
58
*/
51
- private final SimpleDateFormat [] dateFormatters
52
- = new SimpleDateFormat []{
59
+ private static final SimpleDateFormat [] dateFormatsUtc = {
60
+ // Most commonly returned formats
61
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss'Z'" ),
62
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss'Z'" ),
63
+ new SimpleDateFormat ("ss.SSS" ),
64
+
65
+ // Other
66
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ),
53
67
new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss'Z'" ),
54
- new SimpleDateFormat ("ss.SSS" )
68
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSS'Z'" ),
69
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSS'Z'" ),
70
+
71
+ };
72
+
73
+ /**
74
+ * Array of {@link SimpleDateFormat} objects representing the date formats for
75
+ * local time.
76
+ * These formats are used to parse dates in local time zones.
77
+ * Formats are listed in order of decreasing precision. When adding
78
+ * to this list, please ensure the order is kept.
79
+ */
80
+ private static final SimpleDateFormat [] dateFormatsLocal = {
81
+ // no dashes, no colons
82
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSZZZ" ),
83
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSZZ" ),
84
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSZ" ),
85
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSXXX" ),
86
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSXX" ),
87
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSSX" ),
88
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss.SSS" ),
89
+
90
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssZZZ" ),
91
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssZZ" ),
92
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssZ" ),
93
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssXXX" ),
94
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssXX" ),
95
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmssX" ),
96
+ new SimpleDateFormat ("yyyyMMdd'T'HHmmss" ),
97
+
98
+ // no dashes, with colons
99
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSZZZ" ),
100
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSZZ" ),
101
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSZ" ),
102
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSXXX" ),
103
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSXX" ),
104
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSSX" ),
105
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss.SSS" ),
106
+
107
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssZZZ" ),
108
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssZZ" ),
109
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssZ" ),
110
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssXXX" ),
111
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssXX" ),
112
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ssX" ),
113
+ new SimpleDateFormat ("yyyyMMdd'T'HH:mm:ss" ),
114
+
115
+ // dashes and colons
116
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ" ),
117
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSZZ" ),
118
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSZ" ),
119
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSXXX" ),
120
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSXX" ),
121
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSSX" ),
122
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss.SSS" ),
123
+
124
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssZZZ" ),
125
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssZZ" ),
126
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssZ" ),
127
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssXXX" ),
128
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssXX" ),
129
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ssX" ),
130
+ new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss" ),
55
131
};
56
132
57
133
/**
@@ -62,28 +138,44 @@ public CustomDateDeserializer() {
62
138
}
63
139
64
140
/**
65
- * Constructs a {@link CustomDateDeserializer} instance with the specified value type.
141
+ * Constructs a {@link CustomDateDeserializer} instance with the specified value
142
+ * type.
66
143
*
67
144
* @param t The value type to handle (can be null, handled by superclass)
68
145
*/
69
146
public CustomDateDeserializer (Class t ) {
70
147
super (t );
148
+ var utcTimeZone = TimeZone .getTimeZone ("UTC" );
149
+ for (var utcFormatter : dateFormatsUtc ) {
150
+ utcFormatter .setTimeZone (utcTimeZone );
151
+ }
71
152
}
72
153
154
+ private static
155
+
73
156
/**
74
157
* Deserializes a {@link Date} object from the given JSON parser.
75
158
*
76
- * @param jsonParser The JSON parser containing the date value to deserialize
159
+ * @param jsonParser The JSON parser containing the date value to
160
+ * deserialize
77
161
* @param deserializationContext The deserialization context
78
162
* @return The deserialized {@link Date} object
79
163
* @throws IOException if an I/O error occurs during deserialization
80
164
*/
81
- @ Override
82
- public Date deserialize (JsonParser jsonParser , DeserializationContext deserializationContext ) throws IOException {
165
+ @ Override public Date deserialize (JsonParser jsonParser , DeserializationContext deserializationContext )
166
+ throws IOException {
167
+ var text = jsonParser .getText ();
168
+ for (SimpleDateFormat formatter : dateFormatsUtc ) {
169
+ try {
170
+ return formatter .parse (text );
171
+ } catch (ParseException e ) {
172
+ // ignore
173
+ }
174
+ }
83
175
84
- for (SimpleDateFormat formatter : dateFormatters ) {
176
+ for (SimpleDateFormat formatter : dateFormatsLocal ) {
85
177
try {
86
- return formatter .parse (jsonParser . getText () );
178
+ return formatter .parse (text );
87
179
} catch (ParseException e ) {
88
180
// ignore
89
181
}
0 commit comments