ramsey/uuid · error · UnsupportedOperationException

Not a time-based UUID

Error message

Not a time-based UUID

What it means

Deprecated Uuid::getDateTime() (removed in ramsey/uuid 5.0; replaced by UuidV1::getDateTime()) converts the 60-bit timestamp of a time-based UUID into a DateTimeImmutable. If the UUID's version nibble is not 1 it throws UnsupportedOperationException, because only v1 UUIDs carry an extractable Gregorian timestamp.

Source

Thrown at src/DeprecatedUuidMethodsTrait.php:120

     * @deprecated This method will be removed in 5.0.0. There is no alternative recommendation, so plan accordingly.
     */
    public function getNumberConverter(): NumberConverterInterface
    {
        return $this->numberConverter;
    }

    /**
     * @deprecated In ramsey/uuid version 5.0.0, this will be removed. It is available at {@see UuidV1::getDateTime()}.
     *
     * @return DateTimeImmutable An immutable instance of DateTimeInterface
     *
     * @throws UnsupportedOperationException if UUID is not time-based
     * @throws DateTimeException if DateTime throws an exception/error
     */
    public function getDateTime(): DateTimeInterface
    {
        if ($this->fields->getVersion() !== 1) {
            throw new UnsupportedOperationException('Not a time-based UUID');
        }

        $time = $this->timeConverter->convertTime($this->fields->getTimestamp());

        try {
            return new DateTimeImmutable(
                '@'
                . $time->getSeconds()->toString()
                . '.'
                . str_pad($time->getMicroseconds()->toString(), 6, '0', STR_PAD_LEFT)
            );
        } catch (Throwable $e) {
            throw new DateTimeException($e->getMessage(), (int) $e->getCode(), $e);
        }
    }

    /**
     * @deprecated Use {@see UuidInterface::getFields()} to get a {@see \Ramsey\Uuid\Fields\FieldsInterface} instance.

View on GitHub (pinned to da5b521600)

Solutions

  1. Branch on the concrete class: if ($uuid instanceof \Ramsey\Uuid\Rfc4122\UuidV1) { $uuid->getDateTime(); } and skip/derive otherwise.
  2. Generate v1 (Uuid::uuid1()) when you need the embedded timestamp - or better, UUIDv7 for time-ordered IDs.
  3. Stop relying on the UUID for timestamps: store an explicit created_at column.
  4. Complete the 5.0 migration path now: replace the deprecated trait methods with UuidV1-specific ones.

Example fix

// before
$createdAt = $uuid->getDateTime(); // throws UnsupportedOperationException on v4

// after
$createdAt = $uuid instanceof \Ramsey\Uuid\Rfc4122\UuidV1
    ? $uuid->getDateTime()
    : null;
Defensive patterns

Strategy: type-guard

Validate before calling

if ($uuid instanceof \Ramsey\Uuid\Rfc4122\UuidV1) {
    $createdAt = $uuid->getDateTime();
} else {
    $createdAt = null; // or read the stored created_at column
}

Type guard

/** @psalm-assert-if-true \Ramsey\Uuid\Rfc4122\UuidV1 $uuid */
function isTimeBasedUuid(UuidInterface $uuid): bool
{
    return $uuid instanceof \Ramsey\Uuid\Rfc4122\UuidV1;
}

Try / catch

try {
    $dateTime = $uuid->getDateTime();
} catch (\Ramsey\Uuid\Exception\UnsupportedOperationException $e) {
    $dateTime = null; // UUID carries no timestamp
}

Prevention

When it happens

Trigger: Uuid::uuid4()->getDateTime(); any generic UuidInterface handle (e.g. a decoded value or a primary key) where getDateTime() is called but the version is 2/3/4/5/6/7.

Common situations: Codebase migrated from v1 keys to v4 keys while keeping getDateTime() calls for created-at style logic; generic code that assumes every UUID is time-based; upgrading ramsey/uuid versions where the call now throws on non-v1 instances.

Related errors


AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21). Data as JSON: /api/errors/e7c279d442f01868. Report an issue: GitHub.