Skip to content

Commit a0c5851

Browse files
authored
Backport OffsetDateTime changes from 4.0 (#3090)
Backport OffsetDateTime changes from Java/Python on 4.0 where OffsetDateTime is now the default Date type in Gremlin, while retained Date as accepted input for steps. Added OffsetDateTime serializers to Go/JS/.NET. Made OffsetDateTime the default serializer for date types in GLVs (Date type will only deserialize).
1 parent 619e1f7 commit a0c5851

76 files changed

Lines changed: 1182 additions & 299 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
4949
* Fixed bug in `group()` value traversal of the second `by()` where a `CollectingBarrierStep` could produce an unexpected filtering effect when `ReducingBarrierStep` or `SupplyingBarrierStep` instances were not taken into account.
5050
* Changed `DetachedFactory` to special case the handling of `ComputerAdjacentVertex` which doesn't carry properties but still needs to be detachable for OLAP cases.
5151
* Deprecated `ProfilingAware.prepareForProfiling` method preferring to simply `resetBarrierFromValueTraversal` from the `Grouping` interface after strategy application.
52+
* Deprecated `Date` in favor of `OffsetDateTime` as the default date type in core, `Date` is still supported as input to date steps for compatibility.
53+
* Added and made `OffsetDateTime` serializers the default for existing date types in Python, Go, JavaScript, and .NET. `Date` is only used to deserialize from server.
5254
* Added missing strategies in `gremlin-go`, updated certain strategies to take varargs and updated `GoTranslatorVisitor` for corresponding translations.
5355
* Fixed `BigInt` and `BigDecimal` parsing in `gremlin-go` cucumber test suite, fixed `UnscaledValue` type in `BigDecimal` struct and added `ParseBigDecimal` method.
5456
* Added validation to `groupCount()` to prevent an invalid usage of multiple `by()` modulators.

docs/src/reference/the-traversal.asciidoc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ The `asDate()`-step (*map*) converts string or numeric input to Date.
812812
For string input only ISO-8601 format is supported. For numbers, the value is considered as the number of the
813813
milliseconds since "the epoch" (January 1, 1970, 00:00:00 GMT). Date input is passed without changes.
814814
815-
If the incoming traverser is not a string, number or Date then an `IllegalArgumentException` will be thrown.
815+
If the incoming traverser is not a string, number, Date or OffsetDateTime then an `IllegalArgumentException` will be thrown.
816816
817817
[gremlin-groovy,modern]
818818
----
@@ -1354,7 +1354,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
13541354
=== DateAdd Step
13551355
13561356
The `dateAdd()`-step (*map*) returns the value with the addition of the value number of units as specified by the DateToken.
1357-
If the incoming traverser is not a Date, then an `IllegalArgumentException` will be thrown.
1357+
If the incoming traverser is not a Date or OffsetDateTime, then an `IllegalArgumentException` will be thrown.
13581358
13591359
[gremlin-groovy,modern]
13601360
----
@@ -1373,7 +1373,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
13731373
=== DateDiff Step
13741374
13751375
The `dateDiff()`-step (*map*) returns the difference between two Dates in epoch time.
1376-
If the incoming traverser is not a Date, then an `IllegalArgumentException` will be thrown.
1376+
If the incoming traverser is not a Date or OffsetDateTime, then an `IllegalArgumentException` will be thrown.
13771377
13781378
[gremlin-groovy,modern]
13791379
----
@@ -1385,6 +1385,7 @@ g.inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00
13851385
*Additional References*
13861386
13871387
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(Date)`],
1388+
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(OffsetDateTime)`],
13881389
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`dateDiff(Traversal)`]
13891390
13901391
[[dedup-step]]

docs/src/upgrade/release-3.8.x.asciidoc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ complete list of all the modifications that are part of this release.
3030
3131
=== Upgrading for Users
3232
33+
==== The Switch from Date to OffsetDateTime
34+
The default implementation for date type in Gremlin is now changed from the `java.util.Date` to the more encompassing `java.time.OffsetDateTime`. This means the reference implementation for all date manipulation steps, `asDate()`, `dateAdd()`, and `dateDiff()`, as well as helper methods `datetime()`, will return `OffsetDateTime`, whose string representation will be in ISO 8601 format.
35+
36+
`Date` is still supported as incoming traverser results for these steps, as well as input into `dateDiff()` for compatibility purposes. All dates are assumed to be in `UTC` (given epoch time).
37+
38+
If one is using a persisted TinkerGraph that stored `Date` objects inside properties, one may notice `OffsetDateTime` being returned after traversal manipulation. The recommended solution is to update all existing `Date` objects into `OffsetDateTime`. This can be done by querying for the properties and transforming them using `asDate()`. Do note that all dates are assumed to be in `UTC` (given epoch time).
39+
40+
For Python, Go, JavaScript, and .NET GLVs, the existing date types are retained. The change is at the serialization level, where the exiting date type will be serialized as `OffsetDateTime` to the server, and both `Date` and `OffsetDateTime` from the server will be deserialized into the existing date types in the host language. As such, users of these GLVs should not notice impact to the application code. The caution remains in cases when client is accessing a database with `Date` object stored, the `Date` to `OffsetDateTime` transformations on the server assumes `UTC` timezone.
41+
42+
For Java GLV, this change would impact users who are expecting the old `Date` object from a traversal in their application, in this case the recommendation is to update code to expect `OffsetDateTime` as part of the version upgrade.
43+
3344
==== Simplification to g creation
3445
The creation of "g" is the start point to writing Gremlin. There are a number of ways to create it, but TinkerPop has
3546
long recommended the use of the anonymous `traversal()` function for this creation.
@@ -284,4 +295,16 @@ See: link:https://issues.apache.org/jira/browse/TINKERPOP-3121[TINKERPOP-3121]
284295
285296
==== Graph System Providers
286297
298+
==== The Switch from Date to OffsetDateTime
299+
The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more encompassing `java.time.OffsetDateTime`. This means the reference implementation for all date manipulation steps, `asDate()`, `dateAdd()`, and `dateDiff()`, as well as helper methods `datetime()`, will return `OffsetDateTime`, whose string representation will be in ISO 8601 format.
300+
301+
`Date` is still supported as incoming traverser results for these steps, as well as input into `dateDiff()` for compatibility purposes. All dates are assumed to be in `UTC` (given epoch time).
302+
303+
This may impact providers who use TinkerGraph or whose implementation store dates as `java.util.Date`. While steps will support `Date`, all date manipulations will output `OffsetDateTime`. If a user had persisted `Date` objects in the database, upgrading to 3.8 may lead to the database having both types stored. It is recommended for users to perform transformation of `Date` to `OffsetDateTime` to retain consistency.
304+
287305
==== Graph Driver Providers
306+
307+
==== The Switch from Date to OffsetDateTime
308+
The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more encompassing `java.time.OffsetDateTime`. This means the reference implementation for all date manipulation steps, `asDate()`, `dateAdd()`, and `dateDiff()`, as well as helper methods `datetime()`, will return `OffsetDateTime`, whose string representation will be in ISO 8601 format.
309+
310+
This means that drivers should use the extended `OffsetDateTime` type in the IO specs to serialize and deserialize native date objects.

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ public final class CoreImports {
330330
CLASS_IMPORTS.add(TimeUtil.class);
331331
CLASS_IMPORTS.add(Lambda.class);
332332
CLASS_IMPORTS.add(java.util.Date.class);
333+
CLASS_IMPORTS.add(java.time.OffsetDateTime.class);
333334
CLASS_IMPORTS.add(java.sql.Timestamp.class);
334335
CLASS_IMPORTS.add(java.util.UUID.class);
335336

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
2323

2424
import java.lang.reflect.Array;
25-
import java.util.Date;
25+
import java.time.OffsetDateTime;
26+
import java.util.Comparator;
2627
import java.util.Map;
2728
import java.util.Objects;
2829

@@ -68,8 +69,8 @@ public String parseString(final GremlinParser.StringArgumentContext ctx) {
6869
/**
6970
* Wrapper to visit function for Date type.
7071
*/
71-
public Date parseDate(final GremlinParser.DateArgumentContext ctx) {
72-
return (Date) visitDateArgument(ctx);
72+
public OffsetDateTime parseDate(final GremlinParser.DateArgumentContext ctx) {
73+
return (OffsetDateTime) visitDateArgument(ctx);
7374
}
7475

7576
/**

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131

3232
import java.math.BigDecimal;
3333
import java.math.BigInteger;
34+
import java.time.OffsetDateTime;
3435
import java.util.ArrayList;
35-
import java.util.Date;
3636
import java.util.HashSet;
3737
import java.util.LinkedHashMap;
3838
import java.util.List;
@@ -86,8 +86,8 @@ public String parseString(final GremlinParser.StringNullableLiteralContext strin
8686
/**
8787
* Parse a Date based literal context and return the Date.
8888
*/
89-
public Date parseDate(final GremlinParser.DateLiteralContext dateLiteral) {
90-
return (Date) visitDateLiteral(dateLiteral);
89+
public OffsetDateTime parseDate(final GremlinParser.DateLiteralContext dateLiteral) {
90+
return (OffsetDateTime) visitDateLiteral(dateLiteral);
9191
}
9292

9393
/**

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import java.math.BigDecimal;
2525
import java.math.BigInteger;
26-
import java.util.Date;
26+
import java.time.OffsetDateTime;
2727
import java.util.HashMap;
2828
import java.util.List;
2929
import java.util.Map;
@@ -167,7 +167,7 @@ public Void visitBooleanLiteral(final GremlinParser.BooleanLiteralContext ctx) {
167167

168168
@Override
169169
public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
170-
return anonymize(ctx, Date.class);
170+
return anonymize(ctx, OffsetDateTime.class);
171171
}
172172

173173
@Override

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
2828
import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
2929

30-
import java.util.Date;
30+
import java.time.OffsetDateTime;
3131
import java.util.HashMap;
3232
import java.util.List;
3333
import java.util.Map;
@@ -158,10 +158,10 @@ public Void visitFloatLiteral(final GremlinParser.FloatLiteralContext ctx) {
158158
public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
159159
// child at 2 is the date argument to datetime() and comes enclosed in quotes
160160
final String dtString = ctx.getChild(2).getText();
161-
final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
162-
sb.append("DateTimeOffset.FromUnixTimeMilliseconds(");
163-
sb.append(dt.getTime());
164-
sb.append(")");
161+
final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
162+
sb.append("DateTimeOffset.Parse(\"");
163+
sb.append(dt);
164+
sb.append("\")");
165165
return null;
166166
}
167167

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
import org.apache.tinkerpop.gremlin.structure.VertexProperty;
2828
import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
2929

30+
import java.time.OffsetDateTime;
3031
import java.util.Arrays;
3132
import java.util.Collections;
32-
import java.util.Date;
3333
import java.util.HashMap;
3434
import java.util.List;
3535
import java.util.Map;
@@ -57,8 +57,17 @@ public GoTranslateVisitor(final String graphTraversalSourceName) {
5757
public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
5858
// child at 2 is the date argument to datetime() and comes enclosed in quotes
5959
final String dtString = ctx.getChild(2).getText();
60-
final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
61-
sb.append("time.UnixMilli(" + dt.getTime() + ")");
60+
final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
61+
final String zoneInfo = dt.getOffset().getId().equals("Z") ? "UTC+00:00" : "UTC" + dt.getOffset().getId();
62+
sb.append("time.Date(").append(dt.getYear()).
63+
append(", ").append(dt.getMonthValue()).
64+
append(", ").append(dt.getDayOfMonth()).
65+
append(", ").append(dt.getHour()).
66+
append(", ").append(dt.getMinute()).
67+
append(", ").append(dt.getSecond()).
68+
append(", ").append(dt.getNano()).
69+
append(", time.FixedZone(\"").append(zoneInfo).append("\", ").append(dt.getOffset().getTotalSeconds()).append(")").
70+
append(")");
6271
return null;
6372
}
6473

gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavaTranslateVisitor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
2626
import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
2727

28-
import java.util.Date;
28+
import java.time.OffsetDateTime;
2929
import java.util.List;
3030
import java.util.stream.Collectors;
3131

@@ -152,10 +152,10 @@ public Void visitMapKey(final GremlinParser.MapKeyContext ctx) {
152152
public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
153153
// child at 2 is the date argument to datetime() and comes enclosed in quotes
154154
final String dtString = ctx.getChild(2).getText();
155-
final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
156-
sb.append("new Date(");
157-
sb.append(dt.getTime());
158-
sb.append(")");
155+
final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
156+
sb.append("OffsetDateTime.parse(\"");
157+
sb.append(dt);
158+
sb.append("\")");
159159
return null;
160160
}
161161

0 commit comments

Comments
 (0)