Skip to content

Commit 3f18d7b

Browse files
authored
Merge pull request #274 from microsoftgraph/calendar
Enhanced CalendarSerializer and fixed bugs in deserialization
2 parents 8d4ec6c + 595d420 commit 3f18d7b

File tree

2 files changed

+261
-18
lines changed

2 files changed

+261
-18
lines changed

src/main/java/com/microsoft/graph/serializer/CalendarSerializer.java

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public final class CalendarSerializer {
4242
*/
4343
private CalendarSerializer() {
4444
}
45-
45+
4646
/**
4747
* Deserializes an ISO-8601 formatted date
4848
*
@@ -51,39 +51,73 @@ private CalendarSerializer() {
5151
* @throws java.text.ParseException the parse exception
5252
*/
5353
public static Calendar deserialize(final String strVal) throws ParseException {
54-
// Change Z to +0000 to adapt the string to a format
54+
// Change Z to adapt the string to a format
5555
// that can be parsed in Java
5656
final boolean hasZ = strVal.indexOf('Z') != -1;
57+
final boolean hasDot = strVal.indexOf('.') != -1;
58+
59+
5760
String modifiedStrVal;
5861
final String zSuffix;
59-
if (hasZ) {
62+
if (hasZ && hasDot) {
63+
zSuffix = "";
64+
modifiedStrVal = strVal.replace("Z", "+00:00");
65+
} else if (hasZ && !hasDot) {
6066
zSuffix = "Z";
6167
modifiedStrVal = strVal.replace("Z", "+0000");
6268
} else {
6369
zSuffix = "";
6470
modifiedStrVal = strVal;
6571
}
66-
67-
// Parse the well-formatted date string.
72+
73+
final boolean hasOffset = modifiedStrVal.contains("T")
74+
? (modifiedStrVal.substring(modifiedStrVal.indexOf('T') + 1).contains("+"))
75+
|| (modifiedStrVal.substring(modifiedStrVal.indexOf('T') + 1).contains("-"))
76+
: false;
77+
78+
// Parse the well-formatted date string with and without offsets (eg: 2019-06-21T17:12:35.138, 2019-06-21T17:12:35.138+0000, 2019-06-21T17:12:35.138-07:00)
6879
final String datePattern;
69-
if (modifiedStrVal.contains(".")) {
80+
if (hasDot) {
81+
82+
String offsetSuffix = modifiedStrVal.substring(modifiedStrVal.indexOf(".") + 1);
83+
84+
// Find index of offset
85+
int offsetIndex = -1;
86+
if (hasOffset) {
87+
offsetIndex = (offsetSuffix.indexOf('+') != -1) ? offsetSuffix.indexOf('+') : offsetSuffix.indexOf('-');
88+
offsetIndex = modifiedStrVal.indexOf('.') + 1 + offsetIndex; //find offset index in original string
89+
}
90+
91+
7092
//SimpleDateFormat only supports 3 milliseconds
71-
String milliseconds = modifiedStrVal.substring(modifiedStrVal.indexOf('.') + 1,
72-
modifiedStrVal.indexOf('+'));
73-
final int millisSegmentLength = 3;
74-
if (milliseconds.length() > millisSegmentLength) {
75-
milliseconds = milliseconds.substring(0, millisSegmentLength);
76-
modifiedStrVal = modifiedStrVal.substring(0,
77-
modifiedStrVal.indexOf('.') + 1)
78-
+ milliseconds
79-
+ modifiedStrVal.substring(modifiedStrVal.indexOf('+'));
93+
//Strip extra characters in millisecond field (eg: 2019-06-21T17:12:35.1385912-07:00)
94+
String milliSeconds = hasOffset ? modifiedStrVal.substring(modifiedStrVal.indexOf('.') + 1, offsetIndex)
95+
: modifiedStrVal.substring(modifiedStrVal.indexOf('.') + 1);
96+
final int MILLIS_SEGMENT_LENGTH = 3;
97+
98+
if (milliSeconds.length() > MILLIS_SEGMENT_LENGTH) {
99+
milliSeconds = milliSeconds.substring(0, MILLIS_SEGMENT_LENGTH);
80100
}
81-
82-
datePattern = "yyyy-MM-dd'T'HH:mm:ss.SSS" + zSuffix;
101+
102+
//Handle date formats with and without offset cases
103+
if (hasOffset) {
104+
modifiedStrVal = modifiedStrVal.substring(0, modifiedStrVal.indexOf('.') + 1) + milliSeconds
105+
+ modifiedStrVal.substring(offsetIndex);
106+
datePattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
107+
} else {
108+
modifiedStrVal = modifiedStrVal.substring(0, modifiedStrVal.indexOf('.') + 1) + milliSeconds;
109+
datePattern = "yyyy-MM-dd'T'HH:mm:ss.SSS" + zSuffix;
110+
}
111+
112+
} else if (zSuffix != "") {
113+
datePattern = "yyyy-MM-dd'T'HH:mm:ss" + zSuffix;
114+
} else if (hasOffset){
115+
datePattern = "yyyy-MM-dd'T'HH:mm:ssX";
83116
} else {
84-
datePattern = "yyyy-MM-dd'T'HH:mm:ss" + zSuffix;
117+
datePattern = "yyyy-MM-dd'T'HH:mm:ss";
85118
}
86119

120+
87121
final SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);
88122
dateFormat.setTimeZone(TimeZone.getDefault());
89123

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
package com.microsoft.graph.serializer;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertNotNull;
5+
6+
import java.util.Calendar;
7+
import java.util.TimeZone;
8+
9+
import org.junit.Test;
10+
11+
/**
12+
* Test cases for calendar serialization and deserialization
13+
*
14+
* @author mobilal
15+
*
16+
*/
17+
public class CalendarSerializerTests {
18+
19+
/**
20+
* Validate if a calendar date instance could be serialized
21+
* @throws Exception if calendar couldn't be serialized
22+
*/
23+
@Test
24+
public void testDateSerialization() throws Exception {
25+
Calendar calendar = Calendar.getInstance();
26+
calendar.setTimeInMillis(1561162355000L);
27+
String expected = "2019-06-22T00:12:35.000Z";
28+
String actual = CalendarSerializer.serialize(calendar);
29+
assertNotNull(actual);
30+
assertEquals(expected, actual);
31+
}
32+
33+
/**
34+
* Validate if a date without milliseconds and offset could be deserialized
35+
* @throws Exception if date is not parsable
36+
*/
37+
@Test
38+
public void testSimpleDateTimeDeserialization() throws Exception {
39+
40+
String datetime = "2019-06-21T17:12:35";
41+
TimeZone defaultTimeZone = TimeZone.getDefault();
42+
43+
// Set timezone to UTC for testing
44+
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
45+
Calendar expected = java.util.Calendar.getInstance();
46+
expected.setTimeInMillis(1561137155000L);
47+
Calendar actual = CalendarSerializer.deserialize(datetime);
48+
assertNotNull(actual);
49+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
50+
51+
// Reset timezone after testing
52+
TimeZone.setDefault(defaultTimeZone);
53+
}
54+
55+
/**
56+
* Validate if date with UTC timezone (z) could be deserialized
57+
* @throws Exception if date is not parsable
58+
*/
59+
@Test
60+
public void testUTCSimpleDateTimeDeserialization() throws Exception {
61+
String datetime = "2019-06-21T17:12:35Z";
62+
Calendar expected = java.util.Calendar.getInstance();
63+
expected.setTimeInMillis(1561137155000L);
64+
Calendar actual = CalendarSerializer.deserialize(datetime);
65+
assertNotNull(actual);
66+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
67+
}
68+
69+
/**
70+
* Validate if date with UTC timezone (z) and milliseconds could be deserialized
71+
* @throws Exception if date is not parsable
72+
*/
73+
@Test
74+
public void testUTCDateTimeWithMillisDeserialization() throws Exception {
75+
String datetime = "2019-06-21T17:12:35.1385912Z";
76+
Calendar expected = java.util.Calendar.getInstance();
77+
expected.setTimeInMillis(1561137155138L);
78+
Calendar actual = CalendarSerializer.deserialize(datetime);
79+
assertNotNull(actual);
80+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
81+
}
82+
83+
/**
84+
* Validate if date with UTC offset (+00:00) could be deserialized
85+
* @throws Exception if date is not parsable
86+
*/
87+
@Test
88+
public void testUTCDateTimeInOffsetFormatDeserialization() throws Exception {
89+
String datetime = "2019-06-21T17:12:35+00:00";
90+
Calendar expected = java.util.Calendar.getInstance();
91+
expected.setTimeInMillis(1561137155000L);
92+
Calendar actual = CalendarSerializer.deserialize(datetime);
93+
assertNotNull(actual);
94+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
95+
}
96+
97+
/**
98+
* Validate if date with UTC offset (+00:00) and milliseconds could be deserialized
99+
* @throws Exception if date is not parsable
100+
*/
101+
@Test
102+
public void testUTCDateTimeWithMillisAndOffsetDeserialization() throws Exception {
103+
String datetime = "2019-06-21T17:12:35.1385912+00:00";
104+
Calendar expected = java.util.Calendar.getInstance();
105+
expected.setTimeInMillis(1561137155138L);
106+
Calendar actual = CalendarSerializer.deserialize(datetime);
107+
assertNotNull(actual);
108+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
109+
}
110+
111+
/**
112+
* Validate if date with different UTC offset (+0000) could be deserialized
113+
* @throws Exception if date is not parsable
114+
*/
115+
@Test
116+
public void testUTCDateTimeInNonstandardOffsetFormatDeserialization() throws Exception {
117+
String datetime = "2019-06-21T17:12:35+0000";
118+
Calendar expected = java.util.Calendar.getInstance();
119+
expected.setTimeInMillis(1561137155000L);
120+
Calendar actual = CalendarSerializer.deserialize(datetime);
121+
assertNotNull(actual);
122+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
123+
}
124+
125+
/**
126+
* Validate if date with positive timezone offset (+07:00) could be deserialized
127+
* @throws Exception if date is not parsable
128+
*/
129+
@Test
130+
public void testDateTimePositiveOffsetFormatDeserialization() throws Exception {
131+
String datetime = "2019-06-21T17:12:35+07:00";
132+
Calendar expected = java.util.Calendar.getInstance();
133+
expected.setTimeInMillis(1561111955000L);
134+
Calendar actual = CalendarSerializer.deserialize(datetime);
135+
assertNotNull(actual);
136+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
137+
}
138+
139+
/**
140+
* Validate if date with positive timezone offset (+07:00) and milliseconds could be deserialized
141+
* @throws Exception if date is not parsable
142+
*/
143+
@Test
144+
public void testDateTimeWithMillisAndPositiveOffsetDeserialization() throws Exception {
145+
String datetime = "2019-06-21T17:12:35.1385912+07:00";
146+
Calendar expected = java.util.Calendar.getInstance();
147+
expected.setTimeInMillis(1561111955138L);
148+
Calendar actual = CalendarSerializer.deserialize(datetime);
149+
assertNotNull(actual);
150+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
151+
}
152+
153+
/**
154+
* Validate if date with positive timezone offset in different format (+0700) could be deserialized
155+
* @throws Exception if date is not parsable
156+
*/
157+
@Test
158+
public void testUTCDateTimeInNonstandardPositiveOffsetFormatDeserialization() throws Exception {
159+
String datetime = "2019-06-21T17:12:35+0700";
160+
Calendar expected = java.util.Calendar.getInstance();
161+
expected.setTimeInMillis(1561111955000L);
162+
Calendar actual = CalendarSerializer.deserialize(datetime);
163+
assertNotNull(actual);
164+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
165+
}
166+
167+
/**
168+
* Validate if date with negative timezone offset (-07:00) could be deserialized
169+
* @throws Exception if date is not parsable
170+
*/
171+
@Test
172+
public void testDateTimeNegativeOffsetFormatDeserialization() throws Exception {
173+
String datetime = "2019-06-21T17:12:35-07:00";
174+
Calendar expected = java.util.Calendar.getInstance();
175+
expected.setTimeInMillis(1561162355000L);
176+
Calendar actual = CalendarSerializer.deserialize(datetime);
177+
assertNotNull(actual);
178+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
179+
}
180+
181+
/**
182+
* Validate if date with negative timezone offset (-07:00) and milliseconds could be deserialized
183+
* @throws Exception if date is not parsable
184+
*/
185+
@Test
186+
public void testDateTimeWithMillisAndNegativeOffsetDeserialization() throws Exception {
187+
String datetime = "2019-06-21T17:12:35.1385912-07:00";
188+
Calendar expected = java.util.Calendar.getInstance();
189+
expected.setTimeInMillis(1561162355138L);
190+
Calendar actual = CalendarSerializer.deserialize(datetime);
191+
assertNotNull(actual);
192+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
193+
}
194+
195+
/**
196+
* Validate if date with negative timezone offset in different format (-0700) could be deserialized
197+
* @throws Exception if date is not parsable
198+
*/
199+
@Test
200+
public void testUTCDateTimeInNonstandardNegativeOffsetFormatDeserialization() throws Exception {
201+
String datetime = "2019-06-21T17:12:35-0700";
202+
Calendar expected = java.util.Calendar.getInstance();
203+
expected.setTimeInMillis(1561162355000L);
204+
Calendar actual = CalendarSerializer.deserialize(datetime);
205+
assertNotNull(actual);
206+
assertEquals(expected.getTimeInMillis(), actual.getTimeInMillis());
207+
}
208+
209+
}

0 commit comments

Comments
 (0)