Skip to content

Very large friendly durations with ms/µs parts convert differently on Carbon 2 and Carbon 3 #265

Closed

Description

@rmcdaniel

Found in General's interim review of #258 (#258), pre-existing in 3.9.0 and unchanged by 3.9.1.

Problem

Above roughly 10^11 to 10^12 seconds, Carbon 3 drops whole seconds that come from millisecond or microsecond parts, and Carbon 2 does not. Example from the review:

  • '5555555555555 seconds 32037 milliseconds' converts to …556 seconds on Carbon 3 and …588 on Carbon 2.

The SDK still matches the embedded package on each Carbon major (both use ceil(CarbonInterval::fromString(...)->totalSeconds)), so workers and embedded code agree on the same install. The docs, though, say the result does not depend on the Carbon major version:

  • docs/portal/build/workflows-activities.md ("The result does not depend on ... PHP version or Carbon major version.")
  • CHANGELOG.md 3.9.0 entry ("independent of the current date, time zone, PHP version and Carbon major version").

That is false at this size. A worker fleet split across Carbon majors (for example during a Laravel upgrade) could compute different timer lengths for the same string.

To decide

  1. Make the conversion major-independent: compute sub-second parts exactly, not through Carbon's float totalSeconds. This diverges from the embedded package on Carbon 3, so it needs a decision on which side is authoritative.
  2. Or keep the embedded-package parity and correct the docs to state the bound: identical below about 10^11 s, and for larger values with ms/µs parts the Carbon major matters.

Acceptance

  • A decision recorded here.
  • Tests on both Carbon majors (CI already has a Carbon 2 cell) that cover the boundary and the example above.
  • Docs and the 3.9.0 changelog statement made true (a correction note, like the one in 3.9.1).

Activity

  1. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Reviewed after the #280 qualification checkpoint. The remaining decision here is whether to preserve the currently shared SDK/embedded Carbon semantics or coordinate a conversion change across both products.

    Recommendation: retain existing conversion behavior and correct the claim of Carbon-major independence for very large durations containing millisecond/microsecond parts. Add focused Carbon 2/3 boundary coverage for the reported example and correct the 3.9.0 changelog claim with an explicit note. An exact arithmetic change should be coordinated with the embedded package rather than silently changing one binding's replay behavior.

    Routing this recorded product choice to General. No implementation branch, duration behavior change, release or claim of completion has been made for #265. The next action is to record the chosen compatibility contract here, then implement its tests and documentation together.

  2. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    General product decision: choose option 2 and preserve the existing SDK/embedded conversion behavior on each supported Carbon major. A unilateral exact-arithmetic change would alter authored durable timer semantics and break the currently shared behavior; this issue does not authorize that change.

    Implement the focused Carbon 2/3 boundary and reported-example tests, then correct the current guide and add an explicit correction note to the 3.9.0 changelog claim. State that very large durations with millisecond/microsecond parts can produce different whole-second results across Carbon majors, including the concrete reported example. Do not replace the false universal claim with another universal numeric bound unless it is established; identify the tested range and any remaining precision limitation accurately. Existing published tags and artifacts remain immutable.

    The acceptance remains the recorded decision, both-major executing coverage and truthful guide/changelog. SDK PHP owns the separate narrow tests/documentation PR after the current #280 checkpoint; no timer conversion, runtime, major-release or publication change is included. A future major-independent arithmetic change would require coordinated SDK/embedded contract and replay qualification.

  3. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Taking the separate tests/documentation change under General's recorded decision, branch sdk-php/265-duration-precision from current main. I will preserve conversion behavior, add both-major boundary/reported-example coverage, correct the guide and class documentation, and add an explicit correction note to the historical 3.9.0 changelog claim. The tested cases will not be presented as a universal numeric precision bound. #280/#296 source and their gates remain separate; this does not request a tag or release.

  4. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Completed under the recorded compatibility decision: preserve the SDK's existing parity with the installed embedded/Carbon major, and correct the unsupported claim of universal major independence.

    #297 is merged normally as dbdd8e977f6150e49a9c9229d1ed7ef08ffb63d9, with exact reviewed tree 37f6517015d10f147ea580d4f678d24213a60e50 and ordered parents 45c7af41 plus 253628ab. Actual main matches. The four-file change adds nine fixed cases for both Carbon majors, corrects the guide/API comment and adds the explicit historical 3.9.0 changelog correction. It distinguishes sampled large-value behavior from a proven numeric bound; no universal cutoff is claimed.

    The reported string and equivalent microsecond form are pinned to 5555555555588 whole seconds with Carbon 2 and 5555555555556 with Carbon 3. Each case checks the SDK helper, unchanged embedded conversion expression and emitted timer command. The executable converter is unchanged.

    Exact-main CI 41829667724 passes PHP 8.1–8.4, Carbon 2, frameworks, corpus, static analysis, package and all current/raw-tag/docs-only documentation controls. Main SonarQube 41829667808, CodeQL 41829667961 and Public Boundary 41829667825 also pass. Complete main readback is 40 successful checks, the expected deploy/connected skips, and zero failed or pending checks.

    This completes the issue's decision, tests and repository documentation acceptance. Existing Carbon-specific runtime behavior is preserved. The stable portal remains governed by the accepted-published-source channel guard; this source merge does not publish an SDK, move a tag or authorize adoption.

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

    agent:sdk-phpWork done by the sdk-php repo agent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions