phalcon/cphalcon · error · Phalcon\Time\Clock\Exceptions\InvalidModifier

Invalid modifier: "{modifier}"

Error message

Invalid modifier: "{modifier}"

What it means

Phalcon\Time\Clock\FrozenClock is a frozen clock used in tests; adjust() shifts the stored DateTimeImmutable by a PHP date modifier string. On PHP >= 8.3, DateTimeImmutable::modify() throws on an unparseable modifier, and FrozenClock wraps that Throwable into Phalcon\Time\Clock\Exceptions\InvalidModifier ('Invalid modifier: "..."') with the original as $previous (phalcon/Time/Clock/FrozenClock.zep:71).

Source

Thrown at phalcon/Time/Clock/FrozenClock.zep:71

    }

    /**
     * Mutates the clock to a new value. All consumers receive the same modification
     *
     * @throws InvalidModifier
     */
    public function adjust(string modifier) -> <static>
    {
        var ex, modified, priorWarning;
        bool failed;

        let failed = false;

        if version_compare(phpversion(), "8.3", ">=") {
            try {
                let modified = this->now->modify(modifier);
            } catch Throwable, ex {
                throw new InvalidModifier(modifier, ex);
            }
        } else {
            /**
             * Pre-8.3 fallback: DateTimeImmutable::modify() emits a warning
             * instead of throwing on an invalid modifier, so the warning is
             * captured through a temporary error handler. Remove this branch
             * once the minimum supported PHP version reaches 8.3.
             */
            let priorWarning = globals_get("warning.enable");

            globals_set("warning.enable", false);
            set_error_handler(
                function (number, message, file, line) {
                    globals_set("warning.enable", true);
                },
                E_WARNING
            );

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Use a DateTime-relative format accepted by modify(): '+2 hours', '-1 day', 'next Monday', 'last day of next month'.
  2. For computed targets, construct a new FrozenClock with the absolute time instead of adjusting by a string.
  3. Catch Phalcon\Time\Clock\Exceptions\InvalidModifier when the modifier comes from external input, and fall back to a known-good modifier.

Example fix

// before
$clock->adjust('in 2 hours'); // 'in ...' is not a DateTime modifier

// after
$clock->adjust('+2 hours');
Defensive patterns

Strategy: try-catch

Try / catch

use Phalcon\Time\Clock\Exceptions\InvalidModifier;

try {
    $clock->adjust($modifier);
} catch (InvalidModifier $e) {
    // $modifier came from data; keep the clock and report
    $this->fail('Cannot adjust frozen clock: ' . $e->getMessage());
}

Prevention

When it happens

Trigger: $clock->adjust('in 2 hours'), $clock->adjust('whenever'), $clock->adjust('+1 dy') — any string DateTimeImmutable::modify() cannot parse. Works: '+2 hours', '-1 day', 'next Monday', 'first day of next month', 'midnight'.

Common situations: Test fixtures parameterized with human phrases ('in two days'); passing user/config input straight into adjust(); typos in relative formats; code that assumed strtotime() semantics (e.g. 'in 2 days' is valid for strtotime but not for DateTime::modify).

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/de986fbd93ab8984. Report an issue: GitHub.