This is an automated email from the ASF dual-hosted git repository.

andreac pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.8-dev by this push:
     new 60f284047e [TINKERPOP-3212] Date manipulation consistency (#3267)
60f284047e is described below

commit 60f284047eb4f63593553472e40050faac356553
Author: andreachild <[email protected]>
AuthorDate: Thu Nov 6 12:45:49 2025 -0800

    [TINKERPOP-3212] Date manipulation consistency (#3267)
    
    https://issues.apache.org/jira/browse/TINKERPOP-3212
    Improve date handling consistency and allow for round-trippable date 
manipulation by changing asNumber() to convert dates to milliseconds since 
epoch and dateDiff() to return milliseconds instead of seconds.
---
 CHANGELOG.asciidoc                                 |  2 +
 docs/src/reference/the-traversal.asciidoc          |  8 +++-
 docs/src/upgrade/release-3.8.0.asciidoc            | 33 +++++++++++++++-
 .../process/traversal/step/map/AsNumberStep.java   | 15 +++++--
 .../process/traversal/step/map/DateDiffStep.java   |  2 +-
 .../traversal/step/map/AsNumberStepTest.java       | 11 ++++++
 .../traversal/step/map/DateDiffStepTest.java       | 29 +++++++++-----
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  4 ++
 gremlin-go/driver/cucumber/gremlin.go              |  4 ++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  4 ++
 gremlin-python/src/main/python/radish/gremlin.py   |  4 ++
 .../gremlin/test/features/data/DateTime.feature    |  2 +-
 .../gremlin/test/features/map/AsDate.feature       | 24 ++++++++++-
 .../gremlin/test/features/map/AsNumber.feature     | 22 +++++++++++
 .../gremlin/test/features/map/DateDiff.feature     | 46 +++++++++++++++++++---
 15 files changed, 185 insertions(+), 25 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 641cf47641..bee2ee232d 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -109,6 +109,8 @@ This release also includes changes from <<release-3-7-XXX, 
3.7.XXX>>.
 * Removed the `@RemoteOnly` testing tag in Gherkin as lambda tests have all 
been moved to the Java test suite.
 * Updated gremlin-javascript to use GraphBinary as default instead of 
GraphSONv3
 * Added the `asNumber()` step to perform number conversion.
+* Modified `asNumber()` to handle `OffsetDateTime` and `Date`
+* Modified `dateDiff()` to return milliseconds instead of seconds
 * Changed `repeat()` to make `repeatTraversal` global rather than a mix of 
local and global.
 * Renamed many types in the grammar for consistent use of terms "Literal", 
"Argument", and "Varargs".
 * Changed `gremlin-net` so that System.Text.Json is only listed as an explicit 
dependency when it is not available from the framework.
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index dc32bc791b..8b8f94dc1c 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -853,6 +853,8 @@ String inputs are parsed into numeric values. By default, 
the value will be pars
 whole number, or as a double if it contains a decimal point. A 
`NumberFormatException` will be thrown if the string
 cannot be parsed into a valid number format.
 
+Date inputs are converted to milliseconds since epoch (January 1, 1970, 
00:00:00 GMT).
+
 All other input types will result in `IllegalArgumentException`.
 
 [gremlin-groovy,modern]
@@ -860,11 +862,13 @@ All other input types will result in 
`IllegalArgumentException`.
 g.inject(1234).asNumber() <1>
 g.inject(1.76d).asNumber() <2>
 g.inject(1.76d).asNumber(GType.INT) <3>
+g.inject("2023-08-02T00:00:00Z").asDate().asNumber() <4>
 ----
 
 <1> An int will be passed through.
 <2> A double will be passed through.
 <3> A double is converted into an int.
+<4> A date is converted into milliseconds since epoch.
 
 [NOTE, caption=Java]
 ====
@@ -1516,7 +1520,7 @@ 
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 [[dateDiff-step]]
 === DateDiff Step
 
-The `dateDiff()`-step (*map*) returns the difference between two Dates in 
epoch time. 
+The `dateDiff()`-step (*map*) returns the difference between two Dates in 
epoch time in milliseconds. 
 If the incoming traverser is not a Date or OffsetDateTime, then an 
`IllegalArgumentException` will be thrown.
 
 [gremlin-groovy,modern]
@@ -1524,7 +1528,7 @@ If the incoming traverser is not a Date or 
OffsetDateTime, then an `IllegalArgum
 
g.inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00Z").asDate())
 <1>
 ----
 
-<1> Find difference between two dates
+<1> Find difference between two dates in milliseconds
 
 *Additional References*
 
diff --git a/docs/src/upgrade/release-3.8.0.asciidoc 
b/docs/src/upgrade/release-3.8.0.asciidoc
index c5547429a1..4a0335a44a 100644
--- a/docs/src/upgrade/release-3.8.0.asciidoc
+++ b/docs/src/upgrade/release-3.8.0.asciidoc
@@ -49,6 +49,7 @@ upgrade plan.
 |Breaking |New Type Default |<<float-defaults-to-double,Float Defaults to 
Double>>
 |Breaking |Step Replacement 
|<<removal-of-aggregate-with-scope-and-store,Removal of `aggregate()` with 
`Scope` and `store()`>>
 |Breaking |Step Replacement |<<none-and-discard,none() and discard()>>
+|Breaking |Step Behavior Change 
|<<datediff-step-returns-milliseconds,dateDiff() Step Returns Milliseconds>>
 |Breaking |Step Behavior Change 
|<<repeat-step-global-children-semantics-change,repeat() Step Global Children 
Semantics Change>>
 |Breaking |Step Behavior Change 
|<<modified-limit-skip-range-semantics-in-repeat,Modified limit() skip() 
range() Semantics in repeat()>>
 |Breaking |Step Behavior Change |<<split-on-empty-string,split() on Empty 
String>>
@@ -306,6 +307,28 @@ or 'd') as Double by default. Users who need `BigDecimal` 
precision can still us
 
 ==== Modified Step Behavior
 
+===== dateDiff() Step Returns Milliseconds
+
+The `dateDiff()` step has been changed to return milliseconds instead of 
seconds for consistency with the `asDate()` 
+step which accepts numbers in milliseconds since epoch (January 1, 1970, 
00:00:00 GMT) and the new `asNumber()` step 
+which converts dates to milliseconds since epoch.
+
+[source,text]
+----
+// In 3.7.x seconds are returned
+gremlin> 
g.inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00Z").asDate())
+==>-86400
+
+// In 3.8.0 milliseconds are returned
+gremlin> 
g.inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00Z").asDate())
+==>-86400000
+// math() and asNumber() steps can be used to obtain seconds instead of 
milliseconds
+gremlin> 
g.withSideEffect("x",1000).inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00Z").asDate()).math("_/x").asNumber(GType.LONG)
+==>-86400
+----
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3212[TINKERPOP-3212]
+
 ===== Changes to `repeat()`
 
 [[repeat-step-global-children-semantics-change]]
@@ -1318,7 +1341,7 @@ The new `asNumber()` step provides type casting 
functionality to Gremlin. It ser
 strings and casts numbers into desired types. For the convenience of remote 
traversals in GLVs, these available types
 are denoted by a set of number tokens (`GType`).
 
-This new step will allow users to normalize their data by converting string 
numbers and mixed numeric types to a
+This new step will allow users to normalize their data by converting string 
numbers, dates, and mixed numeric types to a
 consistent format, making it easier to perform downstream mathematical 
operations. As an example:
 
 [source,text]
@@ -1367,6 +1390,14 @@ gremlin> g.inject("128").asNumber(GType.BYTE)
 ==> ArithmeticException
 ----
 
+Dates will be converted to the number of milliseconds since epoch (January 1, 
1970, 00:00:00 GMT):
+
+[source,text]
+----
+gremlin> g.inject("2023-08-02T00:00:00Z").asDate().asNumber()
+==>1690934400000
+----
+
 All other input types will result in `IllegalArgumentException`:
 [source,text]
 ----
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
index e025d57a40..63c4990fe6 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import java.time.OffsetDateTime;
+import java.util.Date;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -53,12 +55,17 @@ public class AsNumberStep<S> extends ScalarMapStep<S, 
Number> {
     protected Number map(final Traverser.Admin<S> traverser) {
         final Object object = traverser.get();
         if (object == null) return null;
+        Number number = null;
         if (object instanceof String) {
-            String numberText = (String) object;
-            Number number = parseNumber(numberText);
-            return typeToken == null ? number : castNumber(number, typeToken);
+            number = parseNumber((String) object);
         } else if (object instanceof Number) {
-            Number number = (Number) object;
+            number = (Number) object;
+        } else if (object instanceof Date) {
+            number = ((Date) object).toInstant().toEpochMilli();
+        } else if (object instanceof OffsetDateTime) {
+            number = ((OffsetDateTime) object).toInstant().toEpochMilli();
+        }
+        if (number != null) {
             return typeToken == null ? number : castNumber(number, typeToken);
         }
         throw new IllegalArgumentException(String.format("Can't parse type %s 
as number.", object.getClass().getSimpleName()));
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStep.java
index 0befbdbf32..19d0b40ed0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStep.java
@@ -95,7 +95,7 @@ public final class DateDiffStep<S> extends ScalarMapStep<S, 
Long> implements Tra
         }
 
         // let's not throw exception and assume null date == 0
-        return otherDate == null ? date.toEpochSecond() : 
Duration.between(otherDate, date).getSeconds();
+        return otherDate == null ? date.toInstant().toEpochMilli() : 
Duration.between(otherDate, date).toMillis();
     }
 
     @Override
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
index 7c8984214a..f4e2aebd89 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStepTest.java
@@ -18,6 +18,9 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.util.Date;
 import org.apache.tinkerpop.gremlin.process.traversal.GType;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
@@ -31,6 +34,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
+import static java.time.ZoneOffset.UTC;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
@@ -61,6 +65,13 @@ public class AsNumberStepTest extends StepTest {
         assertEquals((short) 1, __.__("1").asNumber(GType.SHORT).next());
         assertEquals(1L, __.__("1").asNumber(GType.LONG).next());
         assertEquals(3.14, __.__("3.14").asNumber(GType.DOUBLE).next()); 
//float to double
+        // round trip date to number
+        final OffsetDateTime date = OffsetDateTime.of(LocalDateTime.of(2025, 
11, 3, 7, 20, 19, 0), UTC);
+        final long dateEpochMillis = date.toInstant().toEpochMilli();
+        assertEquals(date, __.__(date).asNumber().asDate().next());
+        assertEquals(dateEpochMillis, 
__.__(dateEpochMillis).asDate().asNumber().next());
+        assertEquals(dateEpochMillis, __.__(new 
Date(dateEpochMillis)).asNumber().next());
+        assertEquals(date, __.__(new 
Date(dateEpochMillis)).asNumber().asDate().next());
         // NumberUtils allows additional string processing
         assertEquals(123.0f, __.__("123.").asNumber().next());
         assertEquals(291, __.__("0x123").asNumber().next());
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStepTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStepTest.java
index 5fb8e0120f..34daf561b8 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStepTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStepTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import java.time.Instant;
+import java.time.LocalDateTime;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
@@ -46,7 +48,7 @@ public class DateDiffStepTest extends StepTest {
         final OffsetDateTime now = OffsetDateTime.now(UTC);
         final OffsetDateTime other = now.plus(Duration.ofDays(7));
 
-        assertEquals(604800L, (long) __.__(other).dateDiff(now).next());
+        assertEquals(604800000L, (long) __.__(other).dateDiff(now).next());
     }
 
     @Test
@@ -54,7 +56,7 @@ public class DateDiffStepTest extends StepTest {
         final OffsetDateTime now = OffsetDateTime.now(UTC);
         final OffsetDateTime other = now.plus(Duration.ofDays(7));
 
-        assertEquals(-604800L, (long) __.__(now).dateDiff(other).next());
+        assertEquals(-604800000L, (long) __.__(now).dateDiff(other).next());
     }
 
     @Test
@@ -62,21 +64,21 @@ public class DateDiffStepTest extends StepTest {
         final OffsetDateTime now = OffsetDateTime.now(UTC);
         final OffsetDateTime other = now.plus(Duration.ofDays(7));
 
-        assertEquals(-604800L, (long) 
__.__(now).dateDiff(__.constant(other)).next());
+        assertEquals(-604800000L, (long) 
__.__(now).dateDiff(__.constant(other)).next());
     }
 
     @Test
     public void shouldHandleNullTraversalParam() {
         final OffsetDateTime now = OffsetDateTime.now(UTC);
 
-        assertEquals(now.toEpochSecond(), (long) 
__.__(now).dateDiff(__.constant(null)).next());
+        assertEquals(now.toInstant().toEpochMilli(), (long) 
__.__(now).dateDiff(__.constant(null)).next());
     }
 
     @Test
     public void shouldHandleNullDate() {
         final OffsetDateTime now = OffsetDateTime.now(UTC);
 
-        assertEquals(now.toEpochSecond(), (long) 
__.__(now).dateDiff((OffsetDateTime) null).next());
+        assertEquals(now.toInstant().toEpochMilli(), (long) 
__.__(now).dateDiff((OffsetDateTime) null).next());
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -94,7 +96,7 @@ public class DateDiffStepTest extends StepTest {
         cal.add(Calendar.DAY_OF_MONTH, 7);
         final Date other = cal.getTime();
 
-        assertEquals(604800L, (long) __.__(other).dateDiff(now).next());
+        assertEquals(604800000L, (long) __.__(other).dateDiff(now).next());
     }
 
     @Test
@@ -107,7 +109,7 @@ public class DateDiffStepTest extends StepTest {
         cal.add(Calendar.DAY_OF_MONTH, 7);
         final Date other = cal.getTime();
 
-        assertEquals(-604800L, (long) __.__(now).dateDiff(other).next());
+        assertEquals(-604800000L, (long) __.__(now).dateDiff(other).next());
     }
 
     @Test
@@ -120,25 +122,32 @@ public class DateDiffStepTest extends StepTest {
         cal.add(Calendar.DAY_OF_MONTH, 7);
         final Date other = cal.getTime();
 
-        assertEquals(-604800L, (long) 
__.__(now).dateDiff(__.constant(other)).next());
+        assertEquals(-604800000L, (long) 
__.__(now).dateDiff(__.constant(other)).next());
     }
 
     @Test
     public void shouldHandleNullTraversalParamWithDateCompatibility() {
         final Date now = new Date();
 
-        assertEquals(now.getTime() / 1000, (long) 
__.__(now).dateDiff(__.constant(null)).next());
+        assertEquals(now.toInstant().toEpochMilli(), (long) 
__.__(now).dateDiff(__.constant(null)).next());
     }
 
     @Test
     public void shouldHandleNullDateWithDateCompatibility() {
         final Date now = new Date();
 
-        assertEquals(now.getTime() / 1000, (long) __.__(now).dateDiff((Date) 
null).next());
+        assertEquals(now.toInstant().toEpochMilli(), (long) 
__.__(now).dateDiff((Date) null).next());
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void shouldThrowWhenInputIsNull() {
         __.__((Object) null).dateDiff(new Date()).next();
     }
+
+    @Test
+    public void shouldRoundTripWithAsDate() {
+        final OffsetDateTime date = OffsetDateTime.of(LocalDateTime.of(2025, 
11, 3, 7, 20, 19, 0), UTC);
+        final OffsetDateTime epoch = Instant.EPOCH.atOffset(UTC);
+        assertEquals(date, 
__.__(date.toInstant().toEpochMilli()).asDate().dateDiff(epoch).asDate().next());
+    }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index be7233eb54..cfe8d03945 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -944,6 +944,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_injectX1_2X_asDate", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(new 
List<object> { 1, 2 }).AsDate()}}, 
                {"g_injectXnullX_asDate", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Inject<object>(null).AsDate()}}, 
                {"g_injectXinvalidstrX_asDate", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>("This String is not an ISO 8601 Date").AsDate()}}, 
+               {"g_V_valuesXbirthdayX_asDate_asNumber_asDate", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV("person").Property("name", "alice").Property("birthday", 
"2020-08-02").AddV("person").Property("name", "john").Property("birthday", 
"1988-12-10").AddV("person").Property("name", "charlie").Property("birthday", 
"2002-02-01").AddV("person").Property("name", "suzy").Property("birthday", 
"1965-10-31"), (g,p) =>g.V().Values<object>("birth [...]
                {"g_injectX5bX_asNumber", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((sbyte) 
5).AsNumber()}}, 
                {"g_injectX5sX_asNumber", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>((short) 
5).AsNumber()}}, 
                {"g_injectX5iX_asNumber", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Inject<object>(5).AsNumber()}}, 
@@ -970,6 +971,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXGType_INTX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().As("a").Out("knows").As("b").Math("a + 
b").By("age").AsNumber(GType.Int)}}, 
                
{"g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXGType_LONGX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithSideEffect("x", 100).V().Values<object>("age").Math("_ + 
x").AsNumber(GType.Long)}}, 
                {"g_V_valuesXageX_asString_asNumberXGType_DOUBLEX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Values<object>("age").AsString().AsNumber(GType.Double)}}, 
+               {"g_V_valuesXbirthdayX_asNumber_asDate_asNumber", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV("person").Property("name", "alice").Property("birthday", 
1596326400000).AddV("person").Property("name", "john").Property("birthday", 
597715200000).AddV("person").Property("name", "charlie").Property("birthday", 
1012521600000).AddV("person").Property("name", "suzy").Property("birthday", 
-131587200000), (g,p) =>g.V().Values<object>(" [...]
                {"g_injectX1_2X_asString", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(1, 
2).AsString()}}, 
                {"g_injectX1_2X_asStringXlocalX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(1, 2).AsString<object>(Scope.Local)}}, 
                {"g_injectXlist_1_2X_asStringXlocalX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(new List<object> { 1, 2 
}).AsString<object>(Scope.Local)}}, 
@@ -1085,6 +1087,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z"), 
DateTimeOffset.Parse("2023-08-02T00:00Z")).DateDiff(DateTimeOffset.Parse("2023-08-09T00:00Z"))}},
 
                {"g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-08T00:00Z"), 
DateTimeOffset.Parse("2023-08-08T00:00Z")).DateDiff(__.Constant<object>(DateTimeOffset.Parse("2023-08-01T00:00Z")))}},
 
                {"g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-08T00:00Z"), 
DateTimeOffset.Parse("2023-08-08T00:00Z")).DateDiff(__.Inject(DateTimeOffset.Parse("2023-10-11T00:00Z")))}},
 
+               
{"g_V_valuesXbirthdayX_asDate_dateDiffXdatetimeX19700101T0000ZXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV("person").Property("name", "alice").Property("birthday", 
"1596326400000").AddV("person").Property("name", "john").Property("birthday", 
"597715200000").AddV("person").Property("name", "charlie").Property("birthday", 
"1012521600000").AddV("person").Property("name", "suzy").Property("birthday", 
"-131587200000"), (g,p) [...]
+               
{"g_V_hasXname_aliceX_valuesXbirthdayX_asDate_dateDiffXconstantXnullXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV("person").Property("name", "alice").Property("birthday", 
1596326400000), (g,p) =>g.V().Has("name", 
"alice").Values<object>("birthday").AsDate().DateDiff(__.Constant<object>(null))}},
 
                {"g_injectXnullX_differenceXinjectX1XX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(null).Difference(__.Inject(1))}}, 
                {"g_V_valuesXnameX_differenceXV_foldX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Values<object>("name").Difference(__.V().Fold())}}, 
                {"g_V_fold_differenceXconstantXnullXX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Fold().Difference(__.Constant<object>(null))}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 84c97cad85..63119f6df3 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -914,6 +914,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_injectX1_2X_asDate": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject([]interface{}{1, 2}).AsDate()}}, 
     "g_injectXnullX_asDate": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject(nil).AsDate()}}, 
     "g_injectXinvalidstrX_asDate": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("This String 
is not an ISO 8601 Date").AsDate()}}, 
+    "g_V_valuesXbirthdayX_asDate_asNumber_asDate": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"alice").Property("birthday", "2020-08-02").AddV("person").Property("name", 
"john").Property("birthday", "1988-12-10").AddV("person").Property("name", 
"charlie").Property("birthday", "2002-02-01").AddV("person").Property("name", 
"suzy").Property("birthday", "1965-10-31")}, func(g *gremlingo.GraphTraversal 
[...]
     "g_injectX5bX_asNumber": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject(int8(5)).AsNumber()}}, 
     "g_injectX5sX_asNumber": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject(int16(5)).AsNumber()}}, 
     "g_injectX5iX_asNumber": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject(int32(5)).AsNumber()}}, 
@@ -940,6 +941,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXGType_INTX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().As("a").Out("knows").As("b").Math("a + 
b").By("age").AsNumber(gremlingo.GType.Int)}}, 
     "g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXGType_LONGX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.WithSideEffect("x", 
100).V().Values("age").Math("_ + x").AsNumber(gremlingo.GType.Long)}}, 
     "g_V_valuesXageX_asString_asNumberXGType_DOUBLEX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Values("age").AsString().AsNumber(gremlingo.GType.Double)}}, 
+    "g_V_valuesXbirthdayX_asNumber_asDate_asNumber": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"alice").Property("birthday", 1596326400000).AddV("person").Property("name", 
"john").Property("birthday", 597715200000).AddV("person").Property("name", 
"charlie").Property("birthday", 1012521600000).AddV("person").Property("name", 
"suzy").Property("birthday", -131587200000)}, func(g *gremlingo.GraphTrav [...]
     "g_injectX1_2X_asString": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(1, 
2).AsString()}}, 
     "g_injectX1_2X_asStringXlocalX": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(1, 
2).AsString(gremlingo.Scope.Local)}}, 
     "g_injectXlist_1_2X_asStringXlocalX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject([]interface{}{1, 
2}).AsString(gremlingo.Scope.Local)}}, 
@@ -1055,6 +1057,8 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject(time.Date(2023, 8, 2, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0)), time.Date(2023, 8, 2, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0))).DateDiff(time.Date(2023, 8, 9, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0)))}}, 
     "g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject(time.Date(2023, 8, 8, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0)), time.Date(2023, 8, 8, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 
0))).DateDiff(gremlingo.T__.Constant(time.Date(2023, 8, 1, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0))))}}, 
     "g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject(time.Date(2023, 8, 8, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0)), time.Date(2023, 8, 8, 0, 0, 0, 0, 
time.FixedZone("UTC+00:00", 0))).DateDiff(gremlingo.T__.Inject(time.Date(2023, 
10, 11, 0, 0, 0, 0, time.FixedZone("UTC+00:00", 0))))}}, 
+    "g_V_valuesXbirthdayX_asDate_dateDiffXdatetimeX19700101T0000ZXX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"alice").Property("birthday", "1596326400000").AddV("person").Property("name", 
"john").Property("birthday", "597715200000").AddV("person").Property("name", 
"charlie").Property("birthday", 
"1012521600000").AddV("person").Property("name", "suzy").Property("birthday", 
"-131587200000")}, fu [...]
+    "g_V_hasXname_aliceX_valuesXbirthdayX_asDate_dateDiffXconstantXnullXX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"alice").Property("birthday", 1596326400000)}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Has("name", 
"alice").Values("birthday").AsDate().DateDiff(gremlingo.T__.Constant(nil))}}, 
     "g_injectXnullX_differenceXinjectX1XX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.Inject(nil).Difference(gremlingo.T__.Inject(1))}}, 
     "g_V_valuesXnameX_differenceXV_foldX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Values("name").Difference(gremlingo.T__.V().Fold())}}, 
     "g_V_fold_differenceXconstantXnullXX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Fold().Difference(gremlingo.T__.Constant(nil))}}, 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index f75d6bcee3..5e0fc66f47 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -945,6 +945,7 @@ const gremlins = {
     g_injectX1_2X_asDate: [function({g}) { return g.inject([1, 2]).asDate() 
}], 
     g_injectXnullX_asDate: [function({g}) { return g.inject(null).asDate() }], 
     g_injectXinvalidstrX_asDate: [function({g}) { return g.inject("This String 
is not an ISO 8601 Date").asDate() }], 
+    g_V_valuesXbirthdayX_asDate_asNumber_asDate: [function({g}) { return 
g.addV("person").property("name", "alice").property("birthday", 
"2020-08-02").addV("person").property("name", "john").property("birthday", 
"1988-12-10").addV("person").property("name", "charlie").property("birthday", 
"2002-02-01").addV("person").property("name", "suzy").property("birthday", 
"1965-10-31") }, function({g}) { return 
g.V().values("birthday").asDate().asNumber().asDate() }], 
     g_injectX5bX_asNumber: [function({g}) { return g.inject(5).asNumber() }], 
     g_injectX5sX_asNumber: [function({g}) { return g.inject(5).asNumber() }], 
     g_injectX5iX_asNumber: [function({g}) { return g.inject(5).asNumber() }], 
@@ -971,6 +972,7 @@ const gremlins = {
     g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXGType_INTX: 
[function({g}) { return g.V().as("a").out("knows").as("b").math("a + 
b").by("age").asNumber(GType.int) }], 
     g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXGType_LONGX: 
[function({g}) { return g.withSideEffect("x", 100).V().values("age").math("_ + 
x").asNumber(GType.long) }], 
     g_V_valuesXageX_asString_asNumberXGType_DOUBLEX: [function({g}) { return 
g.V().values("age").asString().asNumber(GType.double) }], 
+    g_V_valuesXbirthdayX_asNumber_asDate_asNumber: [function({g}) { return 
g.addV("person").property("name", "alice").property("birthday", 
1596326400000).addV("person").property("name", "john").property("birthday", 
597715200000).addV("person").property("name", "charlie").property("birthday", 
1012521600000).addV("person").property("name", "suzy").property("birthday", 
-131587200000) }, function({g}) { return 
g.V().values("birthday").asNumber().asDate().asNumber() }], 
     g_injectX1_2X_asString: [function({g}) { return g.inject(1, 2).asString() 
}], 
     g_injectX1_2X_asStringXlocalX: [function({g}) { return g.inject(1, 
2).asString(Scope.local) }], 
     g_injectXlist_1_2X_asStringXlocalX: [function({g}) { return g.inject([1, 
2]).asString(Scope.local) }], 
@@ -1086,6 +1088,8 @@ const gremlins = {
     g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX: [function({g}) { return 
g.inject(new Date('2023-08-02T00:00Z'), new 
Date('2023-08-02T00:00Z')).dateDiff(new Date('2023-08-09T00:00Z')) }], 
     g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX: 
[function({g}) { return g.inject(new Date('2023-08-08T00:00Z'), new 
Date('2023-08-08T00:00Z')).dateDiff(__.constant(new Date('2023-08-01T00:00Z'))) 
}], 
     g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX: [function({g}) 
{ return g.inject(new Date('2023-08-08T00:00Z'), new 
Date('2023-08-08T00:00Z')).dateDiff(__.inject(new Date('2023-10-11T00:00Z'))) 
}], 
+    g_V_valuesXbirthdayX_asDate_dateDiffXdatetimeX19700101T0000ZXX: 
[function({g}) { return g.addV("person").property("name", 
"alice").property("birthday", "1596326400000").addV("person").property("name", 
"john").property("birthday", "597715200000").addV("person").property("name", 
"charlie").property("birthday", 
"1012521600000").addV("person").property("name", "suzy").property("birthday", 
"-131587200000") }, function({g}) { return 
g.V().values("birthday").asNumber().asDate().dateDiff(new [...]
+    g_V_hasXname_aliceX_valuesXbirthdayX_asDate_dateDiffXconstantXnullXX: 
[function({g}) { return g.addV("person").property("name", 
"alice").property("birthday", 1596326400000) }, function({g}) { return 
g.V().has("name", 
"alice").values("birthday").asDate().dateDiff(__.constant(null)) }], 
     g_injectXnullX_differenceXinjectX1XX: [function({g}) { return 
g.inject(null).difference(__.inject(1)) }], 
     g_V_valuesXnameX_differenceXV_foldX: [function({g}) { return 
g.V().values("name").difference(__.V().fold()) }], 
     g_V_fold_differenceXconstantXnullXX: [function({g}) { return 
g.V().fold().difference(__.constant(null)) }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index a1eddde85f..f371334d8f 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -917,6 +917,7 @@ world.gremlins = {
     'g_injectX1_2X_asDate': [(lambda g:g.inject([1, 2]).as_date())], 
     'g_injectXnullX_asDate': [(lambda g:g.inject(None).as_date())], 
     'g_injectXinvalidstrX_asDate': [(lambda g:g.inject('This String is not an 
ISO 8601 Date').as_date())], 
+    'g_V_valuesXbirthdayX_asDate_asNumber_asDate': [(lambda 
g:g.add_v('person').property('name', 'alice').property('birthday', 
'2020-08-02').add_v('person').property('name', 'john').property('birthday', 
'1988-12-10').add_v('person').property('name', 'charlie').property('birthday', 
'2002-02-01').add_v('person').property('name', 'suzy').property('birthday', 
'1965-10-31')), (lambda 
g:g.V().values('birthday').as_date().as_number().as_date())], 
     'g_injectX5bX_asNumber': [(lambda g:g.inject(5).as_number())], 
     'g_injectX5sX_asNumber': [(lambda g:g.inject(5).as_number())], 
     'g_injectX5iX_asNumber': [(lambda g:g.inject(5).as_number())], 
@@ -943,6 +944,7 @@ world.gremlins = {
     'g_V_asXaX_outXknowsX_asXbX_mathXa_plus_bX_byXageX_asNumberXGType_INTX': 
[(lambda g:g.V().as_('a').out('knows').as_('b').math('a + 
b').by('age').as_number(GType.INT))], 
     'g_withSideEffectXx_100X_V_age_mathX__plus_xX_asNumberXGType_LONGX': 
[(lambda g:g.with_side_effect('x', 100).V().values('age').math('_ + 
x').as_number(GType.LONG))], 
     'g_V_valuesXageX_asString_asNumberXGType_DOUBLEX': [(lambda 
g:g.V().values('age').as_string().as_number(GType.DOUBLE))], 
+    'g_V_valuesXbirthdayX_asNumber_asDate_asNumber': [(lambda 
g:g.add_v('person').property('name', 'alice').property('birthday', 
long(1596326400000)).add_v('person').property('name', 
'john').property('birthday', 
long(597715200000)).add_v('person').property('name', 
'charlie').property('birthday', 
long(1012521600000)).add_v('person').property('name', 
'suzy').property('birthday', long(-131587200000))), (lambda 
g:g.V().values('birthday').as_number().as_date().as_number())], 
     'g_injectX1_2X_asString': [(lambda g:g.inject(1, 2).as_string())], 
     'g_injectX1_2X_asStringXlocalX': [(lambda g:g.inject(1, 
2).as_string(Scope.local))], 
     'g_injectXlist_1_2X_asStringXlocalX': [(lambda g:g.inject([1, 
2]).as_string(Scope.local))], 
@@ -1058,6 +1060,8 @@ world.gremlins = {
     'g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX': [(lambda 
g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00'), 
datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_diff(datetime.datetime.fromisoformat('2023-08-09T00:00+00:00')))],
 
     'g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX': [(lambda 
g:g.inject(datetime.datetime.fromisoformat('2023-08-08T00:00+00:00'), 
datetime.datetime.fromisoformat('2023-08-08T00:00+00:00')).date_diff(__.constant(datetime.datetime.fromisoformat('2023-08-01T00:00+00:00'))))],
 
     'g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX': [(lambda 
g:g.inject(datetime.datetime.fromisoformat('2023-08-08T00:00+00:00'), 
datetime.datetime.fromisoformat('2023-08-08T00:00+00:00')).date_diff(__.inject(datetime.datetime.fromisoformat('2023-10-11T00:00+00:00'))))],
 
+    'g_V_valuesXbirthdayX_asDate_dateDiffXdatetimeX19700101T0000ZXX': [(lambda 
g:g.add_v('person').property('name', 'alice').property('birthday', 
'1596326400000').add_v('person').property('name', 'john').property('birthday', 
'597715200000').add_v('person').property('name', 
'charlie').property('birthday', 
'1012521600000').add_v('person').property('name', 'suzy').property('birthday', 
'-131587200000')), (lambda 
g:g.V().values('birthday').as_number().as_date().date_diff(datetime.datetime.fro
 [...]
+    'g_V_hasXname_aliceX_valuesXbirthdayX_asDate_dateDiffXconstantXnullXX': 
[(lambda g:g.add_v('person').property('name', 'alice').property('birthday', 
long(1596326400000))), (lambda g:g.V().has('name', 
'alice').values('birthday').as_date().date_diff(__.constant(None)))], 
     'g_injectXnullX_differenceXinjectX1XX': [(lambda 
g:g.inject(None).difference(__.inject(1)))], 
     'g_V_valuesXnameX_differenceXV_foldX': [(lambda 
g:g.V().values('name').difference(__.V().fold()))], 
     'g_V_fold_differenceXconstantXnullXX': [(lambda 
g:g.V().fold().difference(__.constant(None)))], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/data/DateTime.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/data/DateTime.feature
index e6b6722109..a2cd4c65fa 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/data/DateTime.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/data/DateTime.feature
@@ -61,7 +61,7 @@ Feature: Data - DATETIME
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[-30].l |
+      | d[-30000].l |
 
   Scenario: 
g_V_valuesXdatetimeX_isXtypeOfXGType_DATETIMEXX_whereXisXgtXdatetimeX2020_01_01XXXX
     Given the empty graph
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsDate.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsDate.feature
index 0e01fb9251..1a1e9f3168 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsDate.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsDate.feature
@@ -104,4 +104,26 @@ Feature: Step - asDate()
       g.inject('This String is not an ISO 8601 Date').asDate()
       """
     When iterated to list
-    Then the traversal will raise an error with message containing text of 
"Can't parse"
\ No newline at end of file
+    Then the traversal will raise an error with message containing text of 
"Can't parse"
+    
+  #  asDate should be round-trippable with asNumber
+  Scenario: g_V_valuesXbirthdayX_asDate_asNumber_asDate
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "alice").property("birthday", 
"2020-08-02").
+        addV("person").property("name", "john").property("birthday", 
"1988-12-10").
+        addV("person").property("name","charlie").property("birthday", 
"2002-02-01").
+        addV("person").property("name", "suzy").property("birthday", 
"1965-10-31")
+      """
+    And the traversal of
+      """
+      g.V().values("birthday").asDate().asNumber().asDate()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | dt[2020-08-02T00:00:00Z] |
+      | dt[1988-12-10T00:00:00Z] |
+      | dt[2002-02-01T00:00:00Z] |
+      | dt[1965-10-31T00:00:00Z] |
\ No newline at end of file
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
index 831c0b8c4b..6b6680753b 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AsNumber.feature
@@ -325,3 +325,25 @@ Feature: Step - asNumber()
       | d[27.0].d |
       | d[32.0].d |
       | d[35.0].d |
+
+  #  asNumber should be round-trippable with asDate
+  Scenario: g_V_valuesXbirthdayX_asNumber_asDate_asNumber
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "alice").property("birthday", 
1596326400000).
+        addV("person").property("name", "john").property("birthday", 
597715200000).
+        addV("person").property("name","charlie").property("birthday", 
1012521600000).
+        addV("person").property("name", "suzy").property("birthday", 
-131587200000)
+      """
+    And the traversal of
+      """
+      g.V().values("birthday").asNumber().asDate().asNumber()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[597715200000].l |
+      | d[1596326400000].l |
+      | d[1012521600000].l |
+      | d[-131587200000].l |
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/DateDiff.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/DateDiff.feature
index 5d115b351c..aa15c2e6b4 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/DateDiff.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/DateDiff.feature
@@ -28,8 +28,8 @@ Feature: Step - dateDiff()
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[-604800].l |
-      | d[-604800].l |
+      | d[-604800000].l |
+      | d[-604800000].l |
 
   @GraphComputerVerificationInjectionNotSupported
   Scenario: g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX
@@ -41,8 +41,8 @@ Feature: Step - dateDiff()
     When iterated to list
     Then the result should be unordered
       | result |
-      | d[604800].l |
-      | d[604800].l |
+      | d[604800000].l |
+      | d[604800000].l |
 
   @GraphComputerVerificationInjectionNotSupported
   Scenario: g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX
@@ -55,4 +55,40 @@ Feature: Step - dateDiff()
     Then the result should be unordered
       | result |
       | d[0].l |
-      | d[0].l |
\ No newline at end of file
+      | d[0].l |
+
+  Scenario: g_V_valuesXbirthdayX_asDate_dateDiffXdatetimeX19700101T0000ZXX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "alice").property("birthday", 
"1596326400000").
+        addV("person").property("name", "john").property("birthday", 
"597715200000").
+        addV("person").property("name","charlie").property("birthday", 
"1012521600000").
+        addV("person").property("name", "suzy").property("birthday", 
"-131587200000")
+      """
+    And the traversal of
+      """
+      
g.V().values("birthday").asNumber().asDate().dateDiff(datetime("1970-01-01T00:00Z"))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[597715200000].l |
+      | d[1596326400000].l |
+      | d[1012521600000].l |
+      | d[-131587200000].l |
+
+  Scenario: 
g_V_hasXname_aliceX_valuesXbirthdayX_asDate_dateDiffXconstantXnullXX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "alice").property("birthday", 
1596326400000)
+      """
+    And the traversal of
+      """
+      g.V().has("name", 
"alice").values("birthday").asDate().dateDiff(__.constant(null))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[1596326400000].l |
\ No newline at end of file


Reply via email to