google / google/gson

DateTypeAdapter deserialization fails based on user's 24 hour preference

Open
#935 16 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
24.2k
Forks
4.5k
Avg merge
6d 4h
Merged PRs (30d)
12

Description

I've encountered a bug affecting (de)serialization of dates on Android devices using gson 2.7.
### Description/Stacktrace

When trying to deserialize this date (`Sep 26, 2016 18:13:24`), after switching my device time preferences from 24 hour to 12 hour, using `DateTypeAdapter.deserializeToDate`, the following exception was thrown:

```
java.lang.NumberFormatException: Invalid number: Sep
at com.google.gson.internal.bind.util.ISO8601Utils.parseInt(ISO8601Utils.java:311)
at com.google.gson.internal.bind.util.ISO8601Utils.parse(ISO8601Utils.java:129)
```
### Steps to reproduce

Reproduced on a Nexus 5X running Android 7.0. I have also seen this crash reported from varying devices and Android versions.
1. Create a `java.util.Date` object at the following time: `Sep 26, 2016 18:13:24` (any date should work, but I will use this date for the example).
2. Serialize the date object using `DateTypeAdapter.write`, observe that the output is either the string above or `Sep 26, 2016 6:13:24 PM` depending on your device's 24 hour time settings.
3. Go to device date & time settings.
4. Switch to using 24-hour format (or vice versa)
5. Try to deserialize the date string using `DateTypeAdapter.deserializeToDate` and observe the exception above being thrown.
#### If you are using the 24-hour format
- `DateTypeAdapter.deserializeToDate` -> `Sep 26, 2016 18:13:24` -> works as expected
- `DateTypeAdapter.deserializeToDate` -> `Sep 26, 2016 6:13:24 PM` -> throws an exception
#### If you are using the 12-hour format
- `DateTypeAdapter.deserializeToDate` -> `Sep 26, 2016 18:13:24` -> throws an exception
- `DateTypeAdapter.deserializeToDate` -> `Sep 26, 2016 6:13:24 PM` -> works as expected

That the ISO8601Utils cannot deserialize this string does not seem to be the issue. The problem seems to be that the `DateFormat` object `enUsFormat` is used by default to serialize the Date object. Then when it deserializes it, it tries to format it using this same DateFormat, if that fails it's falling back to another DateFormat and finally the ISO8601Utils, which also will fail because it's not meant to handle this format. When the 24-hour time preference is switched, the DateFormat object no longer can correctly format the serialized string, and therefore the adapter falls back to ISO8601Utils which throws an error. `DefaultDateTypeAdapter` also appears to have the same problem as `DateTypeAdapter` as it is contains the same (de)serialization logic for `java.util.Date` objects.

A workaround I am using is to create a TypeAdapter to handle dates and to use ISO8601Utils directly rather than default to using DateFormat so that the serialized string will be agnostic of the user's time preferences.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.