You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2025/04/11 18:17:15 UTC

(tinkerpop) branch 3.8-dev updated: Backport OffsetDateTime changes from 4.0 (#3090)

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

xiazcy 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 a0c5851521 Backport OffsetDateTime changes from 4.0 (#3090)
a0c5851521 is described below

commit a0c5851521be7c29e2dd4afb701b5a79188d1dbd
Author: Yang Xia <55...@users.noreply.github.com>
AuthorDate: Fri Apr 11 11:17:10 2025 -0700

    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).
---
 CHANGELOG.asciidoc                                 |   2 +
 docs/src/reference/the-traversal.asciidoc          |   7 +-
 docs/src/upgrade/release-3.8.x.asciidoc            |  23 ++++
 .../tinkerpop/gremlin/jsr223/CoreImports.java      |   1 +
 .../gremlin/language/grammar/ArgumentVisitor.java  |   7 +-
 .../language/grammar/GenericLiteralVisitor.java    |   6 +-
 .../translator/AnonymizedTranslatorVisitor.java    |   4 +-
 .../translator/DotNetTranslateVisitor.java         |  10 +-
 .../language/translator/GoTranslateVisitor.java    |  15 +-
 .../language/translator/JavaTranslateVisitor.java  |  10 +-
 .../translator/JavascriptTranslateVisitor.java     |  11 +-
 .../translator/PythonTranslateVisitor.java         |   8 +-
 .../gremlin/process/traversal/Translator.java      |   9 ++
 .../traversal/dsl/graph/GraphTraversal.java        |  28 +++-
 .../gremlin/process/traversal/dsl/graph/__.java    |  18 ++-
 .../process/traversal/step/map/AsDateStep.java     |  29 ++--
 .../process/traversal/step/map/DateAddStep.java    |  60 +++++---
 .../process/traversal/step/map/DateDiffStep.java   |  61 +++++++--
 .../translator/AnonymizingTypeTranslator.java      |   8 ++
 .../traversal/translator/DotNetTranslator.java     |   6 +
 .../traversal/translator/GolangTranslator.java     |  14 ++
 .../traversal/translator/GroovyTranslator.java     |  11 ++
 .../traversal/translator/JavascriptTranslator.java |   6 +
 .../traversal/translator/PythonTranslator.java     |   8 ++
 .../tinkerpop/gremlin/util/DatetimeHelper.java     |  32 ++---
 .../grammar/GeneralLiteralVisitorTest.java         |  37 ++---
 .../language/translator/GremlinTranslatorTest.java |  23 +++-
 .../process/traversal/step/map/AsDateStepTest.java |  26 +++-
 .../traversal/step/map/DateAddStepTest.java        |  62 +++++++--
 .../traversal/step/map/DateDiffStepTest.java       |  62 +++++++--
 .../translator/AnonymizingTypeTranslatorTest.java  |   9 ++
 .../traversal/translator/DotNetTranslatorTest.java |   9 +-
 .../traversal/translator/GolangTranslatorTest.java |  15 ++
 .../traversal/translator/GroovyTranslatorTest.java |  15 +-
 .../translator/JavascriptTranslatorTest.java       |   9 +-
 .../traversal/translator/PythonTranslatorTest.java |  15 ++
 .../tinkerpop/gremlin/util/DatetimeHelperTest.java |  54 ++++----
 .../Structure/IO/GraphBinary/DataType.cs           |   1 +
 .../IO/GraphBinary/TypeSerializerRegistry.cs       |   7 +-
 ...meOffsetSerializer.cs => DateTimeSerializer.cs} |  10 +-
 .../GraphBinary/Types/OffsetDateTimeSerializer.cs  |  80 +++++++++++
 .../Structure/IO/GraphSON/GraphSONReader.cs        |   1 +
 .../Structure/IO/GraphSON/GraphSONWriter.cs        |   2 +-
 ...Serializer.cs => OffsetDateTimeDeserializer.cs} |  12 +-
 ...teSerializer.cs => OffsetDateTimeSerializer.cs} |   4 +-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  19 +--
 .../Structure/IO/GraphSON/GraphSONWriterTests.cs   |   2 +-
 gremlin-go/driver/cucumber/cucumberSteps_test.go   |   7 +-
 gremlin-go/driver/cucumber/gremlin.go              |  19 +--
 gremlin-go/driver/graphBinary.go                   |  73 +++++++++-
 gremlin-go/driver/graphBinary_test.go              |  33 +++++
 gremlin-go/driver/serializer.go                    |   8 +-
 .../lib/structure/io/binary/GraphBinary.js         |   1 +
 .../structure/io/binary/internals/AnySerializer.js |   1 +
 .../binary/internals/OffsetDateTimeSerializer.js   | 151 +++++++++++++++++++++
 .../lib/structure/io/graph-serializer.js           |   3 +-
 .../lib/structure/io/type-serializers.js           |  13 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    |  19 +--
 .../test/unit/graphbinary/AnySerializer-test.js    |  16 ++-
 .../gremlin-javascript/test/unit/graphson-test.js  |   4 +-
 .../gremlin_python/structure/io/graphbinaryV1.py   |  40 +++++-
 .../gremlin_python/structure/io/graphsonV2d0.py    |  19 ++-
 .../gremlin_python/structure/io/graphsonV3d0.py    |  19 ++-
 .../src/main/python/radish/feature_steps.py        |   2 +-
 gremlin-python/src/main/python/radish/gremlin.py   |  19 +--
 .../main/python/tests/process/test_traversal.py    |   3 +-
 .../tests/structure/io/test_functionalityio.py     |  14 ++
 .../tests/structure/io/test_graphbinaryV1.py       |  32 ++++-
 .../python/tests/structure/io/test_graphsonV2d0.py |  24 +++-
 .../python/tests/structure/io/test_graphsonV3d0.py |  24 +++-
 .../server/GremlinServerHttpIntegrateTest.java     |   2 +-
 .../process/traversal/step/OrderabilityTest.java   |  13 +-
 .../gremlin/test/features/map/AsDate.feature       |  12 ++
 .../util/ser/binary/types/sample/SamplePerson.java |   8 +-
 .../types/sample/SamplePersonSerializer.java       |   4 +-
 .../types/sample/SamplePersonSerializerTest.java   |   5 +-
 76 files changed, 1151 insertions(+), 305 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 73aa930c44..f50e509d06 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -49,6 +49,8 @@ This release also includes changes from <<release-3-7-XXX, 3.7.XXX>>.
 * 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.
 * Changed `DetachedFactory` to special case the handling of `ComputerAdjacentVertex` which doesn't carry properties but still needs to be detachable for OLAP cases.
 * Deprecated `ProfilingAware.prepareForProfiling` method preferring to simply `resetBarrierFromValueTraversal` from the `Grouping` interface after strategy application.
+* Deprecated `Date` in favor of `OffsetDateTime` as the default date type in core, `Date` is still supported as input to date steps for compatibility.
+* 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.
 * Added missing strategies in `gremlin-go`, updated certain strategies to take varargs and updated `GoTranslatorVisitor` for corresponding translations.
 * Fixed `BigInt` and `BigDecimal` parsing in `gremlin-go` cucumber test suite, fixed `UnscaledValue` type in `BigDecimal` struct and added `ParseBigDecimal` method.
 * Added validation to `groupCount()` to prevent an invalid usage of multiple `by()` modulators.
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 51a0f94a59..797fb53a21 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -812,7 +812,7 @@ The `asDate()`-step (*map*) converts string or numeric input to Date.
 For string input only ISO-8601 format is supported. For numbers, the value is considered as the number of the
 milliseconds since "the epoch" (January 1, 1970, 00:00:00 GMT). Date input is passed without changes.
 
-If the incoming traverser is not a string, number or Date then an `IllegalArgumentException` will be thrown.
+If the incoming traverser is not a string, number, Date or OffsetDateTime then an `IllegalArgumentException` will be thrown.
 
 [gremlin-groovy,modern]
 ----
@@ -1354,7 +1354,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 === DateAdd Step
 
 The `dateAdd()`-step (*map*) returns the value with the addition of the value number of units as specified by the DateToken. 
-If the incoming traverser is not a Date, then an `IllegalArgumentException` will be thrown.
+If the incoming traverser is not a Date or OffsetDateTime, then an `IllegalArgumentException` will be thrown.
 
 [gremlin-groovy,modern]
 ----
@@ -1373,7 +1373,7 @@ link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gre
 === DateDiff Step
 
 The `dateDiff()`-step (*map*) returns the difference between two Dates in epoch time. 
-If the incoming traverser is not a Date, then an `IllegalArgumentException` will be thrown.
+If the incoming traverser is not a Date or OffsetDateTime, then an `IllegalArgumentException` will be thrown.
 
 [gremlin-groovy,modern]
 ----
@@ -1385,6 +1385,7 @@ g.inject("2023-08-02T00:00:00Z").asDate().dateDiff(constant("2023-08-03T00:00:00
 *Additional References*
 
 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)`],
+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)`],
 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)`]
 
 [[dedup-step]]
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc b/docs/src/upgrade/release-3.8.x.asciidoc
index 30e9f8860a..b241931d94 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -30,6 +30,17 @@ complete list of all the modifications that are part of this release.
 
 === Upgrading for Users
 
+==== The Switch from Date to OffsetDateTime
+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.
+
+`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).
+
+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).
+
+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 [...]
+
+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.
+
 ==== Simplification to g creation
 The creation of "g" is the start point to writing Gremlin. There are a number of ways to create it, but TinkerPop has
 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]
 
 ==== Graph System Providers
 
+==== The Switch from Date to OffsetDateTime
+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.
+
+`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).
+
+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.
+
 ==== Graph Driver Providers
+
+==== The Switch from Date to OffsetDateTime
+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.
+
+This means that drivers should use the extended `OffsetDateTime` type in the IO specs to serialize and deserialize native date objects.
\ No newline at end of file
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index dcac5c222b..a4d77b0fd2 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -330,6 +330,7 @@ public final class CoreImports {
         CLASS_IMPORTS.add(TimeUtil.class);
         CLASS_IMPORTS.add(Lambda.class);
         CLASS_IMPORTS.add(java.util.Date.class);
+        CLASS_IMPORTS.add(java.time.OffsetDateTime.class);
         CLASS_IMPORTS.add(java.sql.Timestamp.class);
         CLASS_IMPORTS.add(java.util.UUID.class);
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
index 7d808d16c4..d153085205 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/ArgumentVisitor.java
@@ -22,7 +22,8 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.lang.reflect.Array;
-import java.util.Date;
+import java.time.OffsetDateTime;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.Objects;
 
@@ -68,8 +69,8 @@ public class ArgumentVisitor extends DefaultGremlinBaseVisitor<Object> {
     /**
      * Wrapper to visit function for Date type.
      */
-    public Date parseDate(final GremlinParser.DateArgumentContext ctx) {
-        return (Date) visitDateArgument(ctx);
+    public OffsetDateTime parseDate(final GremlinParser.DateArgumentContext ctx) {
+        return (OffsetDateTime) visitDateArgument(ctx);
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index 07eb21f048..04499f1380 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -31,8 +31,8 @@ import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -86,8 +86,8 @@ public class GenericLiteralVisitor extends DefaultGremlinBaseVisitor<Object> {
     /**
      * Parse a Date based literal context and return the Date.
      */
-    public Date parseDate(final GremlinParser.DateLiteralContext dateLiteral) {
-        return (Date) visitDateLiteral(dateLiteral);
+    public OffsetDateTime parseDate(final GremlinParser.DateLiteralContext dateLiteral) {
+        return (OffsetDateTime) visitDateLiteral(dateLiteral);
     }
 
     /**
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
index 225baacbba..8537df8e32 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/AnonymizedTranslatorVisitor.java
@@ -23,7 +23,7 @@ import org.apache.tinkerpop.gremlin.language.grammar.GremlinParser;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.util.Date;
+import java.time.OffsetDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -167,7 +167,7 @@ public class AnonymizedTranslatorVisitor extends TranslateVisitor {
 
     @Override
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
-        return anonymize(ctx, Date.class);
+        return anonymize(ctx, OffsetDateTime.class);
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
index 7a0a8f74a7..08c5de23eb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/DotNetTranslateVisitor.java
@@ -27,7 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Option
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
-import java.util.Date;
+import java.time.OffsetDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -158,10 +158,10 @@ public class DotNetTranslateVisitor extends AbstractTranslateVisitor {
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
         // child at 2 is the date argument to datetime() and comes enclosed in quotes
         final String dtString = ctx.getChild(2).getText();
-        final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
-        sb.append("DateTimeOffset.FromUnixTimeMilliseconds(");
-        sb.append(dt.getTime());
-        sb.append(")");
+        final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
+        sb.append("DateTimeOffset.Parse(\"");
+        sb.append(dt);
+        sb.append("\")");
         return null;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
index 32130ed631..8b75a30182 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/GoTranslateVisitor.java
@@ -27,9 +27,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Option
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -57,8 +57,17 @@ public class GoTranslateVisitor extends AbstractTranslateVisitor {
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
         // child at 2 is the date argument to datetime() and comes enclosed in quotes
         final String dtString = ctx.getChild(2).getText();
-        final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
-        sb.append("time.UnixMilli(" + dt.getTime() + ")");
+        final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
+        final String zoneInfo = dt.getOffset().getId().equals("Z") ? "UTC+00:00" : "UTC" + dt.getOffset().getId();
+        sb.append("time.Date(").append(dt.getYear()).
+                append(", ").append(dt.getMonthValue()).
+                append(", ").append(dt.getDayOfMonth()).
+                append(", ").append(dt.getHour()).
+                append(", ").append(dt.getMinute()).
+                append(", ").append(dt.getSecond()).
+                append(", ").append(dt.getNano()).
+                append(", time.FixedZone(\"").append(zoneInfo).append("\", ").append(dt.getOffset().getTotalSeconds()).append(")").
+                append(")");
         return null;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavaTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavaTranslateVisitor.java
index f0843b18d8..26b9b70efc 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavaTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavaTranslateVisitor.java
@@ -25,7 +25,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Option
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
-import java.util.Date;
+import java.time.OffsetDateTime;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -152,10 +152,10 @@ public class JavaTranslateVisitor extends AbstractTranslateVisitor {
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
         // child at 2 is the date argument to datetime() and comes enclosed in quotes
         final String dtString = ctx.getChild(2).getText();
-        final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
-        sb.append("new Date(");
-        sb.append(dt.getTime());
-        sb.append(")");
+        final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
+        sb.append("OffsetDateTime.parse(\"");
+        sb.append(dt);
+        sb.append("\")");
         return null;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
index 364b1f5ad6..e247e5e749 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/JavascriptTranslateVisitor.java
@@ -27,7 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
-import java.util.Date;
+import java.time.OffsetDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -134,10 +134,11 @@ public class JavascriptTranslateVisitor extends AbstractTranslateVisitor {
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
         // child at 2 is the date argument to datetime() and comes enclosed in quotes
         final String dtString = ctx.getChild(2).getText();
-        final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
-        sb.append("new Date(");
-        sb.append(dt.getTime());
-        sb.append(")");
+        // for consistency, use the way OffsetDateTime formats the date strings
+        final OffsetDateTime dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
+        sb.append("new Date('");
+        sb.append(dt);
+        sb.append("')");
         return null;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
index 9d2109b2da..4cf0eb8a61 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/translator/PythonTranslateVisitor.java
@@ -26,7 +26,6 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
 import java.math.BigInteger;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -161,8 +160,11 @@ public class PythonTranslateVisitor extends AbstractTranslateVisitor {
     public Void visitDateLiteral(final GremlinParser.DateLiteralContext ctx) {
         // child at 2 is the date argument to datetime() and comes enclosed in quotes
         final String dtString = ctx.getChild(2).getText();
-        final Date dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString));
-        sb.append("datetime.datetime.utcfromtimestamp(" + dt.getTime() + " / 1000.0)");
+        // for consistency, use the way OffsetDateTime formats the date strings
+        final String dt = DatetimeHelper.parse(removeFirstAndLastCharacters(dtString)).toString();
+        // specially handling as python isoformat does not support zulu until 3.11
+        final String dtISOString = dt.endsWith("Z") ? dt.replace("Z", "+00:00") : dt;
+        sb.append("datetime.datetime.fromisoformat('").append(dtISOString).append("')");
         return null;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
index 120176821a..29f846cda8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -139,6 +140,11 @@ public interface Translator<S, T> {
              */
             protected abstract String getSyntax(final Date o);
 
+            /**
+             * Take the {@code OffsetDateTime} argument and convert it to a string representation in the target language.
+             */
+            protected abstract String getSyntax(final OffsetDateTime o);
+
             /**
              * Take the {@code Timestamp} argument and convert it to a string representation in the target language.
              */
@@ -310,6 +316,9 @@ public interface Translator<S, T> {
                 } else if (object instanceof Date) {
                     final Object objectOrWrapper = withParameters ? object : getSyntax((Date) object);
                     return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
+                } else if (object instanceof OffsetDateTime) {
+                    final Object objectOrWrapper = withParameters ? object : getSyntax((OffsetDateTime) object);
+                    return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
                 } else if (object instanceof UUID) {
                     final Object objectOrWrapper = withParameters ? object : getSyntax((UUID) object);
                     return script.getBoundKeyOrAssign(withParameters, objectOrWrapper);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index c97a172b6d..32b830c252 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -204,6 +204,7 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -1840,25 +1841,25 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
-     * Parse value of the incoming traverser as an ISO-8601 {@link Date}.
+     * Parse value of the incoming traverser as an ISO-8601 {@link OffsetDateTime}.
      *
      * @return the traversal with an appended {@link AsDateStep}.
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#asDate-step" target="_blank">Reference Documentation - asDate Step</a>
      * @since 3.7.1
      */
-    public default GraphTraversal<S, Date> asDate() {
+    public default GraphTraversal<S, OffsetDateTime> asDate() {
         this.asAdmin().getBytecode().addStep(Symbols.asDate);
         return this.asAdmin().addStep(new AsDateStep<>(this.asAdmin()));
     }
 
     /**
-     * Increase value of input {@link Date}.
+     * Increase value of input {@link OffsetDateTime}.
      *
      * @return the traversal with an appended {@link DateAddStep}.
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#dateAdd-step" target="_blank">Reference Documentation - dateAdd Step</a>
      * @since 3.7.1
      */
-    public default GraphTraversal<S, Date> dateAdd(final DT dateToken, final int value) {
+    public default GraphTraversal<S, OffsetDateTime> dateAdd(final DT dateToken, final int value) {
         this.asAdmin().getBytecode().addStep(Symbols.dateAdd, dateToken, value);
         return this.asAdmin().addStep(new DateAddStep<>(this.asAdmin(), dateToken, value));
     }
@@ -1869,20 +1870,35 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @return the traversal with an appended {@link DateDiffStep}.
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#dateDiff-step" target="_blank">Reference Documentation - dateDiff Step</a>
      * @since 3.7.1
+     * @deprecated As of release 3.8.0, deprecated in favor of {@link GraphTraversal#dateDiff(OffsetDateTime)}.
      */
+    @Deprecated
     public default GraphTraversal<S, Long> dateDiff(final Date value) {
         this.asAdmin().getBytecode().addStep(Symbols.dateDiff, value);
         return this.asAdmin().addStep(new DateDiffStep<>(this.asAdmin(), value));
     }
 
     /**
-     * Returns the difference between two {@link Date} in epoch time.
+     * Returns the difference between two {@link OffsetDateTime} in epoch time.
+     *
+     * @return the traversal with an appended {@link DateDiffStep}.
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#dateDiff-step" target="_blank">Reference Documentation - dateDiff Step</a>
+     * @since 3.7.1
+     */
+    public default GraphTraversal<S, Long> dateDiff(final OffsetDateTime value) {
+        this.asAdmin().getBytecode().addStep(Symbols.dateDiff, value);
+        return this.asAdmin().addStep(new DateDiffStep<>(this.asAdmin(), value));
+    }
+
+    /**
+     * Returns the difference between two dates in epoch time.
      *
+     * @param dateTraversal a traversal that supplies a {@link OffsetDateTime} object ({@link Date} is also accepted for compatibility).
      * @return the traversal with an appended {@link DateDiffStep}.
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#dateDiff-step" target="_blank">Reference Documentation - dateDiff Step</a>
      * @since 3.7.1
      */
-    public default GraphTraversal<S, Long> dateDiff(final Traversal<?, Date> dateTraversal) {
+    public default GraphTraversal<S, Long> dateDiff(final Traversal<?, ?> dateTraversal) {
         this.asAdmin().getBytecode().addStep(Symbols.dateDiff, dateTraversal);
         return this.asAdmin().addStep(new DateDiffStep<>(this.asAdmin(), dateTraversal));
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 270317772c..e1edcfc5f4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -37,6 +37,7 @@ import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 
+import java.time.OffsetDateTime;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Iterator;
@@ -774,28 +775,37 @@ public class __ {
     /**
      * @see GraphTraversal#asDate()
      */
-    public static <A> GraphTraversal<A, Date> asDate() {
+    public static <A> GraphTraversal<A, OffsetDateTime> asDate() {
         return __.<A>start().asDate();
     }
 
     /**
      * @see GraphTraversal#dateAdd(DT, int)
      */
-    public static <A> GraphTraversal<A, Date> dateAdd(final DT dateToken, final int value) {
+    public static <A> GraphTraversal<A, OffsetDateTime> dateAdd(final DT dateToken, final int value) {
         return __.<A>start().dateAdd(dateToken, value);
     }
 
     /**
-     * @see GraphTraversal#dateDiff(Date)
+     * @see GraphTraversal#dateDiff(OffsetDateTime)
+     * @deprecated As of release 3.8.0, deprecated in favor of {@link GraphTraversal#dateDiff(OffsetDateTime)}.
      */
+    @Deprecated
     public static <A> GraphTraversal<A, Long> dateDiff(final Date value) {
         return __.<A>start().dateDiff(value);
     }
 
+    /**
+     * @see GraphTraversal#dateDiff(OffsetDateTime)
+     */
+    public static <A> GraphTraversal<A, Long> dateDiff(final OffsetDateTime value) {
+        return __.<A>start().dateDiff(value);
+    }
+
     /**
      * @see GraphTraversal#dateDiff(Traversal)
      */
-    public static <A> GraphTraversal<A, Long> dateDiff(final Traversal<?, Date> dateTraversal) {
+    public static <A> GraphTraversal<A, Long> dateDiff(final Traversal<?, OffsetDateTime> dateTraversal) {
         return __.<A>start().dateDiff(dateTraversal);
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java
index 52609644d1..c9d26e937f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java
@@ -20,18 +20,17 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.DatetimeHelper;
 
 import java.math.BigInteger;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
 import java.time.format.DateTimeParseException;
 import java.util.Collections;
 import java.util.Date;
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -39,27 +38,29 @@ import java.util.Set;
  *
  * @author Valentyn Kahamlyk
  */
-public final class AsDateStep<S> extends ScalarMapStep<S, Date> {
+public final class AsDateStep<S> extends ScalarMapStep<S, OffsetDateTime> {
 
     public AsDateStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
-    protected Date map(final Traverser.Admin<S> traverser) {
+    protected OffsetDateTime map(final Traverser.Admin<S> traverser) {
         final Object object = traverser.get();
         if (object == null)
-            throw new IllegalArgumentException("Can't parse null as Date.");
+            throw new IllegalArgumentException("Can't parse null as OffsetDateTime.");
         if (object instanceof Date)
-            return (Date) object;
+            return OffsetDateTime.ofInstant(((Date) object).toInstant(), ZoneOffset.UTC);
+        if (object instanceof OffsetDateTime)
+            return (OffsetDateTime) object;
         if (object instanceof Byte || object instanceof Short || object instanceof Integer || object instanceof Long)
-            // numbers handled as milliseconds since January 1, 1970, 00:00:00 GMT.
-            return new Date(((Number) object).longValue());
+            // numbers handled as milliseconds since January 1, 1970, 00:00:00 UTC.
+            return OffsetDateTime.ofInstant(Instant.ofEpochMilli(((Number) object).longValue()), ZoneOffset.UTC);
         if (object instanceof BigInteger) {
             try {
-                return new Date(((BigInteger) object).longValueExact());
+                return OffsetDateTime.ofInstant(Instant.ofEpochMilli(((BigInteger) object).longValueExact()), ZoneOffset.UTC);
             } catch (ArithmeticException ae) {
-                throw new IllegalArgumentException("Can't parse " + object + " as Date.");
+                throw new IllegalArgumentException("Can't parse " + object + " as OffsetDateTime.");
             }
         }
 
@@ -68,11 +69,11 @@ public final class AsDateStep<S> extends ScalarMapStep<S, Date> {
                 return DatetimeHelper.parse((String) object);
             }
             catch (DateTimeParseException e) {
-                throw new IllegalArgumentException("Can't parse " + object + " as Date.");
+                throw new IllegalArgumentException("Can't parse " + object + " as OffsetDateTime.");
             }
         }
 
-        throw new IllegalArgumentException("Can't parse " + object.getClass().getName() + " as Date.");
+        throw new IllegalArgumentException("Can't parse " + object.getClass().getName() + " as OffsetDateTime.");
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStep.java
index ef45701d1f..adf44e7125 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStep.java
@@ -24,11 +24,11 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
-import java.util.Calendar;
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -36,37 +36,51 @@ import java.util.Set;
  *
  * @author Valentyn Kahamlyk
  */
-public final class DateAddStep<S> extends ScalarMapStep<S, Date> {
-
-    final static Map<DT, Integer> DTtoCalendar = new HashMap<>();
-
-    static {
-        DTtoCalendar.put(DT.second, Calendar.SECOND);
-        DTtoCalendar.put(DT.minute, Calendar.MINUTE);
-        DTtoCalendar.put(DT.hour, Calendar.HOUR_OF_DAY);
-        DTtoCalendar.put(DT.day, Calendar.DAY_OF_MONTH);
-    }
+public final class DateAddStep<S> extends ScalarMapStep<S, OffsetDateTime> {
 
     private DT dateToken;
+    private Duration duration;
     private int value;
 
     public DateAddStep(final Traversal.Admin traversal, final DT dateToken, final int value) {
         super(traversal);
+        switch (dateToken) {
+            case second:
+                this.duration = Duration.ofSeconds(value);
+                break;
+            case minute:
+                this.duration = Duration.ofMinutes(value);
+                break;
+            case hour:
+                this.duration= Duration.ofHours(value);
+                break;
+            case day:
+                this.duration= Duration.ofDays(value);
+                break;
+            default:
+                throw new IllegalArgumentException("DT tokens should only be second, minute, hour, or day.");
+        }
         this.dateToken = dateToken;
         this.value = value;
     }
 
     @Override
-    protected Date map(final Traverser.Admin<S> traverser) {
+    protected OffsetDateTime map(final Traverser.Admin<S> traverser) {
         final Object object = traverser.get();
-
-        if (!(object instanceof Date)) throw new IllegalArgumentException("dateAdd accept only Date.");
-
-        final Calendar cal = Calendar.getInstance();
-        cal.setTime((Date) object);
-        cal.add(DTtoCalendar.get(dateToken), value);
-
-        return cal.getTime();
+        OffsetDateTime date;
+
+        if (!(object instanceof OffsetDateTime)) {
+            // allow incoming traverser to resolve into Date object for compatibility
+            if (object instanceof Date) {
+                date = ((Date) object).toInstant().atOffset(ZoneOffset.UTC);
+            } else {
+                throw new IllegalArgumentException("dateAdd() accept only OffsetDateTime or Date (deprecated).");
+            }
+        } else {
+            date = (OffsetDateTime) object;
+        }
+
+        return date.plus(duration);
     }
 
     @Override
@@ -83,6 +97,7 @@ public final class DateAddStep<S> extends ScalarMapStep<S, Date> {
     public int hashCode() {
         int result = super.hashCode();
         result = 31 * result + dateToken.hashCode();
+        result = 31 * result + duration.hashCode();
         result = 31 * result + value;
         return result;
     }
@@ -91,6 +106,7 @@ public final class DateAddStep<S> extends ScalarMapStep<S, Date> {
     public DateAddStep<S> clone() {
         final DateAddStep<S> clone = (DateAddStep<S>) super.clone();
         clone.value = this.value;
+        clone.duration = this.duration;
         clone.dateToken = this.dateToken;
         return clone;
     }
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 d15d461845..1aa7d3f073 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
@@ -25,6 +25,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequire
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Set;
@@ -36,15 +39,20 @@ import java.util.Set;
  */
 public final class DateDiffStep<S> extends ScalarMapStep<S, Long> implements TraversalParent {
 
-    private Date value;
-    private Traversal.Admin<S, Date> dateTraversal;
+    private OffsetDateTime value;
+    private Traversal.Admin<S, ?> dateTraversal;
 
     public DateDiffStep(final Traversal.Admin traversal, final Date value) {
+        super(traversal);
+        this.value = value == null ? null : value.toInstant().atOffset(ZoneOffset.UTC);
+    }
+
+    public DateDiffStep(final Traversal.Admin traversal, final OffsetDateTime value) {
         super(traversal);
         this.value = value;
     }
 
-    public DateDiffStep(final Traversal.Admin traversal, final Traversal<?, Date> dateTraversal) {
+    public DateDiffStep(final Traversal.Admin traversal, final Traversal<?, ?> dateTraversal) {
         super(traversal);
         this.dateTraversal = this.integrateChild(dateTraversal.asAdmin());
     }
@@ -52,18 +60,41 @@ public final class DateDiffStep<S> extends ScalarMapStep<S, Long> implements Tra
     @Override
     protected Long map(final Traverser.Admin<S> traverser) {
         final Object object = traverser.get();
-
-        if (!(object instanceof Date))
-            throw new IllegalArgumentException(
-                    String.format("DateDiff can only take Date as argument, encountered %s", object.getClass()));
-
-        final Date otherDate = value != null ? value :
-                dateTraversal != null ? TraversalUtil.apply(traverser, dateTraversal) : null;
+        OffsetDateTime date;
+        OffsetDateTime otherDate;
+
+        if (!(object instanceof OffsetDateTime)) {
+            // allow incoming traverser to resolve into Date object for compatibility
+            if (object instanceof Date) {
+                date = ((Date) object).toInstant().atOffset(ZoneOffset.UTC);
+            } else {
+                // note: null handling consistency to be resolved https://issues.apache.org/jira/browse/TINKERPOP-3152
+                throw new IllegalArgumentException(
+                        String.format("DateDiff can only take OffsetDateTime or Date (deprecated) as argument, encountered %s", object.getClass()));
+            }
+        } else {
+            date = (OffsetDateTime) object;
+        }
+
+
+        if (null == value && null != dateTraversal) {
+            Object traversalDate = TraversalUtil.apply(traverser, dateTraversal);
+            if (traversalDate == null) {
+                otherDate = null;
+            } else if (traversalDate instanceof Date) {
+                // for cases when traversal resolves to a java.util.Date object (e.g. inject(new Date()))
+                otherDate = ((Date) traversalDate).toInstant().atOffset(ZoneOffset.UTC);
+            } else if (traversalDate instanceof OffsetDateTime) {
+                otherDate = (OffsetDateTime) traversalDate;
+            } else {
+                throw new IllegalArgumentException(String.format("DateDiff can only take OffsetDateTime or Date (deprecated) as argument, encountered %s", object.getClass()));
+            }
+        } else {
+            otherDate = value;
+        }
 
         // let's not throw exception and assume null date == 0
-        final long otherDateMs = otherDate == null ? 0 : otherDate.getTime();
-
-        return (((Date) object).getTime() - otherDateMs) / 1000;
+        return otherDate == null ? date.toEpochSecond() : Duration.between(otherDate, date).getSeconds();
     }
 
     @Override
@@ -96,11 +127,11 @@ public final class DateDiffStep<S> extends ScalarMapStep<S, Long> implements Tra
         return StringFactory.stepString(this);
     }
 
-    public Date getValue() {
+    public OffsetDateTime getValue() {
         return this.value;
     }
 
-    public Traversal.Admin<S, Date> getDateTraversal() {
+    public Traversal.Admin<S, ?> getDateTraversal() {
         return this.dateTraversal;
     }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslator.java
index aab8e95b93..eba123d1e3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslator.java
@@ -28,6 +28,7 @@ import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
@@ -127,6 +128,13 @@ public class AnonymizingTypeTranslator extends GroovyTranslator.DefaultTypeTrans
 //        return "new Date(" + o.getTime() + "L)";
     }
 
+    @Override
+    protected String getSyntax(final OffsetDateTime o) {
+        return anonymizer.anonymize(o).toString();
+//      Original syntax:
+//        return "OffsetDateTime.parse(\"" + o.toString() + "\")";
+    }
+
     @Override
     protected String getSyntax(final Timestamp o) {
         return anonymizer.anonymize(o).toString();
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
index 306dfe504e..8f7ce24a96 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
@@ -50,6 +50,7 @@ import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
@@ -157,6 +158,11 @@ public final class DotNetTranslator implements Translator.ScriptTranslator {
             return "DateTimeOffset.FromUnixTimeMilliseconds(" + o.getTime() + ")";
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            return "DateTimeOffset.Parse(\"" + o.toString() + "\")";
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return "DateTimeOffset.FromUnixTimeMilliseconds(" + o.getTime() + ")";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java
index 577bc7e0a1..51c9637016 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslator.java
@@ -42,6 +42,7 @@ import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -138,6 +139,19 @@ public final class GolangTranslator implements Translator.ScriptTranslator {
             return "time.UnixMilli(" + o.getTime() + ")";
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            final String zoneInfo = o.getOffset().getId().equals("Z") ? "UTC+00:00" : "UTC" + o.getOffset().getId();
+            return "time.Date(" + o.getYear() +
+                    ", " + o.getMonthValue() +
+                    ", " + o.getDayOfMonth() +
+                    ", " + o.getHour() +
+                    ", " + o.getMinute() +
+                    ", " + o.getSecond() +
+                    ", " + o.getNano() +
+                    ", time.FixedZone(\""+ zoneInfo + "\", " + o.getOffset().getTotalSeconds() +")";
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return "time.UnixMilli(" + o.getTime() + ")";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
index 969cd00e8d..91cc7fc2de 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
@@ -46,6 +46,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Timestamp;
 import java.time.Instant;
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
@@ -147,6 +148,11 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
             return "new Date(" + o.getTime() + "L)";
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            return "OffsetDateTime.parse('" + o.toString() + "')";
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return "new Timestamp(" + o.getTime() + "L)";
@@ -422,6 +428,11 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
             return getDatetimeSyntax(o.toInstant());
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            return getDatetimeSyntax(o.toInstant());
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return getDatetimeSyntax(o.toInstant());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
index a1a507ac6d..deec4f846a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
@@ -43,6 +43,7 @@ import org.apache.tinkerpop.gremlin.util.NumberHelper;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -144,6 +145,11 @@ public final class JavascriptTranslator implements Translator.ScriptTranslator {
             return "new Date(" + o.getTime() + ")";
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            return "new Date('" + o.toString() + "')";
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return "new Date(" + o.getTime() + ")";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
index c9e71e3db6..907ef242b3 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
@@ -47,6 +47,7 @@ import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.sql.Timestamp;
+import java.time.OffsetDateTime;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -154,6 +155,13 @@ public final class PythonTranslator implements Translator.ScriptTranslator {
             return "datetime.datetime.utcfromtimestamp(" + o.getTime() + " / 1000.0)";
         }
 
+        @Override
+        protected String getSyntax(final OffsetDateTime o) {
+            final String dt = o.toString();
+            final String dtISOString = dt.endsWith("Z") ? dt.replace("Z", "+00:00") : dt;
+            return "datetime.datetime.fromisoformat('" + dtISOString + "')";
+        }
+
         @Override
         protected String getSyntax(final Timestamp o) {
             return "timestamp(" + o.getTime() + " / 1000.0)";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/DatetimeHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/DatetimeHelper.java
index 31334117b0..d2cecc91e1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/DatetimeHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/DatetimeHelper.java
@@ -20,16 +20,15 @@ package org.apache.tinkerpop.gremlin.util;
 
 import java.time.Instant;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.time.YearMonth;
-import java.time.ZonedDateTime;
+import java.time.Month;
+import java.time.OffsetDateTime;
+import java.time.Year;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.format.ResolverStyle;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
-import java.util.Date;
 
 import static java.time.ZoneOffset.UTC;
 import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE;
@@ -93,45 +92,38 @@ public final class DatetimeHelper {
      * </ul>>
      *
      */
-    public static Date parse(final String d) {
+    public static OffsetDateTime parse(final String d) {
         final TemporalAccessor t = formatter.parse(d);
 
         if (!t.isSupported(ChronoField.HOUR_OF_DAY)) {
             // no hours field so it must be a Date or a YearMonth
             if (!t.isSupported(ChronoField.DAY_OF_MONTH)) {
                 // must be a YearMonth coz no day
-                return Date.from(YearMonth.from(t).atDay(1).atStartOfDay(UTC).toInstant());
+                return OffsetDateTime.of(LocalDate.of(Year.from(t).getValue(), Month.from(t), 1), LocalTime.MIDNIGHT, UTC);
             } else {
                 // must be a Date as the day is present
-                return Date.from(Instant.ofEpochSecond(LocalDate.from(t).atStartOfDay().toEpochSecond(UTC)));
+                return OffsetDateTime.of(LocalDate.from(t), LocalTime.MIDNIGHT, UTC);
             }
         } else if (!t.isSupported(ChronoField.MONTH_OF_YEAR)) {
             // no month field so must be a Time
-            final Instant timeOnEpochDay = LocalDate.ofEpochDay(0)
-                    .atTime(LocalTime.from(t))
-                    .atZone(UTC)
-                    .toInstant();
-            return Date.from(timeOnEpochDay);
-        } else if (t.isSupported(ChronoField.OFFSET_SECONDS)) {
-            // has all datetime components including an offset
-            return Date.from(ZonedDateTime.from(t).toInstant());
+            return OffsetDateTime.of(LocalDate.ofEpochDay(0), LocalTime.from(t), UTC);
         } else {
-            // has all datetime components but no offset so throw in some UTC
-            return Date.from(ZonedDateTime.of(LocalDateTime.from(t), UTC).toInstant());
+            // can directly obtain from TemporalAccessor
+            return OffsetDateTime.from(t);
         }
     }
 
     /**
      * A proxy call to {@link #parse(String)} but allows for syntax similar to Gremlin grammar of {@code datetime()}.
      */
-    public static Date datetime(final String d) {
+    public static OffsetDateTime datetime(final String d) {
         return parse(d);
     }
 
     /**
      * A proxy allows for syntax similar to Gremlin grammar of {@code datetime()}.
      */
-    public static Date datetime() {
-        return new Date();
+    public static OffsetDateTime datetime() {
+        return OffsetDateTime.now();
     }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
index d7b4ffbe24..0f00b5e582 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
@@ -33,7 +33,8 @@ import org.junit.runners.Parameterized;
 import java.lang.reflect.Constructor;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.time.ZoneId;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
@@ -45,6 +46,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static java.time.ZoneOffset.UTC;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;
@@ -459,29 +461,28 @@ public class GeneralLiteralVisitorTest {
 
     @RunWith(Parameterized.class)
     public static class ValidDatetimeLiteralTest {
-        private static final ZoneId UTC = ZoneId.of("Z");
 
         @Parameterized.Parameter(value = 0)
         public String script;
 
         @Parameterized.Parameter(value = 1)
-        public Date expected;
+        public OffsetDateTime expected;
 
         @Parameterized.Parameters(name = "{0}")
         public static Iterable<Object[]> generateTestParameters() {
             return Arrays.asList(new Object[][]{
-                    {"datetime('2018-03-22T00:35:44.741Z')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"datetime('2018-03-22T00:35:44.741-0000')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"datetime('2018-03-22T00:35:44.741+0000')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"datetime('2018-03-22T00:35:44.741-0300')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(-3)).toInstant())},
-                    {"datetime('2018-03-22T00:35:44.741+1600')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(16)).toInstant())},
-                    {"datetime('2018-03-22T00:35:44.741')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"datetime('2018-03-22T00:35:44Z')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 0, UTC).toInstant())},
-                    {"datetime('2018-03-22T00:35:44')", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 0, UTC).toInstant())},
-                    {"datetime('2018-03-22')", Date.from(ZonedDateTime.of(2018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"datetime('1018-03-22')", Date.from(ZonedDateTime.of(1018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"datetime('9018-03-22')", Date.from(ZonedDateTime.of(9018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"datetime('1000-001')", Date.from(ZonedDateTime.of(1000, 1, 1, 0, 0, 0, 0, UTC).toInstant())},
+                    {"datetime('2018-03-22T00:35:44.741Z')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"datetime('2018-03-22T00:35:44.741-0000')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"datetime('2018-03-22T00:35:44.741+0000')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"datetime('2018-03-22T00:35:44.741-0300')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(-3))},
+                    {"datetime('2018-03-22T00:35:44.741+1600')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(16))},
+                    {"datetime('2018-03-22T00:35:44.741')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"datetime('2018-03-22T00:35:44Z')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 0), UTC)},
+                    {"datetime('2018-03-22T00:35:44')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 0), UTC)},
+                    {"datetime('2018-03-22')", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"datetime('1018-03-22')", OffsetDateTime.of(LocalDateTime.of(1018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"datetime('9018-03-22')", OffsetDateTime.of(LocalDateTime.of(9018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"datetime('1000-001')", OffsetDateTime.of(LocalDateTime.of(1000, 1, 1, 0, 0, 0, 0), UTC)},
             });
         }
 
@@ -491,7 +492,7 @@ public class GeneralLiteralVisitorTest {
             final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
             final GremlinParser.DateLiteralContext ctx = parser.dateLiteral();
 
-            final Date dt = (Date) new GenericLiteralVisitor(new GremlinAntlrToJava()).visitDateLiteral(ctx);
+            final OffsetDateTime dt = (OffsetDateTime) new GenericLiteralVisitor(new GremlinAntlrToJava()).visitDateLiteral(ctx);
             assertEquals(expected, dt);
         }
     }
@@ -503,8 +504,8 @@ public class GeneralLiteralVisitorTest {
             final GremlinParser parser = new GremlinParser(new CommonTokenStream(lexer));
             final GremlinParser.DateLiteralContext ctx = parser.dateLiteral();
 
-            final Date dt = (Date) new GenericLiteralVisitor(new GremlinAntlrToJava()).visitDateLiteral(ctx);
-            assertTrue(new Date().getTime() - dt.getTime() < 1000);
+            final OffsetDateTime dt = (OffsetDateTime) new GenericLiteralVisitor(new GremlinAntlrToJava()).visitDateLiteral(ctx);
+            assertTrue(OffsetDateTime.now(UTC).toInstant().toEpochMilli() - dt.toInstant().toEpochMilli() < 1000);
         }
     }
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
index 64a7d95400..71a7630f35 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/translator/GremlinTranslatorTest.java
@@ -477,13 +477,22 @@ public class GremlinTranslatorTest {
                             "g.with_('x', bigint(10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))"},
                     {"g.with('x', datetime('2023-08-02T00:00:00Z'))",
                             null,
-                            "g.with(string0, date0)",
-                            "g.With(\"x\", DateTimeOffset.FromUnixTimeMilliseconds(1690934400000))",
-                            "g.With(\"x\", time.UnixMilli(1690934400000))",
-                            null,
-                            "g.with(\"x\", new Date(1690934400000))",
-                            "g.with_(\"x\", new Date(1690934400000))",
-                            "g.with_('x', datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0))"},
+                            "g.with(string0, offsetdatetime0)",
+                            "g.With(\"x\", DateTimeOffset.Parse(\"2023-08-02T00:00Z\"))",
+                            "g.With(\"x\", time.Date(2023, 8, 2, 0, 0, 0, 0, time.FixedZone(\"UTC+00:00\", 0)))",
+                            null,
+                            "g.with(\"x\", OffsetDateTime.parse(\"2023-08-02T00:00Z\"))",
+                            "g.with_(\"x\", new Date('2023-08-02T00:00Z'))",
+                            "g.with_('x', datetime.datetime.fromisoformat('2023-08-02T00:00+00:00'))"},
+                    {"g.with('x', datetime('2023-08-02T01:23:45-07:30'))",
+                            null,
+                            "g.with(string0, offsetdatetime0)",
+                            "g.With(\"x\", DateTimeOffset.Parse(\"2023-08-02T01:23:45-07:30\"))",
+                            "g.With(\"x\", time.Date(2023, 8, 2, 1, 23, 45, 0, time.FixedZone(\"UTC-07:30\", -27000)))",
+                            null,
+                            "g.with(\"x\", OffsetDateTime.parse(\"2023-08-02T01:23:45-07:30\"))",
+                            "g.with_(\"x\", new Date('2023-08-02T01:23:45-07:30'))",
+                            "g.with_('x', datetime.datetime.fromisoformat('2023-08-02T01:23:45-07:30'))"},
                     {"g.with('x', [x: 1])",
                             "g.with('x', [x:1])",
                             "g.with(string0, map0)",
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStepTest.java
index 25158f74da..6b9d3ef05d 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStepTest.java
@@ -25,7 +25,10 @@ import org.junit.Test;
 
 import java.math.BigInteger;
 import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.time.ZonedDateTime;
+import java.time.ZoneOffset;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -45,13 +48,12 @@ public class AsDateStepTest extends StepTest {
     @Test
     public void shouldParseDate() {
 
-        final Instant testInstant = ZonedDateTime.of(2023, 8, 2, 0, 0, 0, 0, UTC).toInstant();
-        final Date testDate = new Date(testInstant.getEpochSecond() * 1000);
+        final OffsetDateTime testDate = OffsetDateTime.of(LocalDateTime.of(2023, 8, 2, 0, 0, 0, 0), UTC);
 
-        assertEquals(new Date(1), __.__(1).asDate().next());
-        assertEquals(new Date(3), __.__(3L).asDate().next());
-        assertEquals(new Date(6), __.__(new BigInteger("6")).asDate().next());
-        assertEquals(testDate, __.__(testDate.getTime()).asDate().next());
+        assertEquals(OffsetDateTime.ofInstant(Instant.ofEpochMilli(1), ZoneOffset.UTC), __.__(1).asDate().next());
+        assertEquals(OffsetDateTime.ofInstant(Instant.ofEpochMilli(3), ZoneOffset.UTC), __.__(3L).asDate().next());
+        assertEquals(OffsetDateTime.ofInstant(Instant.ofEpochMilli(6), ZoneOffset.UTC), __.__(new BigInteger("6")).asDate().next());
+        assertEquals(testDate, __.__(testDate.toInstant().toEpochMilli()).asDate().next());
 
         assertEquals(testDate, __.__("2023-08-02T00:00:00Z").asDate().next());
         assertEquals(testDate, __.__(testDate).asDate().next());
@@ -87,4 +89,16 @@ public class AsDateStepTest extends StepTest {
         __.__(null).asDate().next();
     }
 
+    @Test
+    public void shouldAcceptDateForCompatibility() {
+
+        final ZonedDateTime testZoneDate =ZonedDateTime.of(2023, 8, 2, 0, 0, 0, 0, UTC);
+        final Instant testInstant = testZoneDate.toInstant();
+        final Date testDate = new Date(testInstant.toEpochMilli());
+
+        final OffsetDateTime expectedDate = testZoneDate.withZoneSameInstant(UTC).toOffsetDateTime();
+
+        assertEquals(expectedDate, __.__(testDate).asDate().next());
+    }
+
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStepTest.java
index f7bb2efbeb..9836ba9103 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStepTest.java
@@ -24,11 +24,15 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
 import org.junit.Test;
 
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
+import static java.time.ZoneOffset.UTC;
 import static org.junit.Assert.assertEquals;
 
 public class DateAddStepTest extends StepTest {
@@ -40,60 +44,100 @@ public class DateAddStepTest extends StepTest {
 
     @Test
     public void shouldAddHours() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime expected = now.plus(Duration.ofHours(2));
+
+        assertEquals(expected, __.__(now).dateAdd(DT.hour, 2).next());
+    }
+
+    @Test
+    public void shouldAddNegativeHours() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime expected = now.plus(Duration.ofHours(-3));
+
+        assertEquals(expected, __.__(now).dateAdd(DT.hour, -3).next());
+    }
+
+    @Test
+    public void shouldAddMinutes() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime expected = now.plus(Duration.ofMinutes(5));
+
+        assertEquals(expected, __.__(now).dateAdd(DT.minute, 5).next());
+    }
+
+    @Test
+    public void shouldAddSeconds() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime expected = now.plus(Duration.ofSeconds(15));
+
+        assertEquals(expected, __.__(now).dateAdd(DT.second, 15).next());
+    }
+
+    @Test
+    public void shouldAddDays() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime expected = now.plus(Duration.ofDays(50));
+
+        assertEquals(expected, __.__(now).dateAdd(DT.day, 50).next());
+    }
+
+    @Test
+    public void shouldAddHoursForDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
         cal.setTime(now);
         cal.add(Calendar.HOUR_OF_DAY, 2);
-        final Date expected = cal.getTime();
+        final OffsetDateTime expected = OffsetDateTime.ofInstant(cal.getTime().toInstant(), ZoneOffset.UTC);
 
         assertEquals(expected, __.__(now).dateAdd(DT.hour, 2).next());
     }
 
     @Test
-    public void shouldAddNegativeHours() {
+    public void shouldAddNegativeHoursForDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
         cal.setTime(now);
         cal.add(Calendar.HOUR_OF_DAY, -3);
-        final Date expected = cal.getTime();
+        final OffsetDateTime expected = OffsetDateTime.ofInstant(cal.getTime().toInstant(), ZoneOffset.UTC);
 
         assertEquals(expected, __.__(now).dateAdd(DT.hour, -3).next());
     }
 
     @Test
-    public void shouldAddMinutes() {
+    public void shouldAddMinutesForDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
         cal.setTime(now);
         cal.add(Calendar.MINUTE, 5);
-        final Date expected = cal.getTime();
+        final OffsetDateTime expected = OffsetDateTime.ofInstant(cal.getTime().toInstant(), ZoneOffset.UTC);
 
         assertEquals(expected, __.__(now).dateAdd(DT.minute, 5).next());
     }
 
     @Test
-    public void shouldAddSeconds() {
+    public void shouldAddSecondsForDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
         cal.setTime(now);
         cal.add(Calendar.SECOND, 15);
-        final Date expected = cal.getTime();
+        final OffsetDateTime expected = OffsetDateTime.ofInstant(cal.getTime().toInstant(), ZoneOffset.UTC);
 
         assertEquals(expected, __.__(now).dateAdd(DT.second, 15).next());
     }
 
     @Test
-    public void shouldAddDays() {
+    public void shouldAddDaysForDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
         cal.setTime(now);
         cal.add(Calendar.DAY_OF_MONTH, 50);
-        final Date expected = cal.getTime();
+        final OffsetDateTime expected = OffsetDateTime.ofInstant(cal.getTime().toInstant(), ZoneOffset.UTC);
 
         assertEquals(expected, __.__(now).dateAdd(DT.day, 50).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 0cffa601ba..43537aa2fd 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
@@ -23,8 +23,10 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
 import org.junit.Test;
 
-import java.util.Calendar;
+import java.time.Duration;
+import java.time.OffsetDateTime;
 import java.util.Collections;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 import java.util.TimeZone;
@@ -36,11 +38,54 @@ public class DateDiffStepTest extends StepTest {
 
     @Override
     protected List<Traversal> getTraversals() {
-        return Collections.singletonList(__.dateDiff(new Date(1690934420000L)));
+        return Collections.singletonList(__.dateDiff(OffsetDateTime.parse("2023-08-02T00:00:20Z")));
     }
 
     @Test
     public void shouldHandlePositiveValues() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime other = now.plus(Duration.ofDays(7));
+
+        assertEquals(604800L, (long) __.__(other).dateDiff(now).next());
+    }
+
+    @Test
+    public void shouldHandleNegativeValues() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime other = now.plus(Duration.ofDays(7));
+
+        assertEquals(-604800L, (long) __.__(now).dateDiff(other).next());
+    }
+
+    @Test
+    public void shouldHandleTraversalParam() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+        final OffsetDateTime other = now.plus(Duration.ofDays(7));
+
+        assertEquals(-604800L, (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());
+    }
+
+    @Test
+    public void shouldHandleNullDate() {
+        final OffsetDateTime now = OffsetDateTime.now(UTC);
+
+        assertEquals(now.toEpochSecond(), (long) __.__(now).dateDiff((OffsetDateTime) null).next());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldThrowWhenInputIsNotDate() {
+        __.__("2023-08-23T00:00:00Z").dateDiff(OffsetDateTime.now(UTC)).next();
+    }
+
+    @Test
+    public void shouldHandlePositiveValuesWithDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
@@ -53,7 +98,7 @@ public class DateDiffStepTest extends StepTest {
     }
 
     @Test
-    public void shouldHandleNegativeValues() {
+    public void shouldHandleNegativeValuesWithDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
@@ -66,7 +111,7 @@ public class DateDiffStepTest extends StepTest {
     }
 
     @Test
-    public void shouldHandleTraversalParam() {
+    public void shouldHandleTraversalParamWithDateCompatibility() {
         final Date now = new Date();
 
         final Calendar cal = Calendar.getInstance();
@@ -79,21 +124,16 @@ public class DateDiffStepTest extends StepTest {
     }
 
     @Test
-    public void shouldHandleNullTraversalParam() {
+    public void shouldHandleNullTraversalParamWithDateCompatibility() {
         final Date now = new Date();
 
         assertEquals(now.getTime() / 1000, (long) __.__(now).dateDiff(__.constant(null)).next());
     }
 
     @Test
-    public void shouldHandleNullDate() {
+    public void shouldHandleNullDateWithDateCompatibility() {
         final Date now = new Date();
 
         assertEquals(now.getTime() / 1000, (long) __.__(now).dateDiff((Date) null).next());
     }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void shouldThrowWhenInputIsNotDate() {
-        __.__("2023-08-23T00:00:00Z").dateDiff(new Date()).next();
-    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslatorTest.java
index 3bf7fdbb5d..1ce4b3adae 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/AnonymizingTypeTranslatorTest.java
@@ -31,11 +31,14 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.UUID;
 
+import static java.time.ZoneOffset.UTC;
 import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.junit.Assert.assertEquals;
 
@@ -119,6 +122,12 @@ public class AnonymizingTypeTranslatorTest {
         testAnonymize(g.inject(d), "g.inject(date0)");
     }
 
+    @Test
+    public void shouldTranslateOffsetDateTime() {
+        final OffsetDateTime d = OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC);
+        testAnonymize(g.inject(d), "g.inject(offsetdatetime0)");
+    }
+
     @Test
     public void shouldTranslateTimestamp() {
         final Calendar c = Calendar.getInstance();
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java
index 21f8f2e457..17d81fec95 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslatorTest.java
@@ -43,6 +43,8 @@ import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.junit.Test;
 
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
@@ -50,6 +52,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.UUID;
 
+import static java.time.ZoneOffset.UTC;
 import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.apache.tinkerpop.gremlin.process.traversal.Order.asc;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
@@ -126,10 +129,8 @@ public class DotNetTranslatorTest {
 
     @Test
     public void shouldTranslateDate() {
-        final Calendar c = Calendar.getInstance();
-        c.set(1975, Calendar.SEPTEMBER, 7);
-        final Date d = c.getTime();
-        assertTranslation(String.format("DateTimeOffset.FromUnixTimeMilliseconds(%s)", d.getTime()), d);
+        final OffsetDateTime d = OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC);
+        assertTranslation(String.format("DateTimeOffset.Parse(\"%s\")", d), d);
     }
 
     @Test
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java
index 810f6406d2..6ca23f892a 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GolangTranslatorTest.java
@@ -40,6 +40,7 @@ import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalS
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
+import static org.apache.tinkerpop.gremlin.util.DatetimeHelper.datetime;
 import static org.junit.Assert.assertEquals;
 
 public class GolangTranslatorTest {
@@ -139,4 +140,18 @@ public class GolangTranslatorTest {
         script = translator.translate(GraphOp.TX_ROLLBACK.getBytecode()).getScript();
         assertEquals("g.Tx().Rollback()", script);
     }
+
+    @Test
+    public void shouldTranslateOffsetDateTimeUTC() {
+        final String gremlinAsGo = translator.translate(
+                g.inject(datetime("2023-08-02T01:23:45.678Z")).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject(time.Date(2023, 8, 2, 1, 23, 45, 678000000, time.FixedZone(\"UTC+00:00\", 0))", gremlinAsGo);
+    }
+
+    @Test
+    public void shouldTranslateOffsetDateTime() {
+        final String gremlinAsGo = translator.translate(
+                g.inject(datetime("2023-08-02T01:23:45.678-07:30")).asAdmin().getBytecode()).getScript();
+        assertEquals("g.Inject(time.Date(2023, 8, 2, 1, 23, 45, 678000000, time.FixedZone(\"UTC-07:30\", -27000))", gremlinAsGo);
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
index c82decc928..dc97b235f8 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
@@ -44,6 +44,8 @@ import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.junit.Test;
 
 import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.time.ZonedDateTime;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -137,10 +139,8 @@ public class GroovyTranslatorTest {
 
     @Test
     public void shouldTranslateDate() {
-        final Calendar c = Calendar.getInstance();
-        c.set(1975, Calendar.SEPTEMBER, 7);
-        final Date d = c.getTime();
-        assertTranslation(String.format("new Date(%sL)", d.getTime()), d);
+        final OffsetDateTime d = OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC);
+        assertTranslation(String.format("OffsetDateTime.parse('%s')", d), d);
     }
 
     @Test
@@ -171,10 +171,9 @@ public class GroovyTranslatorTest {
     public void shouldTranslateDateUsingLanguageTypeTranslator() {
         final Translator.ScriptTranslator t = GroovyTranslator.of("g",
                 new GroovyTranslator.LanguageTypeTranslator(false));
-        final Date datetime = Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant());
-        final Date date = Date.from(ZonedDateTime.of(2018, 03, 22, 0, 0, 0, 0, UTC).toInstant());
-        assertEquals("g.inject(datetime('2018-03-22T00:00:00Z'),datetime('2018-03-22T00:35:44.741Z'))",
-                t.translate(g.inject(date, datetime)).getScript());
+        final OffsetDateTime date = OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC);
+        assertEquals("g.inject(datetime('2018-03-22T00:35:44.741Z'))",
+                t.translate(g.inject(date)).getScript());
     }
 
     @Test
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
index d799fd2ddf..03d2e4d232 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslatorTest.java
@@ -39,12 +39,15 @@ import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.junit.Test;
 
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.UUID;
 
+import static java.time.ZoneOffset.UTC;
 import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
 import static org.junit.Assert.assertEquals;
@@ -78,10 +81,8 @@ public class JavascriptTranslatorTest {
 
     @Test
     public void shouldTranslateDate() {
-        final Calendar c = Calendar.getInstance();
-        c.set(1975, Calendar.SEPTEMBER, 7);
-        final Date d = c.getTime();
-        assertTranslation(String.format("new Date(%s)", d.getTime()), d);
+        final OffsetDateTime d = OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC);
+        assertTranslation(String.format("new Date('%s')", d), d);
     }
 
     @Test
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
index 292f8cd50d..5be0d5c2f4 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslatorTest.java
@@ -41,6 +41,7 @@ import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalS
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
+import static org.apache.tinkerpop.gremlin.util.DatetimeHelper.datetime;
 import static org.junit.Assert.assertEquals;
 
 public class PythonTranslatorTest {
@@ -171,4 +172,18 @@ public class PythonTranslatorTest {
         final String script = translator.translate(g.inject(objs).asAdmin().getBytecode()).getScript();
         assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
     }
+
+    @Test
+    public void shouldTranslateOffsetDateTimeUTC() {
+        final String gremlinAsPython = translator.translate(
+                g.inject(datetime("2023-08-02T01:23:45.678Z")).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(datetime.datetime.fromisoformat('2023-08-02T01:23:45.678+00:00'))", gremlinAsPython);
+    }
+
+    @Test
+    public void shouldTranslateOffsetDateTime() {
+        final String gremlinAsPython = translator.translate(
+                g.inject(datetime("2023-08-02T01:23:45.678-07:00")).asAdmin().getBytecode()).getScript();
+        assertEquals("g.inject(datetime.datetime.fromisoformat('2023-08-02T01:23:45.678-07:00'))", gremlinAsPython);
+    }
 }
\ No newline at end of file
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/DatetimeHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/DatetimeHelperTest.java
index 72ea3f1558..a3a1372903 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/DatetimeHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/DatetimeHelperTest.java
@@ -24,11 +24,11 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
 import java.time.Instant;
-import java.time.ZoneId;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Arrays;
-import java.util.Date;
 
 import static java.time.ZoneOffset.UTC;
 import static org.junit.Assert.assertEquals;
@@ -43,35 +43,35 @@ public class DatetimeHelperTest {
         public String d;
 
         @Parameterized.Parameter(value = 1)
-        public Date expected;
+        public OffsetDateTime expected;
 
         @Parameterized.Parameters(name = "{0}")
         public static Iterable<Object[]> generateTestParameters() {
             return Arrays.asList(new Object[][]{
-                    {"2018-03-22T00:35:44.741Z", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741-0000", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741+0000", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741+00:00", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741+000000", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741+00:00:00", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44.741-0300", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(-3)).toInstant())},
-                    {"2018-03-22T00:35:44.741+1600", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(16)).toInstant())},
-                    {"2018-03-22T00:35:44.741+16:00", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(16)).toInstant())},
-                    {"2018-03-22T00:35:44.741+160000", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(16)).toInstant())},
-                    {"2018-03-22T00:35:44.741+16:00:00", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHours(16)).toInstant())},
-                    {"2018-03-22T00:35:44.741+1659", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutes(16, 59)).toInstant())},
-                    {"2018-03-22T00:35:44.741+16:59", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutes(16, 59)).toInstant())},
-                    {"2018-03-22T00:35:44.741+165900", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutes(16, 59)).toInstant())},
-                    {"2018-03-22T00:35:44.741+16:59:00", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutes(16, 59)).toInstant())},
-                    {"2018-03-22T00:35:44.741+165930", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutesSeconds(16, 59, 30)).toInstant())},
-                    {"2018-03-22T00:35:44.741+16:59:30", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, ZoneOffset.ofHoursMinutesSeconds(16, 59, 30)).toInstant())},
-                    {"2018-03-22T00:35:44.741", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 741000000, UTC).toInstant())},
-                    {"2018-03-22T00:35:44Z", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 0, UTC).toInstant())},
-                    {"2018-03-22T00:35:44", Date.from(ZonedDateTime.of(2018, 03, 22, 00, 35, 44, 0, UTC).toInstant())},
-                    {"2018-03-22", Date.from(ZonedDateTime.of(2018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"1018-03-22", Date.from(ZonedDateTime.of(1018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"9018-03-22", Date.from(ZonedDateTime.of(9018, 03, 22, 0, 0, 0, 0, UTC).toInstant())},
-                    {"1000-001", Date.from(ZonedDateTime.of(1000, 1, 1, 0, 0, 0, 0, UTC).toInstant())},
+                    {"2018-03-22T00:35:44.741Z", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741-0000", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741+0000", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741+00:00", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741+000000", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741+00:00:00", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44.741-0300", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(-3))},
+                    {"2018-03-22T00:35:44.741+1600", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(16))},
+                    {"2018-03-22T00:35:44.741+16:00", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(16))},
+                    {"2018-03-22T00:35:44.741+160000", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(16))},
+                    {"2018-03-22T00:35:44.741+16:00:00", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHours(16))},
+                    {"2018-03-22T00:35:44.741+1659", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutes(16, 59))},
+                    {"2018-03-22T00:35:44.741+16:59", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutes(16, 59))},
+                    {"2018-03-22T00:35:44.741+165900", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutes(16, 59))},
+                    {"2018-03-22T00:35:44.741+16:59:00", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutes(16, 59))},
+                    {"2018-03-22T00:35:44.741+165930", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutesSeconds(16, 59, 30))},
+                    {"2018-03-22T00:35:44.741+16:59:30", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), ZoneOffset.ofHoursMinutesSeconds(16, 59, 30))},
+                    {"2018-03-22T00:35:44.741", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 741000000), UTC)},
+                    {"2018-03-22T00:35:44Z", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 0), UTC)},
+                    {"2018-03-22T00:35:44", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 00, 35, 44, 0), UTC)},
+                    {"2018-03-22", OffsetDateTime.of(LocalDateTime.of(2018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"1018-03-22", OffsetDateTime.of(LocalDateTime.of(1018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"9018-03-22", OffsetDateTime.of(LocalDateTime.of(9018, 03, 22, 0, 0, 0, 0), UTC)},
+                    {"1000-001", OffsetDateTime.of(LocalDateTime.of(1000, 1, 1, 0, 0, 0, 0), UTC)},
             });
         }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
index 6ccad02937..161db1b1af 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/DataType.cs
@@ -78,6 +78,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
         // TODO: Support metrics and traversal metrics
         public static readonly DataType Char = new DataType(0x80);
         public static readonly DataType Duration = new DataType(0x81);
+        public static readonly DataType OffsetDateTime = new DataType(0x88);
 #pragma warning restore 1591
 
         /// <summary>
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
index e7f1997771..89a6c97e56 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/TypeSerializerRegistry.cs
@@ -44,7 +44,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
                 {typeof(int), SingleTypeSerializers.IntSerializer},
                 {typeof(long), SingleTypeSerializers.LongSerializer},
                 {typeof(string), new StringSerializer()},
-                {typeof(DateTimeOffset), DateTimeOffsetSerializer.DateSerializer},
+                {typeof(DateTimeOffset), new OffsetDateTimeSerializer()},
                 {typeof(GremlinType), new ClassSerializer()},
                 {typeof(Type), new TypeSerializer()},
                 {typeof(double), SingleTypeSerializers.DoubleSerializer},
@@ -91,8 +91,8 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
                 {DataType.Int, SingleTypeSerializers.IntSerializer},
                 {DataType.Long, SingleTypeSerializers.LongSerializer},
                 {DataType.String, new StringSerializer()},
-                {DataType.Date, DateTimeOffsetSerializer.DateSerializer},
-                {DataType.Timestamp, DateTimeOffsetSerializer.TimestampSerializer},
+                {DataType.Date, DateTimeSerializer.DateSerializer},
+                {DataType.Timestamp, DateTimeSerializer.TimestampSerializer},
                 {DataType.Class, new ClassSerializer()},
                 {DataType.Double, SingleTypeSerializers.DoubleSerializer},
                 {DataType.Float, SingleTypeSerializers.FloatSerializer},
@@ -133,6 +133,7 @@ namespace Gremlin.Net.Structure.IO.GraphBinary
                 {DataType.BulkSet, new BulkSetSerializer<List<object>>()},
                 {DataType.Char, new CharSerializer()},
                 {DataType.Duration, new DurationSerializer()},
+                {DataType.OffsetDateTime, new OffsetDateTimeSerializer()},
             };
 
         private readonly Dictionary<string, CustomTypeSerializer> _serializerByCustomTypeName =
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeSerializer.cs
similarity index 84%
rename from gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
rename to gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeSerializer.cs
index 4c4ef4ba3c..e3de62ce58 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeOffsetSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/DateTimeSerializer.cs
@@ -32,20 +32,20 @@ namespace Gremlin.Net.Structure.IO.GraphBinary.Types
     /// A serializer for the GraphBinary types Date and Timestamp. Both are represented as <see cref="DateTimeOffset"/>
     /// in .NET.
     /// </summary>
-    public class DateTimeOffsetSerializer : SimpleTypeSerializer<DateTimeOffset>
+    public class DateTimeSerializer : SimpleTypeSerializer<DateTimeOffset>
     {
         /// <summary>
         /// A serializer for the GraphBinary type Date, represented as <see cref="DateTimeOffset"/> in .NET.
         /// </summary>
-        public static readonly DateTimeOffsetSerializer DateSerializer = new DateTimeOffsetSerializer(DataType.Date);
+        public static readonly DateTimeSerializer DateSerializer = new DateTimeSerializer(DataType.Date);
 
         /// <summary>
         /// A serializer for the GraphBinary type Timestamp, represented as <see cref="DateTimeOffset"/> in .NET.
         /// </summary>
-        public static readonly DateTimeOffsetSerializer TimestampSerializer =
-            new DateTimeOffsetSerializer(DataType.Timestamp);
+        public static readonly DateTimeSerializer TimestampSerializer =
+            new DateTimeSerializer(DataType.Timestamp);
         
-        private DateTimeOffsetSerializer(DataType dataType) : base(dataType)
+        private DateTimeSerializer(DataType dataType) : base(dataType)
         {
         }
 
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/OffsetDateTimeSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/OffsetDateTimeSerializer.cs
new file mode 100644
index 0000000000..a8b1fa6c1f
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/OffsetDateTimeSerializer.cs
@@ -0,0 +1,80 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Gremlin.Net.Structure.IO.GraphBinary.Types
+{
+    /// <summary>
+    /// A serializer for the GraphBinary type OffsetDateTime, represented as <see cref="DateTimeOffset"/>
+    /// in .NET.
+    /// </summary>
+    public class OffsetDateTimeSerializer : SimpleTypeSerializer<DateTimeOffset>
+    {
+        
+        /// <summary>
+        ///     Initializes a new instance of the <see cref="OffsetDateTimeSerializer" /> class.
+        /// </summary>
+        public OffsetDateTimeSerializer() : base(DataType.OffsetDateTime)
+        {
+        }
+
+        /// <inheritdoc />
+        protected override async Task WriteValueAsync(DateTimeOffset value, Stream stream, GraphBinaryWriter writer,
+            CancellationToken cancellationToken = default)
+        {
+            await stream.WriteIntAsync(value.Year, cancellationToken).ConfigureAwait(false);
+            await stream.WriteByteAsync(Convert.ToByte(value.Month), cancellationToken).ConfigureAwait(false);
+            await stream.WriteByteAsync(Convert.ToByte(value.Day), cancellationToken).ConfigureAwait(false);
+            // Note that nanosecond precisions were added after .NET 7
+            // Get the time of day as TimeSpan
+            var timeOfDay = value.TimeOfDay; 
+            // Convert ticks to nanoseconds (1 tick = 100 nanoseconds)
+            var ns = timeOfDay.Ticks * 100;
+            await stream.WriteLongAsync(Convert.ToInt64(ns), cancellationToken).ConfigureAwait(false);
+
+            var offset = value.Offset;
+            var os = offset.Hours * 60 * 60 + offset.Minutes * 60 + offset.Seconds;
+            await stream.WriteIntAsync(os, cancellationToken).ConfigureAwait(false);
+        }
+
+        /// <inheritdoc />
+        protected override async Task<DateTimeOffset> ReadValueAsync(Stream stream, GraphBinaryReader reader,
+            CancellationToken cancellationToken = default)
+        {
+            var year = await stream.ReadIntAsync(cancellationToken).ConfigureAwait(false);
+            var month = await stream.ReadByteAsync(cancellationToken).ConfigureAwait(false);
+            var day = await stream.ReadByteAsync(cancellationToken).ConfigureAwait(false);
+            var ns = await stream.ReadLongAsync(cancellationToken).ConfigureAwait(false);
+            var timeDelta = TimeSpan.FromMilliseconds(ns / 1e6);
+            
+            var os = await stream.ReadIntAsync(cancellationToken).ConfigureAwait(false);
+            var offset = TimeSpan.FromSeconds(os);
+
+            return new DateTimeOffset(year, Convert.ToInt32(month), Convert.ToInt32(day), 0, 0, 0, offset).Add(timeDelta);
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
index 209c0561f4..779c5594a1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONReader.cs
@@ -58,6 +58,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
             { "g:T", new TDeserializer() },
 
             //Extended
+            { "gx:OffsetDateTime", new OffsetDateTimeDeserializer() },
             { "gx:BigDecimal", new DecimalConverter() },
             { "gx:Duration", new DurationDeserializer() },
             { "gx:BigInteger", new BigIntegerDeserializer() },
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
index f62dac2bf7..b883582321 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/GraphSONWriter.cs
@@ -57,7 +57,6 @@ namespace Gremlin.Net.Structure.IO.GraphSON
             { typeof(float), new FloatConverter() },
             { typeof(double), new DoubleConverter() },
             { typeof(Guid), new UuidSerializer() },
-            { typeof(DateTimeOffset), new DateSerializer() },
             { typeof(Type), new ClassSerializer() },
             { typeof(EnumWrapper), new EnumSerializer() },
             { typeof(P), new PSerializer() },
@@ -70,6 +69,7 @@ namespace Gremlin.Net.Structure.IO.GraphSON
             { typeof(ILambda), new LambdaSerializer() },
 
             //Extended
+            { typeof(DateTimeOffset), new OffsetDateTimeSerializer() }, // DateTimeOffset will be serialized as OffsetDateTimeSerializer by default
             { typeof(decimal), new DecimalConverter() },
             { typeof(TimeSpan), new DurationSerializer() },
             { typeof(BigInteger), new BigIntegerSerializer() },
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeDeserializer.cs
similarity index 71%
copy from gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
copy to gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeDeserializer.cs
index a3c726335d..9840fce0ad 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeDeserializer.cs
@@ -18,20 +18,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 #endregion
 
 using System;
-using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class DateSerializer : IGraphSONSerializer
+    internal class OffsetDateTimeDeserializer : IGraphSONDeserializer
     {
-        public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
+        public dynamic Objectify(JsonElement graphsonObject, GraphSONReader reader)
         {
-            DateTimeOffset value = objectData;
-            return GraphSONUtil.ToTypedValue("Date", value.ToUnixTimeMilliseconds());
+            return DateTimeOffset.Parse(graphsonObject.GetString() ??
+                                        throw new IOException("Read null but expected a OffsetDateTime value"));
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeSerializer.cs
similarity index 87%
rename from gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
rename to gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeSerializer.cs
index a3c726335d..05de9c4164 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/DateSerializer.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphSON/OffsetDateTimeSerializer.cs
@@ -26,12 +26,12 @@ using System.Collections.Generic;
 
 namespace Gremlin.Net.Structure.IO.GraphSON
 {
-    internal class DateSerializer : IGraphSONSerializer
+    internal class OffsetDateTimeSerializer : IGraphSONSerializer
     {
         public Dictionary<string, dynamic> Dictify(dynamic objectData, GraphSONWriter writer)
         {
             DateTimeOffset value = objectData;
-            return GraphSONUtil.ToTypedValue("Date", value.ToUnixTimeMilliseconds());
+            return GraphSONUtil.ToTypedValue("OffsetDateTime", value.ToString("O"), "gx");
         }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 5953fad25f..28ac0f0e3a 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -612,6 +612,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_hasXperson_name_aliceX_propertyXsingle_age_unionXage_constantX1XX_sumX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name", "alice").Property(Cardinality.Single, "age", 50), (g,p) =>g.V().Has("person", "name", "alice").Property("age", __.Union<object>(__.Values<object>("age"), __.Constant<object>(1)).Sum<object>()), (g,p) =>g.V().Has("person", "age", 50), (g,p) =>g.V().Has("person", "age", 51)}}, 
                {"g_V_limitX3X_addVXsoftwareX_aggregateXa1X_byXlabelX_aggregateXa2X_byXlabelX_capXa1_a2X_selectXa_bX_byXunfoldX_foldX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Proper [...]
                {"g_injectXstrX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("2023-08-02T00:00:00Z").AsDate()}}, 
+               {"g_injectXstr_offsetX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>("2023-08-02T00:00:00-07:00").AsDate()}}, 
                {"g_injectX1694017707000X_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(1694017707000).AsDate()}}, 
                {"g_injectX1694017708000LX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).AsDate()}}, 
                {"g_injectX1694017709000dX_asDate", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(p["xx1"]).AsDate()}}, 
@@ -724,15 +725,15 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_order_byXnoX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Order().By("no").Count()}}, 
                {"g_V_group_byXlabelX_count", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object, object>().By(T.Label).Count()}}, 
                {"g_V_group_byXlabelX_countXlocalX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Group<object, object>().By(T.Label).Count(Scope.Local)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXDT_hour_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateAdd(DT.Hour, 2)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXhour_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateAdd(DT.Hour, 2)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXhour_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateAdd(DT.Hour, -1)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXminute_10X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateAdd(DT.Minute, 10)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXsecond_20X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateAdd(DT.Second, 20)}}, 
-               {"g_injectXdatetimeXstrXX_dateAddXday_11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1693958400000)).DateAdd(DT.Day, 11)}}, 
-               {"g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690934400000)).DateDiff(DateTimeOffset.FromUnixTimeMilliseconds(1691539200000))}}, 
-               {"g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1691452800000)).DateDiff(__.Constant<object>(DateTimeOffset.FromUnixTimeMilliseconds(1690848000000)))}}, 
-               {"g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.FromUnixTimeMilliseconds(1691452800000)).DateDiff(__.Inject(DateTimeOffset.FromUnixTimeMilliseconds(1696982400000)))}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXDT_hour_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z")).DateAdd(DT.Hour, 2)}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXhour_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z")).DateAdd(DT.Hour, 2)}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXhour_1X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z")).DateAdd(DT.Hour, -1)}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXminute_10X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z")).DateAdd(DT.Minute, 10)}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXsecond_20X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-08-02T00:00Z")).DateAdd(DT.Second, 20)}}, 
+               {"g_injectXdatetimeXstrXX_dateAddXday_11X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(DateTimeOffset.Parse("2023-09-06T00:00Z")).DateAdd(DT.Day, 11)}}, 
+               {"g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject<object>(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")).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")).DateDiff(__.Inject(DateTimeOffset.Parse("2023-10-11T00:00Z")))}}, 
                {"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-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
index 7b57bc41e6..3b00d00135 100644
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
@@ -232,7 +232,7 @@ namespace Gremlin.Net.UnitTest.Structure.IO.GraphSON
 
             var graphSon = writer.WriteObject(dateTimeOffset);
 
-            const string expected = "{\"@type\":\"g:Date\",\"@value\":1475583442552}";
+            const string expected = "{\"@type\":\"gx:OffsetDateTime\",\"@value\":\"2016-10-04T12:17:22.5520000+00:00\"}";
             Assert.Equal(expected, graphSon);
         }
 
diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go b/gremlin-go/driver/cucumber/cucumberSteps_test.go
index 7e8a4218f7..1ad8f1ddd7 100644
--- a/gremlin-go/driver/cucumber/cucumberSteps_test.go
+++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go
@@ -111,11 +111,14 @@ func parseValue(value string, graphName string) interface{} {
 
 // Parse dateTime.
 func toDateTime(stringVal, graphName string) interface{} {
-	val, err := time.Parse(time.RFC3339, stringVal)
+	val, err := time.Parse(time.RFC3339Nano, stringVal)
 	if err != nil {
 		return nil
 	}
-	return val
+	_, os := val.Zone()
+	// go doesn't expose getting the abbreviated zone names from offset despite parsing into them, so we'll need
+	// to update the location into UTC+/-HH:SS format for evaluation purposes
+	return val.In(gremlingo.GetTimezoneFromOffset(os))
 }
 
 // Parse numeric.
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index a1eccef27f..c569150664 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -581,6 +581,7 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_hasXperson_name_aliceX_propertyXsingle_age_unionXage_constantX1XX_sumX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "alice").Property(gremlingo.Cardinality.Single, "age", 50)}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Has("person", "name", "alice").Property("age", gremlingo.T__.Union(gremlingo.T__.Values("age"), gremlingo.T_ [...]
     "g_V_limitX3X_addVXsoftwareX_aggregateXa1X_byXlabelX_aggregateXa2X_byXlabelX_capXa1_a2X_selectXa_bX_byXunfoldX_foldX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property("name", "josh").Prop [...]
     "g_injectXstrX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("2023-08-02T00:00:00Z").AsDate()}}, 
+    "g_injectXstr_offsetX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("2023-08-02T00:00:00-07:00").AsDate()}}, 
     "g_injectX1694017707000X_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(1694017707000).AsDate()}}, 
     "g_injectX1694017708000LX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).AsDate()}}, 
     "g_injectX1694017709000dX_asDate": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"]).AsDate()}}, 
@@ -693,15 +694,15 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
     "g_V_order_byXnoX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Order().By("no").Count()}}, 
     "g_V_group_byXlabelX_count": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Group().By(gremlingo.T.Label).Count()}}, 
     "g_V_group_byXlabelX_countXlocalX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Group().By(gremlingo.T.Label).Count(gremlingo.Scope.Local)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXDT_hour_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateAdd(gremlingo.DT.Hour, 2)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXhour_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateAdd(gremlingo.DT.Hour, 2)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXhour_1X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateAdd(gremlingo.DT.Hour, -1)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXminute_10X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateAdd(gremlingo.DT.Minute, 10)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXsecond_20X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateAdd(gremlingo.DT.Second, 20)}}, 
-    "g_injectXdatetimeXstrXX_dateAddXday_11X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1693958400000)).DateAdd(gremlingo.DT.Day, 11)}}, 
-    "g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1690934400000)).DateDiff(time.UnixMilli(1691539200000))}}, 
-    "g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1691452800000)).DateDiff(gremlingo.T__.Constant(time.UnixMilli(1690848000000)))}}, 
-    "g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.UnixMilli(1691452800000)).DateDiff(gremlingo.T__.Inject(time.UnixMilli(1696982400000)))}}, 
+    "g_injectXdatetimeXstrXX_dateAddXDT_hour_2X": {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))).DateAdd(gremlingo.DT.Hour, 2)}}, 
+    "g_injectXdatetimeXstrXX_dateAddXhour_2X": {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))).DateAdd(gremlingo.DT.Hour, 2)}}, 
+    "g_injectXdatetimeXstrXX_dateAddXhour_1X": {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))).DateAdd(gremlingo.DT.Hour, -1)}}, 
+    "g_injectXdatetimeXstrXX_dateAddXminute_10X": {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))).DateAdd(gremlingo.DT.Minute, 10)}}, 
+    "g_injectXdatetimeXstrXX_dateAddXsecond_20X": {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))).DateAdd(gremlingo.DT.Second, 20)}}, 
+    "g_injectXdatetimeXstrXX_dateAddXday_11X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(time.Date(2023, 9, 6, 0, 0, 0, 0, time.FixedZone("UTC+00:00", 0))).DateAdd(gremlingo.DT.Day, 11)}}, 
+    "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))).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))).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))).DateDiff(gremlingo.T__.Inject(time.Date(2023, 10, 11, 0, 0, 0, 0, time.FixedZone("UTC+00:00", 0))))}}, 
     "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-go/driver/graphBinary.go b/gremlin-go/driver/graphBinary.go
index 18b69dc421..22de276a02 100644
--- a/gremlin-go/driver/graphBinary.go
+++ b/gremlin-go/driver/graphBinary.go
@@ -85,6 +85,7 @@ const (
 	metricsType           dataType = 0x2c
 	traversalMetricsType  dataType = 0x2d
 	durationType          dataType = 0x81
+	offsetDateTimeType    dataType = 0x88
 	nullType              dataType = 0xFE
 )
 
@@ -509,6 +510,39 @@ func timeWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSeria
 	return buffer.Bytes(), nil
 }
 
+func offsetDateTimeWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSerializer) ([]byte, error) {
+	t := value.(time.Time)
+	err := binary.Write(buffer, binary.BigEndian, int32(t.Year()))
+	if err != nil {
+		return nil, err
+	}
+
+	err = binary.Write(buffer, binary.BigEndian, byte(t.Month()))
+	if err != nil {
+		return nil, err
+	}
+	err = binary.Write(buffer, binary.BigEndian, byte(t.Day()))
+	if err != nil {
+		return nil, err
+	}
+	// construct time of day in nanoseconds
+	h := int64(t.Hour())
+	m := int64(t.Minute())
+	s := int64(t.Second())
+	ns := (h * 60 * 60 * 1e9) + (m * 60 * 1e9) + (s * 1e9) + int64(t.Nanosecond())
+	err = binary.Write(buffer, binary.BigEndian, ns)
+	if err != nil {
+		return nil, err
+	}
+	_, os := t.Zone()
+	err = binary.Write(buffer, binary.BigEndian, int32(os))
+	if err != nil {
+		return nil, err
+	}
+
+	return buffer.Bytes(), nil
+}
+
 func durationWriter(value interface{}, buffer *bytes.Buffer, _ *graphBinaryTypeSerializer) ([]byte, error) {
 	t := value.(time.Duration)
 	sec := int64(t / time.Second)
@@ -687,7 +721,7 @@ func (serializer *graphBinaryTypeSerializer) getType(val interface{}) (dataType,
 	case Set:
 		return setType, nil
 	case time.Time:
-		return dateType, nil
+		return offsetDateTimeType, nil  // default serialization of Time will become OffsetDateTime
 	case time.Duration:
 		return durationType, nil
 	case cardinality:
@@ -1044,6 +1078,43 @@ func timeReader(data *[]byte, i *int) (interface{}, error) {
 	return time.UnixMilli(readLongSafe(data, i)), nil
 }
 
+func offsetDateTimeReader(data *[]byte, i *int) (interface{}, error) {
+	year := readIntSafe(data, i)
+	month := readByteSafe(data, i)
+	day := readByteSafe(data, i)
+	totalNS := readLongSafe(data, i)
+	// calculate hour, minute, second, and ns from totalNS (int64) to prevent int overflow in the nanoseconds arg
+	ns := totalNS % 1e9
+	totalS := totalNS / 1e9
+	s := totalS % 60
+	totalM := totalS / 60
+	m := totalM % 60
+	h := totalM / 60
+
+	offset := readIntSafe(data, i)
+	datetime := time.Date(int(year), time.Month(month), int(day), int(h), int(m), int(s), int(ns), GetTimezoneFromOffset(int(offset)))
+	return datetime, nil
+}
+
+// GetTimezoneFromOffset is a helper function to convert an offset in seconds to a time.Location
+func GetTimezoneFromOffset(offsetSeconds int) *time.Location {
+	// calculate hours and minutes from seconds
+	hours := offsetSeconds / 3600
+	minutes := (offsetSeconds % 3600) / 60
+
+	// format the timezone name in the format that go expects
+	// for example: "UTC+01:00" or "UTC-05:30"
+	sign := "+"
+	if hours < 0 {
+		sign = "-"
+		hours = -hours
+		minutes = -minutes
+	}
+	tzName := fmt.Sprintf("UTC%s%02d:%02d", sign, hours, minutes)
+
+	return time.FixedZone(tzName, offsetSeconds)
+}
+
 func durationReader(data *[]byte, i *int) (interface{}, error) {
 	return time.Duration(readLongSafe(data, i)*int64(time.Second) + int64(readIntSafe(data, i))), nil
 }
diff --git a/gremlin-go/driver/graphBinary_test.go b/gremlin-go/driver/graphBinary_test.go
index 69ea3aa4ce..c47b327db4 100644
--- a/gremlin-go/driver/graphBinary_test.go
+++ b/gremlin-go/driver/graphBinary_test.go
@@ -312,6 +312,39 @@ func TestGraphBinaryV1(t *testing.T) {
 			assert.Nil(t, err)
 			assert.Equal(t, source, res)
 		})
+		t.Run("read-write local datetime", func(t *testing.T) {
+			pos := 0
+			var buffer bytes.Buffer
+			source := time.Date(2022, 5, 10, 9, 51, 0, 0, time.Local)
+			buf, err := offsetDateTimeWriter(source, &buffer, nil)
+			assert.Nil(t, err)
+			res, err := offsetDateTimeReader(&buf, &pos)
+			assert.Nil(t, err)
+			// ISO format
+			assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano))
+		})
+		t.Run("read-write UTC datetime", func(t *testing.T) {
+			pos := 0
+			var buffer bytes.Buffer
+			source := time.Date(2022, 5, 10, 9, 51, 0, 0, time.UTC)
+			buf, err := offsetDateTimeWriter(source, &buffer, nil)
+			assert.Nil(t, err)
+			res, err := offsetDateTimeReader(&buf, &pos)
+			assert.Nil(t, err)
+			// ISO format
+			assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano))
+		})
+		t.Run("read-write HST datetime", func(t *testing.T) {
+			pos := 0
+			var buffer bytes.Buffer
+			source := time.Date(2022, 5, 10, 9, 51, 34, 123456789, GetTimezoneFromOffset(-36000))
+			buf, err := offsetDateTimeWriter(source, &buffer, nil)
+			assert.Nil(t, err)
+			res, err := offsetDateTimeReader(&buf, &pos)
+			assert.Nil(t, err)
+			// ISO format
+			assert.Equal(t, source.Format(time.RFC3339Nano), res.(time.Time).Format(time.RFC3339Nano))
+		})
 	})
 
 	t.Run("error handle tests", func(t *testing.T) {
diff --git a/gremlin-go/driver/serializer.go b/gremlin-go/driver/serializer.go
index 04a7e468b5..b7aa4a9750 100644
--- a/gremlin-go/driver/serializer.go
+++ b/gremlin-go/driver/serializer.go
@@ -265,6 +265,7 @@ func initSerializers() {
 		setType:               setWriter,
 		dateType:              timeWriter,
 		durationType:          durationWriter,
+		offsetDateTimeType:    offsetDateTimeWriter,
 		cardinalityType:       enumWriter,
 		columnType:            enumWriter,
 		directionType:         enumWriter,
@@ -310,9 +311,10 @@ func initDeserializers() {
 		classType:  readClass,
 
 		// Date Time
-		dateType:      timeReader,
-		timestampType: timeReader,
-		durationType:  durationReader,
+		dateType:      		timeReader,
+		timestampType: 		timeReader,
+		offsetDateTimeType: offsetDateTimeReader,
+		durationType:  		durationReader,
 
 		// Graph
 		traverserType:      traverserReader,
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/GraphBinary.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/GraphBinary.js
index 20bc42db02..d3cdfd8c1d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/GraphBinary.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/GraphBinary.js
@@ -71,6 +71,7 @@ ioc.intSerializer               = new (require('./internals/IntSerializer'))(ioc
 ioc.longSerializer              = new (require('./internals/LongSerializer'))(ioc);
 ioc.longSerializerNg            = new (require('./internals/LongSerializerNg'))(ioc);
 ioc.stringSerializer            = new (require('./internals/StringSerializer'))(ioc, ioc.DataType.STRING);
+ioc.offsetDateTimeSerializer    = new (require('./internals/OffsetDateTimeSerializer'))(ioc, ioc.DataType.OFFSETDATETIME);
 ioc.dateSerializer              = new (require('./internals/DateSerializer'))(ioc, ioc.DataType.DATE);
 ioc.timestampSerializer         = new (require('./internals/DateSerializer'))(ioc, ioc.DataType.TIMESTAMP);
 ioc.classSerializer             = new (require('./internals/StringSerializer'))(ioc, ioc.DataType.CLASS);
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/AnySerializer.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/AnySerializer.js
index e31d7d415b..b4395b5845 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/AnySerializer.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/AnySerializer.js
@@ -35,6 +35,7 @@ module.exports = class AnySerializer {
       ioc.numberSerializationStrategy,
 
       ioc.booleanSerializer,
+      ioc.offsetDateTimeSerializer,
       ioc.dateSerializer,
       ioc.bytecodeSerializer,
       ioc.pSerializer,
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/OffsetDateTimeSerializer.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/OffsetDateTimeSerializer.js
new file mode 100644
index 0000000000..30045ffd0f
--- /dev/null
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/binary/internals/OffsetDateTimeSerializer.js
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+'use strict';
+
+const { Buffer } = require('buffer');
+
+module.exports = class OffsetDateTimeSerializer {
+  constructor(ioc, ID) {
+    this.ioc = ioc;
+    this.ID = ID;
+    this.ioc.serializers[ID] = this;
+  }
+
+  canBeUsedFor(value) {
+    return value instanceof Date;
+  }
+
+  serialize(item, fullyQualifiedFormat = true) {
+    if (item === undefined || item === null) {
+      if (fullyQualifiedFormat) {
+        return Buffer.from([this.ID, 0x01]);
+      }
+      return Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+    }
+
+    const bufs = [];
+    if (fullyQualifiedFormat) {
+      bufs.push(Buffer.from([this.ID, 0x00]));
+    }
+
+    // NOTE: js Date will always display time in UTC, but regular date/hour getters will return in local system time.
+    // To avoid inconsistency we will always serialize the UTC representation of the Date object with offset of 0.
+
+    // {year}
+    let v = Buffer.alloc(4);
+    v.writeInt32BE(item.getUTCFullYear());
+    bufs.push(v);
+
+    // {month}
+    v = Buffer.alloc(1);
+    v.writeUInt8(item.getUTCMonth() + 1); // Java Core DateTime serializer uses 1 - 12 for months, JS uses indices
+    bufs.push(v);
+
+    // {day} - in UTC
+    v = Buffer.alloc(1);
+    v.writeUInt8(item.getUTCDate());
+    bufs.push(v);
+
+    // {nanoseconds}
+    const h = item.getUTCHours(); // in UTC
+    const m = item.getUTCMinutes();
+    const s = item.getUTCSeconds();
+    const ms = item.getUTCMilliseconds();
+    const ns = h * 60 * 60 * 1e9 + m * 60 * 1e9 + s * 1e9 + ms * 1e6;
+    v = Buffer.alloc(8);
+    v.writeBigInt64BE(BigInt(ns));
+    bufs.push(v);
+
+    // {zone offset} - UTC is always used for serialization, as such offset will be 0
+    v = Buffer.alloc(4);
+    v.writeInt32BE(0);
+    bufs.push(v);
+
+    return Buffer.concat(bufs);
+  }
+
+  deserialize(buffer, fullyQualifiedFormat = true) {
+    let len = 0;
+    let cursor = buffer;
+
+    try {
+      if (buffer === undefined || buffer === null || !(buffer instanceof Buffer)) {
+        throw new Error('buffer is missing');
+      }
+      if (buffer.length < 1) {
+        throw new Error('buffer is empty');
+      }
+
+      if (fullyQualifiedFormat) {
+        const type_code = cursor.readUInt8();
+        len++;
+        if (type_code !== this.ID) {
+          throw new Error('unexpected {type_code}');
+        }
+        cursor = cursor.slice(1);
+
+        if (cursor.length < 1) {
+          throw new Error('{value_flag} is missing');
+        }
+        const value_flag = cursor.readUInt8();
+        len++;
+        if (value_flag === 1) {
+          return { v: null, len };
+        }
+        if (value_flag !== 0) {
+          throw new Error('unexpected {value_flag}');
+        }
+        cursor = cursor.slice(1);
+      }
+
+      if (cursor.length < 8) {
+        throw new Error('unexpected {value} length');
+      }
+      len += 18;
+
+      const year = cursor.readInt32BE();
+      cursor = cursor.slice(4);
+      const month = cursor.readUInt8() - 1;
+      cursor = cursor.slice(1);
+      const date = cursor.readUInt8();
+      cursor = cursor.slice(1);
+      const ns = cursor.readBigInt64BE();
+      cursor = cursor.slice(8);
+      const offset = cursor.readInt32BE();
+      cursor.slice(4);
+
+      // calculate hour, minute, second, and ms from ns as JS Date doesn't have ns precision
+      const totalMS = ns / BigInt(1e6);
+      const ms = Number(totalMS) % 1e3;
+      const totalS = Math.trunc(Number(totalMS) / 1e3) - offset; // js Date doesn't have a way to set offset properly, account offset here to use UTC
+      const s = totalS % 60;
+      const totalM = Math.trunc(totalS / 60);
+      const m = totalM % 60;
+      const h = Math.trunc(totalM / 60);
+
+      // use UTC time calculated with offset above
+      const v = new Date(Date.UTC(year, month, date, h, m, s, ms));
+
+      return { v, len };
+    } catch (err) {
+      throw this.ioc.utils.des_error({ serializer: this, args: arguments, cursor, err });
+    }
+  }
+};
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
index 71b1ba2dcc..e022d9ef58 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/graph-serializer.js
@@ -253,6 +253,7 @@ const graphSON2Deserializers = {
   'g:Float': typeSerializers.NumberSerializer,
   'g:Double': typeSerializers.NumberSerializer,
   'g:Date': typeSerializers.DateSerializer,
+  'gx:OffsetDateTime': typeSerializers.OffsetDateTimeSerializer,
   'g:Direction': typeSerializers.DirectionSerializer,
   'g:Vertex': typeSerializers.VertexSerializer,
   'g:Edge': typeSerializers.EdgeSerializer,
@@ -272,7 +273,7 @@ const graphSON3Deserializers = Object.assign({}, graphSON2Deserializers, {
 
 const graphSON2Serializers = [
   typeSerializers.NumberSerializer,
-  typeSerializers.DateSerializer,
+  typeSerializers.OffsetDateTimeSerializer,
   typeSerializers.BytecodeSerializer,
   typeSerializers.TraverserSerializer,
   typeSerializers.TraversalStrategySerializer,
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
index 6747a1b0f0..dc9c705f88 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
@@ -87,10 +87,18 @@ class NumberSerializer extends TypeSerializer {
 }
 
 class DateSerializer extends TypeSerializer {
+  // only deserialize g:Date objects
+  deserialize(obj) {
+    return new Date(obj[valueKey]);
+  }
+}
+
+class OffsetDateTimeSerializer extends TypeSerializer {
+  // Date objects are serialized as OffsetDateTime by default
   serialize(item) {
     return {
-      [typeKey]: 'g:Date',
-      [valueKey]: item.getTime(),
+      [typeKey]: 'gx:OffsetDateTime',
+      [valueKey]: item.toISOString(),
     };
   }
 
@@ -495,6 +503,7 @@ module.exports = {
   BulkSetSerializer,
   BytecodeSerializer,
   DateSerializer,
+  OffsetDateTimeSerializer,
   DirectionSerializer,
   EdgeSerializer,
   EnumSerializer,
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 ec6d3f1f26..4485104c9a 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
@@ -602,6 +602,7 @@ const gremlins = {
     g_V_hasXperson_name_aliceX_propertyXsingle_age_unionXage_constantX1XX_sumX: [function({g}) { return g.addV("person").property("name", "alice").property(Cardinality.single, "age", 50) }, function({g}) { return g.V().has("person", "name", "alice").property("age", __.union(__.values("age"), __.constant(1)).sum()) }, function({g}) { return g.V().has("person", "age", 50) }, function({g}) { return g.V().has("person", "age", 51) }], 
     g_V_limitX3X_addVXsoftwareX_aggregateXa1X_byXlabelX_aggregateXa2X_byXlabelX_capXa1_a2X_selectXa_bX_byXunfoldX_foldX: [function({g}) { return g.addV("person").property("name", "marko").property("age", 29).as("marko").addV("person").property("name", "vadas").property("age", 27).as("vadas").addV("software").property("name", "lop").property("lang", "java").as("lop").addV("person").property("name", "josh").property("age", 32).as("josh").addV("software").property("name", "ripple").property [...]
     g_injectXstrX_asDate: [function({g}) { return g.inject("2023-08-02T00:00:00Z").asDate() }], 
+    g_injectXstr_offsetX_asDate: [function({g}) { return g.inject("2023-08-02T00:00:00-07:00").asDate() }], 
     g_injectX1694017707000X_asDate: [function({g}) { return g.inject(1694017707000).asDate() }], 
     g_injectX1694017708000LX_asDate: [function({g, xx1}) { return g.inject(xx1).asDate() }], 
     g_injectX1694017709000dX_asDate: [function({g, xx1}) { return g.inject(xx1).asDate() }], 
@@ -714,15 +715,15 @@ const gremlins = {
     g_V_order_byXnoX_count: [function({g}) { return g.V().order().by("no").count() }], 
     g_V_group_byXlabelX_count: [function({g}) { return g.V().group().by(T.label).count() }], 
     g_V_group_byXlabelX_countXlocalX: [function({g}) { return g.V().group().by(T.label).count(Scope.local) }], 
-    g_injectXdatetimeXstrXX_dateAddXDT_hour_2X: [function({g}) { return g.inject(new Date(1690934400000)).dateAdd(DT.hour, 2) }], 
-    g_injectXdatetimeXstrXX_dateAddXhour_2X: [function({g}) { return g.inject(new Date(1690934400000)).dateAdd(DT.hour, 2) }], 
-    g_injectXdatetimeXstrXX_dateAddXhour_1X: [function({g}) { return g.inject(new Date(1690934400000)).dateAdd(DT.hour, -1) }], 
-    g_injectXdatetimeXstrXX_dateAddXminute_10X: [function({g}) { return g.inject(new Date(1690934400000)).dateAdd(DT.minute, 10) }], 
-    g_injectXdatetimeXstrXX_dateAddXsecond_20X: [function({g}) { return g.inject(new Date(1690934400000)).dateAdd(DT.second, 20) }], 
-    g_injectXdatetimeXstrXX_dateAddXday_11X: [function({g}) { return g.inject(new Date(1693958400000)).dateAdd(DT.day, 11) }], 
-    g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX: [function({g}) { return g.inject(new Date(1690934400000)).dateDiff(new Date(1691539200000)) }], 
-    g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX: [function({g}) { return g.inject(new Date(1691452800000)).dateDiff(__.constant(new Date(1690848000000))) }], 
-    g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX: [function({g}) { return g.inject(new Date(1691452800000)).dateDiff(__.inject(new Date(1696982400000))) }], 
+    g_injectXdatetimeXstrXX_dateAddXDT_hour_2X: [function({g}) { return g.inject(new Date('2023-08-02T00:00Z')).dateAdd(DT.hour, 2) }], 
+    g_injectXdatetimeXstrXX_dateAddXhour_2X: [function({g}) { return g.inject(new Date('2023-08-02T00:00Z')).dateAdd(DT.hour, 2) }], 
+    g_injectXdatetimeXstrXX_dateAddXhour_1X: [function({g}) { return g.inject(new Date('2023-08-02T00:00Z')).dateAdd(DT.hour, -1) }], 
+    g_injectXdatetimeXstrXX_dateAddXminute_10X: [function({g}) { return g.inject(new Date('2023-08-02T00:00Z')).dateAdd(DT.minute, 10) }], 
+    g_injectXdatetimeXstrXX_dateAddXsecond_20X: [function({g}) { return g.inject(new Date('2023-08-02T00:00Z')).dateAdd(DT.second, 20) }], 
+    g_injectXdatetimeXstrXX_dateAddXday_11X: [function({g}) { return g.inject(new Date('2023-09-06T00:00Z')).dateAdd(DT.day, 11) }], 
+    g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX: [function({g}) { return g.inject(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')).dateDiff(__.constant(new Date('2023-08-01T00:00Z'))) }], 
+    g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX: [function({g}) { return g.inject(new Date('2023-08-08T00:00Z')).dateDiff(__.inject(new Date('2023-10-11T00:00Z'))) }], 
     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-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
index 3c6a53f836..ae7518f13a 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphbinary/AnySerializer-test.js
@@ -75,8 +75,11 @@ describe('GraphBinary.AnySerializer', () => {
       // TODO
       // Yes, Float and Short are not used
 
-      // DateSerializer
-      { v:new Date(1651436603000), b:[DataType.DATE,0x00, 0x00,0x00,0x01,0x80,0x81,0x4A,0xC6,0x78] },
+      // OffestDateTimeSerializer
+      { v:new Date(1651436603000),
+          b:[DataType.OFFSETDATETIME,0x00, 0x00,0x00,0x07,0xe6,0x05,0x01,0x00,0x00,0x42,0xc2,0x77,0xbd,0x8e,0x00,0x00,0x00,0x00,0x00] },
+      { v:new Date('2023-08-02T01:23:45-07:30'),
+          b:[DataType.OFFSETDATETIME,0x00, 0x00,0x00,0x07,0xe7,0x08,0x02,0x00,0x00,0x1d,0x20,0x66,0xbf,0xba,0x00,0x00,0x00,0x00,0x00] },
 
       // BytecodeSerializer
       // Traversal type
@@ -374,6 +377,15 @@ describe('GraphBinary.AnySerializer', () => {
       { v:null,                                   b:[0x04,0x01] },
       { v:new Date('1969-12-31T23:59:59.999Z'),   b:[0x04,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF] },
 
+      // OFFSETDATETIME
+      { v:null,                                   b:[0x88,0x01] },
+      { v:new Date('2023-08-02T01:30:00-10:00'),
+          b:[0x88,0x00,
+              0x00,0x00,0x07,0xe7,
+              0x08,0x02,
+              0x00,0x00,0x04,0xe9,0x49,0x14,0xf0,0x00,
+              0xFF,0xFF,0x73,0x60] },
+
       // TIMESTAMP
       { v:null,                                   b:[0x05,0x01] },
       { v:new Date('1969-12-31T23:59:59.999Z'),   b:[0x05,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF] },
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
index cc7febc4d6..63e51f915d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/unit/graphson-test.js
@@ -206,9 +206,9 @@ describe('GraphSONWriter', function () {
     const expected = JSON.stringify({ "@type" : "g:Double", "@value" : "-Infinity" });
     assert.strictEqual(writer.write(Number.NEGATIVE_INFINITY), expected);
   });
-  it('should write Date', function() {
+  it('should write Date (as OffsetDateTime', function() {
     const writer = new GraphSONWriter();
-    const expected = JSON.stringify({ "@type" : "g:Date", "@value" : 1481750076295 });
+    const expected = JSON.stringify({ "@type" : "gx:OffsetDateTime", "@value" : "2016-12-14T21:14:36.295Z" });
     assert.strictEqual(writer.write(new Date(1481750076295)), expected);
   });
   it('should write boolean values', function () {
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
index 20228bcd1c..d74561bb8a 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
@@ -106,7 +106,7 @@ class DataType(Enum):
     localdatetime = 0x85          # todo
     localtime = 0x86              # todo
     monthday = 0x87               # todo
-    offsetdatetime = 0x88         # todo
+    offsetdatetime = 0x88
     offsettime = 0x89             # todo
     period = 0x8a                 # todo
     year = 0x8b                   # todo
@@ -343,6 +343,44 @@ class DateIO(_GraphBinaryTypeIO):
                            nullable)
 
 
+class OffsetDateTimeIO(_GraphBinaryTypeIO):
+
+    python_type = datetime.datetime
+    graphbinary_type = DataType.offsetdatetime
+
+    @classmethod
+    def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
+        if obj.tzinfo is None:
+            return DateIO.dictify(obj, writer, to_extend, as_value, nullable)
+        cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
+        IntIO.dictify(obj.year, writer, to_extend, True, False)
+        ByteIO.dictify(obj.month, writer, to_extend, True, False)
+        ByteIO.dictify(obj.day, writer, to_extend, True, False)
+        # construct time of day in nanoseconds
+        h = obj.time().hour
+        m = obj.time().minute
+        s = obj.time().second
+        ms = obj.time().microsecond
+        ns = round((h*60*60*1e9) + (m*60*1e9) + (s*1e9) + (ms*1e3))
+        LongIO.dictify(ns, writer, to_extend, True, False)
+        os = round(obj.utcoffset().total_seconds())
+        IntIO.dictify(os, writer, to_extend, True, False)
+        return to_extend
+
+    @classmethod
+    def objectify(cls, buff, reader, nullable=True):
+        return cls.is_null(buff, reader, cls._read_dt, nullable)
+
+    @classmethod
+    def _read_dt(cls, b, r):
+        year = r.to_object(b, DataType.int, False)
+        month = r.to_object(b, DataType.byte, False)
+        day = r.to_object(b, DataType.byte, False)
+        ns = r.to_object(b, DataType.long, False)
+        offset = r.to_object(b, DataType.int, False)
+        tz = datetime.timezone(timedelta(seconds=offset))
+        return datetime.datetime(year, month, day, tzinfo=tz) + timedelta(microseconds=ns/1000)
+
 # Based on current implementation, this class must always be declared before FloatIO.
 # Seems pretty fragile for future maintainers. Maybe look into this.
 class TimestampIO(_GraphBinaryTypeIO):
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
index d4138b6c9d..69b76ea122 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py
@@ -339,7 +339,6 @@ class UUIDIO(_GraphSONTypeIO):
 
 
 class DateIO(_GraphSONTypeIO):
-    python_type = datetime.datetime
     graphson_type = "g:Date"
     graphson_base_type = "Date"
 
@@ -360,6 +359,24 @@ class DateIO(_GraphSONTypeIO):
         return datetime.datetime.utcfromtimestamp(ts / 1000.0)
 
 
+    class OffsetDateTimeIO(_GraphSONTypeIO):
+        python_type = datetime.datetime
+        graphson_type = "gx:OffsetDateTime"
+        graphson_base_type = "OffsetDateTime"
+
+        @classmethod
+        def dictify(cls, obj, writer):
+            if obj.tzinfo is None:
+                return DateIO.dictify(obj, writer)
+            return GraphSONUtil.typed_value(cls.graphson_base_type, obj.isoformat(), "gx")
+
+        @classmethod
+        def objectify(cls, dt, reader):
+            # specially handling as python isoformat does not support zulu until 3.11
+            dt_iso = dt[:-1] + '+00:00' if dt.endswith('Z') else dt
+            return datetime.datetime.fromisoformat(dt_iso)
+
+
 # Based on current implementation, this class must always be declared before FloatIO.
 # Seems pretty fragile for future maintainers. Maybe look into this.
 class TimestampIO(_GraphSONTypeIO):
diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
index 692e4d27b0..9780a2cf15 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
@@ -346,7 +346,6 @@ class UUIDIO(_GraphSONTypeIO):
 
 
 class DateIO(_GraphSONTypeIO):
-    python_type = datetime.datetime
     graphson_type = "g:Date"
     graphson_base_type = "Date"
 
@@ -367,6 +366,24 @@ class DateIO(_GraphSONTypeIO):
         return datetime.datetime.utcfromtimestamp(ts / 1000.0)
 
 
+class OffsetDateTimeIO(_GraphSONTypeIO):
+    python_type = datetime.datetime
+    graphson_type = "gx:OffsetDateTime"
+    graphson_base_type = "OffsetDateTime"
+
+    @classmethod
+    def dictify(cls, obj, writer):
+        if obj.tzinfo is None:
+            return DateIO.dictify(obj, writer)
+        return GraphSONUtil.typed_value(cls.graphson_base_type, obj.isoformat(), "gx")
+
+    @classmethod
+    def objectify(cls, dt, reader):
+        # specially handling as python isoformat does not support zulu until 3.11
+        dt_iso = dt[:-1] + '+00:00' if dt.endswith('Z') else dt
+        return datetime.datetime.fromisoformat(dt_iso)
+
+
 # Based on current implementation, this class must always be declared before FloatIO.
 # Seems pretty fragile for future maintainers. Maybe look into this.
 class TimestampIO(_GraphSONTypeIO):
diff --git a/gremlin-python/src/main/python/radish/feature_steps.py b/gremlin-python/src/main/python/radish/feature_steps.py
index a31c4d7e3c..e87be53f41 100644
--- a/gremlin-python/src/main/python/radish/feature_steps.py
+++ b/gremlin-python/src/main/python/radish/feature_steps.py
@@ -244,7 +244,7 @@ def _convert(val, ctx):
         return val[4:-1]
     elif isinstance(val, str) and re.match(r"^dt\[.*\]$", val):  # parse datetime
         # python 3.8 can handle only subset of ISO 8601 dates
-        return datetime.fromisoformat(val[3:-1].replace('Z', ''))
+        return datetime.fromisoformat(val[3:-1].replace('Z', '+00:00'))
     elif isinstance(val, str) and re.match(r"^d\[NaN\]$", val):  # parse nan
         return float("nan")
     elif isinstance(val, str) and re.match(r"^d\[Infinity\]$", val):  # parse +inf
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 67857503ed..eddc2a5a9a 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -584,6 +584,7 @@ world.gremlins = {
     'g_V_hasXperson_name_aliceX_propertyXsingle_age_unionXage_constantX1XX_sumX': [(lambda g:g.add_v('person').property('name', 'alice').property(Cardinality.single, 'age', 50)), (lambda g:g.V().has('person', 'name', 'alice').property('age', __.union(__.values('age'), __.constant(1)).sum_())), (lambda g:g.V().has('person', 'age', 50)), (lambda g:g.V().has('person', 'age', 51))], 
     'g_V_limitX3X_addVXsoftwareX_aggregateXa1X_byXlabelX_aggregateXa2X_byXlabelX_capXa1_a2X_selectXa_bX_byXunfoldX_foldX': [(lambda g:g.add_v('person').property('name', 'marko').property('age', 29).as_('marko').add_v('person').property('name', 'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 'josh').property('age', 32).as_('josh').add_v('software').property('name', 'ripple').property(' [...]
     'g_injectXstrX_asDate': [(lambda g:g.inject('2023-08-02T00:00:00Z').as_date())], 
+    'g_injectXstr_offsetX_asDate': [(lambda g:g.inject('2023-08-02T00:00:00-07:00').as_date())], 
     'g_injectX1694017707000X_asDate': [(lambda g:g.inject(long(1694017707000)).as_date())], 
     'g_injectX1694017708000LX_asDate': [(lambda g, xx1=None:g.inject(xx1).as_date())], 
     'g_injectX1694017709000dX_asDate': [(lambda g, xx1=None:g.inject(xx1).as_date())], 
@@ -696,15 +697,15 @@ world.gremlins = {
     'g_V_order_byXnoX_count': [(lambda g:g.V().order().by('no').count())], 
     'g_V_group_byXlabelX_count': [(lambda g:g.V().group().by(T.label).count())], 
     'g_V_group_byXlabelX_countXlocalX': [(lambda g:g.V().group().by(T.label).count(Scope.local))], 
-    'g_injectXdatetimeXstrXX_dateAddXDT_hour_2X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_add(DT.hour, 2))], 
-    'g_injectXdatetimeXstrXX_dateAddXhour_2X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_add(DT.hour, 2))], 
-    'g_injectXdatetimeXstrXX_dateAddXhour_1X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_add(DT.hour, -1))], 
-    'g_injectXdatetimeXstrXX_dateAddXminute_10X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_add(DT.minute, 10))], 
-    'g_injectXdatetimeXstrXX_dateAddXsecond_20X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_add(DT.second, 20))], 
-    'g_injectXdatetimeXstrXX_dateAddXday_11X': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1693958400000 / 1000.0)).date_add(DT.day, 11))], 
-    'g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1690934400000 / 1000.0)).date_diff(datetime.datetime.utcfromtimestamp(1691539200000 / 1000.0)))], 
-    'g_injectXdatetimeXstr1XX_dateDiffXconstantXdatetimeXstr2XXX': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1691452800000 / 1000.0)).date_diff(__.constant(datetime.datetime.utcfromtimestamp(1690848000000 / 1000.0))))], 
-    'g_injectXdatetimeXstr1XX_dateDiffXinjectXdatetimeXstr2XXX': [(lambda g:g.inject(datetime.datetime.utcfromtimestamp(1691452800000 / 1000.0)).date_diff(__.inject(datetime.datetime.utcfromtimestamp(1696982400000 / 1000.0))))], 
+    'g_injectXdatetimeXstrXX_dateAddXDT_hour_2X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_add(DT.hour, 2))], 
+    'g_injectXdatetimeXstrXX_dateAddXhour_2X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_add(DT.hour, 2))], 
+    'g_injectXdatetimeXstrXX_dateAddXhour_1X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_add(DT.hour, -1))], 
+    'g_injectXdatetimeXstrXX_dateAddXminute_10X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_add(DT.minute, 10))], 
+    'g_injectXdatetimeXstrXX_dateAddXsecond_20X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-08-02T00:00+00:00')).date_add(DT.second, 20))], 
+    'g_injectXdatetimeXstrXX_dateAddXday_11X': [(lambda g:g.inject(datetime.datetime.fromisoformat('2023-09-06T00:00+00:00')).date_add(DT.day, 11))], 
+    'g_injectXdatetimeXstr1XX_dateDiffXdatetimeXstr2XX': [(lambda g:g.inject(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')).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')).date_diff(__.inject(datetime.datetime.fromisoformat('2023-10-11T00:00+00:00'))))], 
     '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-python/src/main/python/tests/process/test_traversal.py b/gremlin-python/src/main/python/tests/process/test_traversal.py
index 8a085e3593..90a4026bfa 100644
--- a/gremlin-python/src/main/python/tests/process/test_traversal.py
+++ b/gremlin-python/src/main/python/tests/process/test_traversal.py
@@ -27,8 +27,7 @@ from gremlin_python.driver import serializer
 from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
 from gremlin_python.structure.graph import Graph
 from gremlin_python.process.anonymous_traversal import traversal
-from gremlin_python.process.traversal import P, Direction
-from gremlin_python.process.traversal import Binding, Bindings
+from gremlin_python.process.traversal import P, Direction, Bindings, Binding
 from gremlin_python.process.graph_traversal import __
 
 gremlin_server_url = os.environ.get('GREMLIN_SERVER_URL', 'ws://localhost:{}/gremlin')
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py b/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py
index d67efb460f..d6effb4813 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_functionalityio.py
@@ -22,6 +22,7 @@ import uuid
 
 from gremlin_python.driver.serializer import GraphSONSerializersV2d0, GraphBinarySerializersV1
 from gremlin_python.process.anonymous_traversal import traversal
+from gremlin_python.process.traversal import DT
 from gremlin_python.statics import *
 
 
@@ -106,6 +107,19 @@ def test_datetime(remote_connection):
     finally:
         g.V(vid).drop().iterate()
 
+def test_offsetdatetime(remote_connection):
+    g = traversal().with_(remote_connection)
+    tz = datetime.timezone(datetime.timedelta(seconds=36000))
+    ms = 12345678912
+    dt = datetime.datetime(2022, 5, 20, tzinfo=tz) + datetime.timedelta(microseconds=ms)
+    resp = g.add_v('test_vertex').property('dt', dt).to_list()
+    vid = resp[0].id
+    try:
+        dt_prop = g.V(vid).properties('dt').to_list()[0]
+        assert isinstance(dt_prop.value, datetime.datetime)
+        assert dt_prop.value == dt
+    finally:
+        g.V(vid).drop().iterate()
 
 def test_uuid(remote_connection):
     g = traversal().with_(remote_connection)
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
index 32201b78a9..102be4997a 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphbinaryV1.py
@@ -17,11 +17,11 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import datetime
 import uuid
 import math
 
-from gremlin_python.statics import timestamp, long, bigint, BigDecimal, SingleByte, SingleChar, ByteBufferType
+from datetime import datetime, timedelta, timezone
+from gremlin_python.statics import long, bigint, BigDecimal, SingleByte, SingleChar, ByteBufferType, timestamp
 from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Path
 from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, GraphBinaryReader
 from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Merge, Direction
@@ -31,7 +31,7 @@ class TestGraphBinaryReader(object):
     graphbinary_reader = GraphBinaryReader()
 
 
-class TestGraphSONWriter(object):
+class TestGraphBinaryWriter(object):
     graphbinary_writer = GraphBinaryWriter()
     graphbinary_reader = GraphBinaryReader()
 
@@ -83,7 +83,7 @@ class TestGraphSONWriter(object):
         assert x.unscaled_value == output.unscaled_value
 
     def test_date(self):
-        x = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
+        x = datetime(2016, 12, 14, 16, 14, 36, 295000)
         output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
         assert x == output
 
@@ -92,6 +92,28 @@ class TestGraphSONWriter(object):
         output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
         assert x == output
 
+    def test_offsetdatetime(self):
+        tz = timezone(timedelta(seconds=36000))
+        ms = 12345678912
+        x = datetime(2022, 5, 20, tzinfo=tz) + timedelta(microseconds=ms)
+        output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
+        assert x == output
+
+    def test_offsetdatetime_format(self):
+        x = datetime.strptime('2022-05-20T03:25:45.678912Z', '%Y-%m-%dT%H:%M:%S.%f%z')
+        output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
+        assert x == output
+
+    def test_offsetdatetime_local(self):
+        x = datetime.now().astimezone()
+        output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
+        assert x == output
+
+    def test_offsetdatetime_epoch(self):
+        x = datetime.fromtimestamp(1690934400).astimezone(timezone.utc)
+        output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
+        assert x == output
+
     def test_string(self):
         x = "serialize this!"
         output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
@@ -233,6 +255,6 @@ class TestGraphSONWriter(object):
         assert x == output
 
     def test_duration(self):
-        x = datetime.timedelta(seconds=1000, microseconds=1000)
+        x = timedelta(seconds=1000, microseconds=1000)
         output = self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(x))
         assert x == output
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
index 8bcb1fbb01..9afb2d3ac8 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py
@@ -250,10 +250,28 @@ class TestGraphSONReader:
         expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
         pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
         ts = int(round(pts * 1000))
-        dt = self.graphson_reader.read_object(json.dumps({"@type": "g:Date", "@value": ts}))
-        assert isinstance(dt, datetime.datetime)
+        output = self.graphson_reader.read_object(json.dumps({"@type": "g:Date", "@value": ts}))
+        assert isinstance(output, datetime.datetime)
         # TINKERPOP-1848
-        assert dt == expected
+        assert expected == output
+
+    def test_offsetdatetime(self):
+        tz = datetime.timezone(datetime.timedelta(seconds=36000))
+        ms = 12345678912
+        expected = datetime.datetime(2022, 5, 20, tzinfo=tz) + datetime.timedelta(microseconds=ms)
+        output = self.graphson_reader.read_object(json.dumps({"@type": "gx:OffsetDateTime", "@value": expected.isoformat()}))
+        assert isinstance(output, datetime.datetime)
+        assert expected == output
+
+    def test_offsetdatetime_zulu(self):
+        tz = datetime.timezone.utc
+        ms = 12345678912
+        expected = datetime.datetime(2022, 5, 20, tzinfo=tz) + datetime.timedelta(microseconds=ms)
+        # simulate zulu format
+        expected_zulu = expected.isoformat()[:-6] + 'Z'
+        output = self.graphson_reader.read_object(json.dumps({"@type": "gx:OffsetDateTime", "@value": expected_zulu}))
+        assert isinstance(output, datetime.datetime)
+        assert expected == output
 
     def test_timestamp(self):
         dt = self.graphson_reader.read_object(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
index a6a65a84e4..6025a0c674 100644
--- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
+++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py
@@ -295,10 +295,28 @@ class TestGraphSONReader:
         expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
         pts = calendar.timegm(expected.utctimetuple()) + expected.microsecond / 1e6
         ts = int(round(pts * 1000))
-        dt = self.graphson_reader.read_object(json.dumps({"@type": "g:Date", "@value": ts}))
-        assert isinstance(dt, datetime.datetime)
+        output = self.graphson_reader.read_object(json.dumps({"@type": "g:Date", "@value": ts}))
+        assert isinstance(output, datetime.datetime)
         # TINKERPOP-1848
-        assert dt == expected
+        assert expected == output
+
+    def test_offsetdatetime(self):
+        tz = datetime.timezone(datetime.timedelta(seconds=36000))
+        ms = 12345678912
+        expected = datetime.datetime(2022, 5, 20, tzinfo=tz) + datetime.timedelta(microseconds=ms)
+        output = self.graphson_reader.read_object(json.dumps({"@type": "gx:OffsetDateTime", "@value": expected.isoformat()}))
+        assert isinstance(output, datetime.datetime)
+        assert expected == output
+
+    def test_offsetdatetime_zulu(self):
+        tz = datetime.timezone.utc
+        ms = 12345678912
+        expected = datetime.datetime(2022, 5, 20, tzinfo=tz) + datetime.timedelta(microseconds=ms)
+        # simulate zulu format
+        expected_zulu = expected.isoformat()[:-6] + 'Z'
+        output = self.graphson_reader.read_object(json.dumps({"@type": "gx:OffsetDateTime", "@value": expected_zulu}))
+        assert isinstance(output, datetime.datetime)
+        assert expected == output
 
     def test_timestamp(self):
         dt = self.graphson_reader.read_object(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
index 40de5c0563..6476580645 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
@@ -1046,7 +1046,7 @@ public class GremlinServerHttpIntegrateTest extends AbstractGremlinServerIntegra
             assertEquals("application/json", response.getEntity().getContentType().getValue());
             final String json = EntityUtils.toString(response.getEntity());
             final JsonNode node = mapper.readTree(json);
-            assertEquals(1521621344741L, node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).longValue());
+            assertEquals("2018-03-22T00:35:44.741+16:00", node.get("result").get("data").get(GraphSONTokens.VALUEPROP).get(0).get(GraphSONTokens.VALUEPROP).textValue());
         }
     }
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/OrderabilityTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/OrderabilityTest.java
index e99812aca6..a9ff65a080 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/OrderabilityTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/OrderabilityTest.java
@@ -37,6 +37,9 @@ import static org.apache.tinkerpop.gremlin.structure.Graph.Features.GraphFeature
 import static org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexFeatures;
 import static org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexPropertyFeatures;
 
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
@@ -50,7 +53,7 @@ public abstract class OrderabilityTest extends AbstractGremlinProcessTest {
 
     private interface Constants {
         UUID uuid = UUID.randomUUID();
-        Date date = new Date();
+        OffsetDateTime date = OffsetDateTime.now(ZoneOffset.UTC);
         List list1 = Arrays.asList(1, 2, 3);
         List list2 = Arrays.asList(1, 2, 3, 4);
         Set set1 = CollectionUtil.asSet(list1);
@@ -185,12 +188,12 @@ public abstract class OrderabilityTest extends AbstractGremlinProcessTest {
                 null,
                 false, true,
                 1, 2.0,
-                Constants.date,
                 "bar", "foo",
                 Constants.uuid,
                 Constants.set1, Constants.set2,
                 Constants.list1, Constants.list2,
-                Constants.map1, Constants.map2
+                Constants.map1, Constants.map2,
+                Constants.date
         ), traversal);
     }
 
@@ -211,13 +214,13 @@ public abstract class OrderabilityTest extends AbstractGremlinProcessTest {
                 null,
                 false, true,
                 1, 2.0,
-                Constants.date,
                 "bar", "foo",
                 Constants.uuid,
                 Constants.set1, Constants.set2,
                 Constants.list1, Constants.list2,
                 Constants.map1, Constants.map2,
-                unknown
+                unknown,
+                Constants.date
         ), traversal);
     }
 
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 1bf47db075..ed24398b5f 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
@@ -30,6 +30,18 @@ Feature: Step - asDate()
       | result |
       | dt[2023-08-02T00:00:00Z] |
 
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXstr_offsetX_asDate
+    Given the empty graph
+    And the traversal of
+      """
+      g.inject("2023-08-02T00:00:00-07:00").asDate()
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | dt[2023-08-02T00:00:00-07:00] |
+
   @GraphComputerVerificationInjectionNotSupported
   Scenario: g_injectX1694017707000X_asDate
     Given the empty graph
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePerson.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePerson.java
index 2970dce3bb..1e1f238038 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePerson.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePerson.java
@@ -18,7 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.util.ser.binary.types.sample;
 
-import java.util.Date;
+import java.time.OffsetDateTime;
 import java.util.Objects;
 
 /**
@@ -26,9 +26,9 @@ import java.util.Objects;
  */
 public class SamplePerson {
     private final String name;
-    private final Date birthDate;
+    private final OffsetDateTime birthDate;
 
-    SamplePerson(final String name, final Date birthDate) {
+    SamplePerson(final String name, final OffsetDateTime birthDate) {
         Objects.requireNonNull(name);
         Objects.requireNonNull(birthDate);
 
@@ -40,7 +40,7 @@ public class SamplePerson {
         return name;
     }
 
-    public Date getBirthDate() {
+    public OffsetDateTime getBirthDate() {
         return birthDate;
     }
 }
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializer.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializer.java
index 2a76206c72..a030ed46d7 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializer.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializer.java
@@ -27,7 +27,7 @@ import org.apache.tinkerpop.gremlin.structure.io.binary.types.CustomTypeSerializ
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.Date;
+import java.time.OffsetDateTime;
 
 /**
  * A sample custom type serializer.
@@ -78,7 +78,7 @@ public final class SamplePersonSerializer implements CustomTypeSerializer<Sample
         }
 
         final String name = context.readValue(buffer, String.class, false);
-        final Date birthDate = context.readValue(buffer, Date.class, false);
+        final OffsetDateTime birthDate = context.readValue(buffer, OffsetDateTime.class, false);
 
         return new SamplePerson(name, birthDate);
     }
diff --git a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializerTest.java b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializerTest.java
index c17e976a2f..0d4caaf0d0 100644
--- a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializerTest.java
+++ b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/types/sample/SamplePersonSerializerTest.java
@@ -33,6 +33,7 @@ import org.junit.Test;
 
 import java.io.IOException;
 import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.util.Collections;
 import java.util.Date;
@@ -86,7 +87,7 @@ public class SamplePersonSerializerTest {
         final GraphBinaryWriter writer = new GraphBinaryWriter(registry);
 
         final SamplePerson person = new SamplePerson("Matias",
-                Date.from(LocalDateTime.of(2005, 8, 5, 1, 0).toInstant(ZoneOffset.UTC)));
+                OffsetDateTime.of(LocalDateTime.of(2005, 8, 5, 1, 0), ZoneOffset.UTC));
 
         for (boolean nullable: new boolean[] { true, false }) {
             final Buffer buffer = bufferFactory.create(allocator.buffer());
@@ -99,7 +100,7 @@ public class SamplePersonSerializerTest {
     }
 
     private void assertPerson(final GraphBinaryMessageSerializerV1 serializer) throws IOException {
-        final Date birthDate = Date.from(LocalDateTime.of(2010, 4, 29, 5, 30).toInstant(ZoneOffset.UTC));
+        final OffsetDateTime birthDate = OffsetDateTime.of(LocalDateTime.of(2010, 4, 29, 5, 30), ZoneOffset.UTC);
         final SamplePerson person = new SamplePerson("Olivia", birthDate);
 
         final ByteBuf serialized = serializer.serializeResponseAsBinary(