[JAVA-4023] Dates before epoch get serialized differently from dates after epoch Created: 25/Feb/21  Updated: 22/Jun/22

Status: Blocked
Project: Java Driver
Component/s: BSON
Affects Version/s: 4.2.0, 4.2.1
Fix Version/s: None

Type: Improvement Priority: Major - P3
Reporter: Aalbert Torsius Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows, Linux (Docker)


Issue Links:
Related
is related to DRIVERS-1586 Consider changing relaxed representat... Backlog

 Description   

When calling toJson() on a Document containing dates before and after epoch (1970), the result differs. Dates after epoch are represented as a string with an ISO 8601 formatted date, while dates before epoch are represented as the number of milliseconds to epoch.

Expectation is that all dates get represented the same way.

Minimal example:

final String jsonInput = "{" +
    "_id: '1234'," +
    "foo: ISODate('1970-01-01T00:00:00.001Z')," +
    "bar: ISODate('1969-12-31T23:59:59.999Z')," +
    "baz: ISODate('1900-01-01T00:00:00.000Z')" +
    "}";
final String expectedOutput = "{" +
    "\"_id\": \"1234\", " +
    "\"foo\": {\"$date\": \"1970-01-01T00:00:00.001Z\"}, " +
    "\"bar\": {\"$date\": \"1969-12-31T23:59:59.999Z\"}, " +
    "\"baz\": {\"$date\": \"1900-01-01T00:00:00Z\"}, " +
    "}";
Document doc = Document.parse(jsonInput);
String jsonOutput = doc.toJson();
 
if (!expectedOutput.equalsIgnoreCase(jsonOutput)) {
    System.out.println(jsonOutput);
};
 
// prints {"_id": "1234", "foo": {"$date": "1970-01-01T00:00:00.001Z"}, "bar": {"$date": {"$numberLong": "-1"}}, "baz": {"$date": {"$numberLong": "-2208988800000"}}}



 Comments   
Comment by Jeffrey Yemin [ 26/Feb/21 ]

I linked this issue to a new issue in the drivers project: DRIVERS-1586.

I'm going to change the status of this issue to Waiting on that one. Thanks for bringing this to our attention.

Comment by Aalbert Torsius [ 26/Feb/21 ]

Well, that has to be the most unexpected expected behaviour I've come across in a long time.

Yes, please do move it to the appropriate project and thank you for the workaround. I ended up using a fallback, but this looks cleaner.

Comment by Jeffrey Yemin [ 25/Feb/21 ]

Hi atorsius@gmail.com,

Yes, that's the expected behavior, as specified for all MongoDB drivers at https://github.com/mongodb/specifications/blob/master/source/extended-json.rst. If you'd like to propose a change to the specification, I can move/copy this issue to the DRIVERS project where we discuss requests such as this.

I can offer as well the following workaround, which makes use of the Java driver's extensible Converter framework for writing JSON:

        String jsonOutput = doc.toJson(JsonWriterSettings.builder()
                .dateTimeConverter((dateTime, writer) -> {
                    writer.writeStartObject();
                    writer.writeString("$date",
                            ZonedDateTime.ofInstant(Instant.ofEpochMilli(dateTime), ZoneId.of("Z")).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
                    writer.writeEndObject();
 
                })
                .build());

Comment by Aalbert Torsius [ 25/Feb/21 ]

In short, while using JsonMode.RELAXED (the default), JsonMode.EXTENDED is used for dates before epoch.

Generated at Thu Feb 08 09:01:02 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.