Skip to content

Commit 21b4391

Browse files
committed
Merge pull request #69 from islanderman/68
Use TimeZone in DeserializationContext when SerializationFeature.WRITE_DATES_WITH_ZONE_ID is not set
2 parents 713d6c5 + 6da8f42 commit 21b4391

15 files changed

+259
-46
lines changed

src/main/java/com/fasterxml/jackson/datatype/joda/cfg/FormatConfig.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.fasterxml.jackson.datatype.joda.cfg;
22

33
import org.joda.time.DateTimeZone;
4-
import org.joda.time.format.*;
4+
import org.joda.time.format.ISODateTimeFormat;
5+
import org.joda.time.format.ISOPeriodFormat;
56

67
/**
78
* Simple container class that holds both default formatter information

src/main/java/com/fasterxml/jackson/datatype/joda/cfg/JacksonJodaDateFormat.java

+8
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ public DateTimeFormatter createParser(DeserializationContext ctxt)
198198
}
199199
return formatter;
200200
}
201+
202+
/**
203+
* Differentiate if TimeZone is specified by caller
204+
* @return true if TimeZone is specified by caller; false otherwise.
205+
*/
206+
public boolean isTimezoneExplicit() {
207+
return _explicitTimezone;
208+
}
201209

202210
/*
203211
/**********************************************************

src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.io.IOException;
44

55
import org.joda.time.DateMidnight;
6+
import org.joda.time.DateTimeZone;
67
import org.joda.time.LocalDate;
78

89
import com.fasterxml.jackson.core.JsonParser;
@@ -36,6 +37,7 @@ public JodaDateDeserializerBase<?> withFormat(JacksonJodaDateFormat format) {
3637
public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt)
3738
throws IOException
3839
{
40+
3941
// We'll accept either long (timestamp) or array:
4042
if (p.isExpectedStartArrayToken()) {
4143
p.nextToken(); // VALUE_NUMBER_INT
@@ -48,7 +50,9 @@ public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt)
4850
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
4951
"after DateMidnight ints");
5052
}
51-
return new DateMidnight(year, month, day);
53+
DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone());
54+
55+
return new DateMidnight(year, month, day, tz);
5256
}
5357
switch (p.getCurrentToken()) {
5458
case VALUE_NUMBER_INT:

src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java

+14-22
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package com.fasterxml.jackson.datatype.joda.deser;
22

3-
import com.fasterxml.jackson.core.*;
4-
import com.fasterxml.jackson.databind.*;
5-
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
6-
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;
3+
import java.io.IOException;
74

8-
import org.joda.time.*;
5+
import org.joda.time.DateTime;
6+
import org.joda.time.DateTimeZone;
7+
import org.joda.time.ReadableDateTime;
8+
import org.joda.time.ReadableInstant;
99

10-
import java.io.IOException;
11-
import java.util.TimeZone;
10+
import com.fasterxml.jackson.core.JsonParser;
11+
import com.fasterxml.jackson.core.JsonToken;
12+
import com.fasterxml.jackson.databind.DeserializationContext;
13+
import com.fasterxml.jackson.databind.JsonDeserializer;
14+
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
15+
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;
1216

1317
/**
1418
* Basic deserializer for {@link ReadableDateTime} and its subtypes.
@@ -42,10 +46,10 @@ public ReadableDateTime deserialize(JsonParser p, DeserializationContext ctxt)
4246
{
4347
JsonToken t = p.getCurrentToken();
4448

49+
DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone());
50+
4551
if (t == JsonToken.VALUE_NUMBER_INT) {
46-
TimeZone tz = ctxt.getTimeZone();
47-
DateTimeZone dtz = (tz == null) ? DateTimeZone.UTC : DateTimeZone.forTimeZone(tz);
48-
return new DateTime(p.getLongValue(), dtz);
52+
return new DateTime(p.getLongValue(), tz);
4953
}
5054
if (t == JsonToken.VALUE_STRING) {
5155
String str = p.getText().trim();
@@ -60,7 +64,6 @@ public ReadableDateTime deserialize(JsonParser p, DeserializationContext ctxt)
6064
String tzId = (ix2 < ix)
6165
? str.substring(ix+1)
6266
: str.substring(ix+1, ix2);
63-
DateTimeZone tz;
6467
try {
6568
tz = DateTimeZone.forID(tzId);
6669
} catch (IllegalArgumentException e) {
@@ -88,15 +91,4 @@ public ReadableDateTime deserialize(JsonParser p, DeserializationContext ctxt)
8891
}
8992
throw ctxt.mappingException(handledType());
9093
}
91-
92-
private static boolean _allDigits(String str)
93-
{
94-
for (int i = 0, len = str.length(); i < len; ++i) {
95-
int c = str.charAt(i);
96-
if (c > '9' | c < '0') {
97-
return false;
98-
}
99-
}
100-
return true;
101-
}
10294
}

src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22

33
import java.io.IOException;
44

5+
import org.joda.time.DateTimeZone;
6+
import org.joda.time.Interval;
7+
58
import com.fasterxml.jackson.core.JsonParser;
69
import com.fasterxml.jackson.core.JsonProcessingException;
7-
810
import com.fasterxml.jackson.databind.DeserializationContext;
911
import com.fasterxml.jackson.databind.JsonMappingException;
1012
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
1113
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;
1214

13-
import org.joda.time.*;
14-
1515
public class IntervalDeserializer extends JodaDateDeserializerBase<Interval>
1616
{
1717
private static final long serialVersionUID = 1L;
@@ -64,7 +64,8 @@ public Interval deserialize(JsonParser jsonParser, DeserializationContext ctxt)
6464
throw JsonMappingException.from(jsonParser,
6565
"Failed to parse number from '"+str+"' (full source String '"+v+"') to construct "+handledType().getName());
6666
}
67-
DateTimeZone tz = _format.getTimeZone();
67+
68+
DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone());
6869
if (tz != null) {
6970
if (!tz.equals(result.getStart().getZone())) {
7071
result = new Interval(result.getStartMillis(), result.getEndMillis(), tz);

src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
import org.joda.time.LocalTime;
66

7-
import com.fasterxml.jackson.core.*;
7+
import com.fasterxml.jackson.core.JsonParser;
8+
import com.fasterxml.jackson.core.JsonToken;
89
import com.fasterxml.jackson.databind.DeserializationContext;
910
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;
1011
import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat;

src/main/java/com/fasterxml/jackson/datatype/joda/deser/key/DateTimeKeyDeserializer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import java.io.IOException;
44
import java.util.TimeZone;
55

6-
import org.joda.time.*;
6+
import org.joda.time.DateTime;
7+
import org.joda.time.DateTimeZone;
78

89
import com.fasterxml.jackson.databind.DeserializationContext;
910
import com.fasterxml.jackson.databind.DeserializationFeature;

src/main/java/com/fasterxml/jackson/datatype/joda/ser/DateTimeZoneSerializer.java

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import org.joda.time.DateTimeZone;
66

77
import com.fasterxml.jackson.core.JsonGenerator;
8-
98
import com.fasterxml.jackson.databind.SerializerProvider;
109

1110
public class DateTimeZoneSerializer extends JodaSerializerBase<DateTimeZone>

src/main/java/com/fasterxml/jackson/datatype/joda/ser/DurationSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import org.joda.time.Duration;
66

7-
import com.fasterxml.jackson.core.*;
7+
import com.fasterxml.jackson.core.JsonGenerator;
88
import com.fasterxml.jackson.databind.SerializationFeature;
99
import com.fasterxml.jackson.databind.SerializerProvider;
1010
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;

src/main/java/com/fasterxml/jackson/datatype/joda/ser/InstantSerializer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import java.io.IOException;
44

5-
import org.joda.time.*;
5+
import org.joda.time.Instant;
66

77
import com.fasterxml.jackson.core.JsonGenerator;
88
import com.fasterxml.jackson.databind.SerializationFeature;

src/main/java/com/fasterxml/jackson/datatype/joda/ser/JodaSerializerBase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.fasterxml.jackson.datatype.joda.ser;
22

3-
import com.fasterxml.jackson.core.JsonGenerator;
43
import java.io.IOException;
54

5+
import com.fasterxml.jackson.core.JsonGenerator;
66
import com.fasterxml.jackson.core.JsonProcessingException;
77
import com.fasterxml.jackson.databind.SerializerProvider;
88
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;

src/main/java/com/fasterxml/jackson/datatype/joda/ser/LocalTimeSerializer.java

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import org.joda.time.LocalTime;
66

77
import com.fasterxml.jackson.core.JsonGenerator;
8-
98
import com.fasterxml.jackson.databind.SerializationFeature;
109
import com.fasterxml.jackson.databind.SerializerProvider;
1110
import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig;

src/test/java/com/fasterxml/jackson/datatype/joda/DateMidnightTest.java

+64
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.fasterxml.jackson.datatype.joda;
22

33
import java.io.IOException;
4+
import java.util.TimeZone;
45

56
import org.joda.time.DateMidnight;
7+
import org.joda.time.DateTimeZone;
68

79
import com.fasterxml.jackson.annotation.JsonFormat;
810
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@@ -29,12 +31,51 @@ public AlternateFormat(DateMidnight v) {
2931
}
3032
}
3133

34+
static class FormattedDateMidnight {
35+
@JsonFormat(timezone="EST")
36+
public DateMidnight dateMidnight;
37+
}
38+
3239
/*
3340
/**********************************************************
3441
/* Test methods
3542
/**********************************************************
3643
*/
3744

45+
public void testDateMidnightDeserWithTimeZone() throws IOException
46+
{
47+
MAPPER.setTimeZone(TimeZone.getTimeZone("Europe/Paris"));
48+
// couple of acceptable formats, so:
49+
DateMidnight date = MAPPER.readValue("[2001,5,25]", DateMidnight.class);
50+
assertEquals(2001, date.getYear());
51+
assertEquals(5, date.getMonthOfYear());
52+
assertEquals(25, date.getDayOfMonth());
53+
54+
DateMidnight date2 = MAPPER.readValue(quote("2005-07-13"), DateMidnight.class);
55+
assertEquals(2005, date2.getYear());
56+
assertEquals(7, date2.getMonthOfYear());
57+
assertEquals(13, date2.getDayOfMonth());
58+
59+
// since 1.6.1, for [JACKSON-360]
60+
assertNull(MAPPER.readValue(quote(""), DateMidnight.class));
61+
62+
63+
MAPPER.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
64+
// couple of acceptable formats, so:
65+
date = MAPPER.readValue("[2001,5,25]", DateMidnight.class);
66+
assertEquals(2001, date.getYear());
67+
assertEquals(5, date.getMonthOfYear());
68+
assertEquals(25, date.getDayOfMonth());
69+
70+
date2 = MAPPER.readValue(quote("2005-07-13"), DateMidnight.class);
71+
assertEquals(2005, date2.getYear());
72+
assertEquals(7, date2.getMonthOfYear());
73+
assertEquals(13, date2.getDayOfMonth());
74+
75+
// since 1.6.1, for [JACKSON-360]
76+
assertNull(MAPPER.readValue(quote(""), DateMidnight.class));
77+
}
78+
3879
public void testDateMidnightDeser() throws IOException
3980
{
4081
// couple of acceptable formats, so:
@@ -85,4 +126,27 @@ public void testCustomFormat() throws Exception
85126
assertNotNull(output.value);
86127
assertEquals(inputDate, output.value);
87128
}
129+
130+
public void testWithTimeZoneOverride() throws Exception
131+
{
132+
ObjectMapper mapper = jodaMapper();
133+
134+
DateMidnight date = mapper.readValue("[2001,5,25]", DateMidnight.class);
135+
FormattedDateMidnight input = new FormattedDateMidnight();
136+
input.dateMidnight = date;
137+
String json = mapper.writeValueAsString(input);
138+
139+
FormattedDateMidnight result = mapper.readValue(json, FormattedDateMidnight.class);
140+
assertNotNull(result);
141+
142+
// Ensure timezone sticks:
143+
DateMidnight resultMidnight = result.dateMidnight;
144+
assertEquals(2001, resultMidnight.getYear());
145+
assertEquals(5, resultMidnight.getMonthOfYear());
146+
assertEquals(25, resultMidnight.getDayOfMonth());
147+
148+
DateTimeZone resultTz = resultMidnight.getZone();
149+
// Is this stable enough for testing?
150+
assertEquals("America/New_York", resultTz.getID());
151+
}
88152
}

src/test/java/com/fasterxml/jackson/datatype/joda/DateTimeTest.java

+37-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
import java.io.IOException;
44

5-
import org.joda.time.*;
5+
import org.joda.time.DateTime;
6+
import org.joda.time.DateTimeZone;
67

7-
import com.fasterxml.jackson.annotation.*;
8-
import com.fasterxml.jackson.databind.*;
8+
import com.fasterxml.jackson.annotation.JsonCreator;
9+
import com.fasterxml.jackson.annotation.JsonFormat;
10+
import com.fasterxml.jackson.annotation.JsonProperty;
11+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
12+
import com.fasterxml.jackson.databind.ObjectMapper;
13+
import com.fasterxml.jackson.databind.SerializationFeature;
914

1015
public class DateTimeTest extends JodaTestBase
1116
{
@@ -48,6 +53,11 @@ public Beanie(@JsonProperty("jodaDateTime") DateTime jodaDateTime,
4853
this.javaUtilDate = javaUtilDate;
4954
}
5055
}
56+
57+
static class FormattedDateTime {
58+
@JsonFormat(timezone="EST")
59+
public DateTime dateTime;
60+
}
5161

5262
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "@class")
5363
private static interface TypeInfoMixIn {
@@ -159,4 +169,28 @@ public void testCustomFormat() throws Exception
159169
// Timezone may (and most likely will) differ so...
160170
assertEquals(inputDate.getMillis(), output.date.getMillis());
161171
}
172+
173+
public void testWithTimeZoneOverride() throws Exception
174+
{
175+
ObjectMapper mapper = jodaMapper();
176+
177+
DateTime date = mapper.readValue(quote("2014-01-20T08:59:01.000-0500"), DateTime.class);
178+
179+
FormattedDateTime input = new FormattedDateTime();
180+
input.dateTime = date;
181+
String json = mapper.writeValueAsString(input);
182+
183+
FormattedDateTime result = mapper.readValue(json, FormattedDateTime.class);
184+
assertNotNull(result);
185+
186+
// Ensure timezone sticks:
187+
DateTime resultMidnight = result.dateTime;
188+
assertEquals(2014, resultMidnight.getYear());
189+
assertEquals(1, resultMidnight.getMonthOfYear());
190+
assertEquals(20, resultMidnight.getDayOfMonth());
191+
192+
DateTimeZone resultTz = resultMidnight.getZone();
193+
// Is this stable enough for testing?
194+
assertEquals("America/New_York", resultTz.getID());
195+
}
162196
}

0 commit comments

Comments
 (0)