Compatibility issue with OGM java.util.Date and Temporal instant creation functions

(Bob Bierman) #1

I would like to be able to create a datetime property that is two-way compatible with the java.util.Date type and a temporal date function (e.g. datetime() ) or other Cypher current date generator function.

Using a @NodeEntity object in java, a Date type property gets stored in Neo4j as a STRING with the format: 2019-03-26T18:55:01.132Z

Using the datetime() temporal function in Neo4j, the same date is stored as a STRING with the format: 2019-03-26T18:55:01.132000000Z

The only difference is the additional zeroes for micro- and nano-seconds. The stored java format can be converted to a datetime() and temporal operators applied, so that is not an issue.

The problem is that if the date field is created in Cypher using the datetime() function, it is returned to the java entity as a ZonedDateTime, and I get this exception:

java.lang.ClassCastException: java.time.ZonedDateTime cannot be cast to java.lang.String
at org.neo4j.ogm.typeconversion.DateStringConverter.toEntityAttribute(DateStringConverter.java:40)

Nodes created using a java entity convert back to Date just fine, it is only date properties updated via temporal instant functions that have this issue.

My question is...is there a temporal function that will store the proper datetime format for conversion? The closest I am able to come is this:

RETURN datetime.truncate('second', datetime())
"2019-03-26T19:52:48Z"

but that still throws the exception because of the missing seconds portion. Which leads me to believe this should solve my problem, alas it does not appear to truncate properly:

RETURN datetime.truncate('millisecond', datetime())
"2019-03-26T19:53:33.902000000Z"

Am I correct in assuming the returned value should be?:
"2019-03-26T19:53:33.902Z"

Is there a bug in the truncate function, or in my thinking? I would appreciate any insight.

1 Like

(Jiropole) #2

I'm not sure if it's related, but as far as I know, OGM does not yet support the native chrono or spatial Neo4j types. This is true for me on Neo4j 3.4.5 / OGM 3.1.2. I just re-proved this early today by attempting to set dates on nodes in a plugin, using OffsetDateTime.now().toInstant(), and then map via OGM to a Date field on my entity, which results in the error.

My simple workaround (until this is addressed) is to store OffsetDateTime.now().toInstant().toEpochMilli() in the DB, and use a long in my entity, which maps fine. Then again, I'm just passing them through, or this might be more annoying. There may be better workarounds, and/or they may fix this in OGM 3.2.

0 Likes

(Bob Bierman) #3

Thank you for the insight. I have considered using long to store the date, but it's not my first choice. I thought I had the problem solved with this:

apoc.temporal.format(datetime(), 'ISO_DATE_TIME')

...which converts to Date in most cases, except one scenario where it truncates trailing zeroes from the millisecond portion and that causes a mapping error upon conversion. I'm considering two options at this point...one is to write my own AttributeConverter to deal with that case, or (I believe) the better option is to create my own apoc procedure that will return a consistent ISO format date, e.g.

TimeZone tz = TimeZone.getTimeZone("UTC");
df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
df.setTimeZone(tz);
return df.format(new Date());

0 Likes

(Bob Bierman) #4

This works both ways. Neo4j temporal <=> java.util.Date

apoc.date.format(timestamp(), 'ms', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

Static format. Does not truncate trailing zeroes from milliseconds as does apoc.temporal.format :+1:

0 Likes