Skip to content

Commit 8fda858

Browse files
committed
Fix #1744
1 parent 6ad4b6d commit 8fda858

File tree

3 files changed

+77
-33
lines changed

3 files changed

+77
-33
lines changed

release-notes/VERSION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Project: jackson-databind
1111
(reported by ctytgat@github)
1212
#1730: InvalidFormatException` for `JsonToken.VALUE_EMBEDDED_OBJECT`
1313
(reported by zigzago@github)
14+
#1744: StdDateFormat: add option to serialize timezone offset with a colon
15+
(contributed by Bertrand R)
1416
#1745: StdDateFormat: accept and truncate millis larger than 3 digits
1517
(suggested by Bertrand R)
1618
#1749: StdDateFormat: performance improvement of '_format(..)' method

src/main/java/com/fasterxml/jackson/databind/util/StdDateFormat.java

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,10 @@ public class StdDateFormat
145145

146146
/**
147147
* Whether the TZ offset must be formatted with a colon between hours and minutes ({@code HH:mm} format)
148+
*
149+
* @since 2.9.1
148150
*/
149-
private boolean _formatTzOffsetWithColumn = false;
151+
private boolean _tzSerializedWithColon = false;
150152

151153
/*
152154
/**********************************************************
@@ -164,11 +166,19 @@ public StdDateFormat(TimeZone tz, Locale loc) {
164166
_locale = loc;
165167
}
166168

167-
protected StdDateFormat(TimeZone tz, Locale loc, Boolean lenient, boolean formatTzOffsetWithColumn) {
169+
protected StdDateFormat(TimeZone tz, Locale loc, Boolean lenient) {
170+
this(tz, loc, lenient, false);
171+
}
172+
173+
/**
174+
* @since 2.9.1
175+
*/
176+
protected StdDateFormat(TimeZone tz, Locale loc, Boolean lenient,
177+
boolean formatTzOffsetWithColon) {
168178
_timezone = tz;
169179
_locale = loc;
170180
_lenient = lenient;
171-
_formatTzOffsetWithColumn = formatTzOffsetWithColumn;
181+
_tzSerializedWithColon = formatTzOffsetWithColon;
172182
}
173183

174184
public static TimeZone getDefaultTimeZone() {
@@ -186,31 +196,61 @@ public StdDateFormat withTimeZone(TimeZone tz) {
186196
if ((tz == _timezone) || tz.equals(_timezone)) {
187197
return this;
188198
}
189-
return new StdDateFormat(tz, _locale, _lenient, _formatTzOffsetWithColumn);
199+
return new StdDateFormat(tz, _locale, _lenient, _tzSerializedWithColon);
190200
}
191201

202+
/**
203+
* "Mutant factory" method that will return an instance that uses specified
204+
* {@code Locale}:
205+
* either {@code this} instance (if setting would not change), or newly
206+
* constructed instance with different {@code Locale} to use.
207+
*/
192208
public StdDateFormat withLocale(Locale loc) {
193209
if (loc.equals(_locale)) {
194210
return this;
195211
}
196-
return new StdDateFormat(_timezone, loc, _lenient, _formatTzOffsetWithColumn);
212+
return new StdDateFormat(_timezone, loc, _lenient, _tzSerializedWithColon);
197213
}
198214

199215
/**
216+
* "Mutant factory" method that will return an instance that has specified leniency
217+
* setting: either {@code this} instance (if setting would not change), or newly
218+
* constructed instance.
219+
*
200220
* @since 2.9
201221
*/
202222
public StdDateFormat withLenient(Boolean b) {
203223
if (_equals(b, _lenient)) {
204224
return this;
205225
}
206-
return new StdDateFormat(_timezone, _locale, b, _formatTzOffsetWithColumn);
226+
return new StdDateFormat(_timezone, _locale, b, _tzSerializedWithColon);
207227
}
208228

229+
/**
230+
* "Mutant factory" method that will return an instance that has specified
231+
* handling of colon when serializing timezone (timezone either written
232+
* like {@code +0500} or {@code +05:00}):
233+
* either {@code this} instance (if setting would not change), or newly
234+
* constructed instance with desired setting for colon inclusion.
235+
*<p>
236+
* NOTE: does NOT affect deserialization as colon is optional accepted
237+
* but not required -- put another way, either serialization is accepted
238+
* by this class.
239+
*
240+
* @since 2.9.1
241+
*/
242+
public StdDateFormat withColonInTimeZone(boolean b) {
243+
if (_tzSerializedWithColon == b) {
244+
return this;
245+
}
246+
return new StdDateFormat(_timezone, _locale, _lenient, b);
247+
}
248+
209249
@Override
210250
public StdDateFormat clone() {
211251
// Although there is that much state to share, we do need to
212252
// orchestrate a bit, mostly since timezones may be changed
213-
return new StdDateFormat(_timezone, _locale, _lenient, _formatTzOffsetWithColumn);
253+
return new StdDateFormat(_timezone, _locale, _lenient, _tzSerializedWithColon);
214254
}
215255

216256
/**
@@ -287,26 +327,23 @@ public boolean isLenient() {
287327
}
288328

289329
/**
290-
* If {@code true}), format TZ offset with a colon ({@code HH:mm}).
291-
*
292-
* @param formatTzOffsetWithColumn whether to include a colon in the formatted TZ
293-
*/
294-
public void setFormatTzOffsetWithColumn(boolean formatTzOffsetWithColumn) {
295-
this._formatTzOffsetWithColumn = formatTzOffsetWithColumn;
296-
}
297-
298-
/**
299-
* Return {@code true} if a colon is to be inserted between the hours and minutes
300-
* of the TZ offset.
301-
*
330+
* Accessor for checking whether this instance would include colon
331+
* within timezone serialization or not: if {code true}, timezone offset
332+
* is serialized like {@code -06:00}; if {code false} as {@code -0600}.
333+
*<p>
334+
* NOTE: only relevant for serialization (formatting), as deserialization
335+
* (parsing) always accepts optional colon but does not require it, regardless
336+
* of this setting.
337+
*
302338
* @return {@code true} if a colon is to be inserted between the hours and minutes
303-
* of the TZ offset
339+
* of the TZ offset when serializing as String; otherwise {@code false}
340+
*
341+
* @since 2.9.1
304342
*/
305-
public boolean isFormatTzOffsetWithColumn() {
306-
return _formatTzOffsetWithColumn;
307-
}
308-
309-
343+
public boolean isColonIncludedInTimeZone() {
344+
return _tzSerializedWithColon;
345+
}
346+
310347
/*
311348
/**********************************************************
312349
/* Public API, parsing
@@ -425,15 +462,15 @@ protected void _format(TimeZone tz, Locale loc, Date date,
425462
int minutes = Math.abs((offset / (60 * 1000)) % 60);
426463
buffer.append(offset < 0 ? '-' : '+');
427464
pad2(buffer, hours);
428-
if( _formatTzOffsetWithColumn ) {
465+
if( _tzSerializedWithColon ) {
429466
buffer.append(':');
430467
}
431468
pad2(buffer, minutes);
432469
} else {
433470
// 24-Jun-2017, tatu: While `Z` would be conveniently short, older specs
434471
// mandate use of full `+0000`
435472
// formatted.append('Z');
436-
if( _formatTzOffsetWithColumn ) {
473+
if( _tzSerializedWithColon ) {
437474
buffer.append("+00:00");
438475
}
439476
else {

src/test/java/com/fasterxml/jackson/databind/ser/jdk/DateSerializationTest.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,19 +136,24 @@ public void testDateISO8601_customTZ() throws IOException
136136

137137
/**
138138
* Configure the StdDateFormat to serialize TZ offset with a colon between hours and minutes
139+
*
140+
* See [databind#1744]
139141
*/
140-
public void testDateISO8601_colonInTZ() throws IOException {
141-
StdDateFormat dateFormat = new StdDateFormat();
142-
dateFormat.setFormatTzOffsetWithColumn(true);
142+
public void testDateISO8601_colonInTZ() throws IOException
143+
{
144+
StdDateFormat dateFormat = new StdDateFormat();
145+
assertFalse(dateFormat.isColonIncludedInTimeZone());
146+
dateFormat = dateFormat.withColonInTimeZone(true);
147+
assertTrue(dateFormat.isColonIncludedInTimeZone());
143148

144-
ObjectMapper mapper = new ObjectMapper();
149+
ObjectMapper mapper = new ObjectMapper();
145150
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
146151
mapper.setDateFormat(dateFormat);
147152

148153
serialize( mapper, judate(1970, 1, 1, 02, 00, 00, 0, "GMT+2"), "1970-01-01T00:00:00.000+00:00");
149-
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+00:00");
154+
serialize( mapper, judate(1970, 1, 1, 00, 00, 00, 0, "UTC"), "1970-01-01T00:00:00.000+00:00");
150155
}
151-
156+
152157
public void testDateOther() throws IOException
153158
{
154159
ObjectMapper mapper = new ObjectMapper();

0 commit comments

Comments
 (0)