Skip to content

Temporal map constructors reject microsecond values 1000–999999, contrary to openCypher TCK #5096

Open

Description

@shulei5831sl

Memgraph version

  • Memgraph 3.13.2
  • Also reproduced on Memgraph 3.12.0 and 3.11.0
  • Reference: Neo4j 2026.05.0-community (behaves as expected)

Description

Memgraph rejects valid microsecond values greater than 999 when constructing temporal values from Cypher maps.

According to the openCypher TCK (Temporal1.feature, scenarios [5] and [8]), a standalone microsecond component may represent the full microsecond-of-second range (0–999999).

For example, microsecond: 645876 should produce a fractional second of .645876.

Memgraph instead raises an exception for any microsecond value greater than 999.

This affects localtime() and datetime() map constructors.

Steps to reproduce

Run:

RETURN localtime({
  hour: 12,
  minute: 31,
  second: 14,
  microsecond: 645876
}) AS t;

Expected result (openCypher TCK):

12:31:14.645876

Actual result (Memgraph 3.13.2):

Memgraph.TransientError.MemgraphError
Creating a LocalTime with invalid microseconds parameter.

Neo4j 2026.05.0-community accepts the same query and returns the expected value.

Boundary tests

The following values were tested on Memgraph 3.13.2:

microsecond Memgraph 3.13.2 Expected behavior
0 Accepted Accepted
999 Accepted Accepted
1000 Error: invalid microseconds parameter Accepted (.001000)
645876 Error: invalid microseconds parameter Accepted (.645876)
999999 Error: invalid microseconds parameter Accepted (.999999)

Values from 0 through 999 are accepted, but values beginning at 1000 are incorrectly rejected.

The same range limitation was observed with datetime().

For example:

RETURN datetime({
  year: 1984,
  month: 10,
  day: 11,
  hour: 12,
  minute: 31,
  second: 14,
  microsecond: 645876,
  timezone: '+01:00'
}) AS dt;

Expected:

1984-10-11T12:31:14.645876+01:00

Memgraph rejects the microsecond parameter instead.

openCypher TCK reference

The expected behavior is explicitly covered by the official openCypher Technology Compatibility Kit:

Source:

https://github.com/opencypher/openCypher/blob/main/tck/features/expressions/temporal/Temporal1.feature

Scenario [5], "Should construct local time", contains:

{hour: 12, minute: 31, second: 14, microsecond: 645876}
    -> '12:31:14.645876'

Scenario [8], "Should construct date time with default time zone", likewise expects:

{year: 1984, month: 10, day: 11,
 hour: 12, minute: 31, second: 14,
 microsecond: 645876}
    -> '1984-10-11T12:31:14.645876Z'

The TCK also distinguishes standalone microsecond-of-second values from combinations of subsecond components.

For example:

RETURN localtime({
  hour: 12,
  minute: 31,
  second: 14,
  millisecond: 123,
  microsecond: 456,
  nanosecond: 789
});

The TCK expects:

12:31:14.123456789

Thus, microsecond: 645876 without a separate millisecond component is valid and must not be rejected merely because it exceeds 999.

Possible root cause

The Memgraph 3.13.2 implementation appears to validate the internal microsecond remainder directly against a range of 0–999.

In src/utils/temporal.cpp:

if (!IsInBounds(0, 999, local_time_parameters.microsecond)) {
  throw temporal::InvalidArgumentException(
      "Creating a LocalTime with invalid microseconds parameter.");
}

Source:

https://github.com/memgraph/memgraph/blob/v3.13.2/src/utils/temporal.cpp#L395-L413

The Cypher localtime() map constructor passes the supplied value directly into this internal parameter:

std::pair{"microsecond"sv, &local_time_parameters.microsecond},

Source:

https://github.com/memgraph/memgraph/blob/v3.13.2/src/query/interpret/awesome_memgraph_functions.cpp#L1750-L1762

The internal representation separates milliseconds and microseconds, which explains the 0–999 remainder check. However, a standalone Cypher map component representing 645876 microseconds should be interpreted as 645 milliseconds plus 876 additional microseconds.

The constructor appears to reject such values before performing the required normalization.

A fix may therefore require adjusting map-component normalization rather than simply increasing the internal field's validation limit.

Impact

  • Valid openCypher temporal map expressions fail at runtime.
  • Applications constructing timestamps from microsecond-of-second values cannot use the complete valid range.
  • Queries using localtime() and datetime() behave differently from openCypher TCK expectations and Neo4j.
  • The failure affects values starting at 1000 microseconds, not only extreme or out-of-range inputs.

Expected behavior

Memgraph should accept standalone microsecond values in the range 0–999999 and construct the corresponding temporal value, consistent with openCypher TCK Temporal1 scenarios [5] and [8].

For example:

RETURN localtime({
  hour: 12,
  minute: 31,
  second: 14,
  microsecond: 645876
}) AS t;

should return:

12:31:14.645876

instead of raising an invalid microseconds parameter error.

Activity

  1. added theissue type on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions