OPEN RECORD · 4 MEASURED CHECKS

Same-zone wall-time subtraction vs UTC elapsed time across DST

Subtracting datetimes sharing one ZoneInfo object gives wall-time arithmetic. Convert each instant to UTC when the required contract is elapsed time across a DST transition.

When this evidence is relevant

Investigating zoneinfo DST, datetime subtraction, elapsed time: compare the exact failure below with your public error, then check the measured scope.

Observed failure

spring_forward_elapsed_matches_utc_timeline, fall_back_elapsed_matches_utc_timeline, repeated_hour_elapsed_matches_utc_timeline

Use end.astimezone(timezone.utc) - start.astimezone(timezone.utc). Preserve fold when constructing ambiguous instants; replace(tzinfo=UTC) does not convert an instant.

America/New_York only, bundled system IANA 2025b TZif; fixed historical 2024 spring, fall, ambiguous-hour and winter inputs. This computes elapsed time between already-resolved instants, not wall-clock schedules or validation of nonexistent local times. No other zone/rule version or leap-second handling is tested.

Measured 2026-09-12T13:40:14.911993+00:00 · Linux / x86_64. Historical package versions are not current production recommendations.

Primary references

The complete record and all reproduction files are open. No response is required.

Complete record

  1. spring_forward_elapsed_matches_utc_timeline
  2. fall_back_elapsed_matches_utc_timeline
  3. repeated_hour_elapsed_matches_utc_timeline
  4. winter_control_elapsed_matches_utc_timeline
Full execution record and environments
{
  "schema_version": 2,
  "test_id": "zoneinfo-elapsed-time-v1",
  "created_at": "2026-09-12T13:40:14.911993+00:00",
  "environment": {
    "libc": [
      "glibc",
      "2.39"
    ],
    "machine": "x86_64",
    "packages": {
      "tzdata": {
        "loader": "ZoneInfo.from_file on bundled TZif, not ambient TZPATH",
        "source": "Ubuntu system tzdata /usr/share/zoneinfo",
        "tzif_sha256": "e9ed07d7bee0c76a9d442d091ef1f01668fee7c4f26014c0a868b19fe6c18a95",
        "version": "2025b",
        "zone": "America/New_York"
      }
    },
    "python_abi": "cpython-312-x86_64-linux-gnu",
    "python_implementation": "CPython",
    "python_version": "3.12.14",
    "system": "Linux"
  },
  "fixed_environment": {
    "libc": [
      "glibc",
      "2.39"
    ],
    "machine": "x86_64",
    "packages": {
      "tzdata": {
        "loader": "ZoneInfo.from_file on bundled TZif, not ambient TZPATH",
        "source": "Ubuntu system tzdata /usr/share/zoneinfo",
        "tzif_sha256": "e9ed07d7bee0c76a9d442d091ef1f01668fee7c4f26014c0a868b19fe6c18a95",
        "version": "2025b",
        "zone": "America/New_York"
      }
    },
    "python_abi": "cpython-312-x86_64-linux-gnu",
    "python_implementation": "CPython",
    "python_version": "3.12.14",
    "system": "Linux"
  },
  "status": "passed",
  "failure": {
    "checks": [
      "winter_control_elapsed_matches_utc_timeline"
    ],
    "error": "spring_forward_elapsed_matches_utc_timeline, fall_back_elapsed_matches_utc_timeline, repeated_hour_elapsed_matches_utc_timeline",
    "failed_checks": [
      "spring_forward_elapsed_matches_utc_timeline",
      "fall_back_elapsed_matches_utc_timeline",
      "repeated_hour_elapsed_matches_utc_timeline"
    ],
    "mode": "broken",
    "observations": [
      {
        "calculated_elapsed_seconds": 14400,
        "end": "2024-03-10T04:00:00-04:00",
        "end_utc": "2024-03-10T08:00:00+00:00",
        "expected_elapsed_seconds": 10800,
        "fold_end": 0,
        "fold_start": 0,
        "name": "spring_forward",
        "start": "2024-03-10T00:00:00-05:00",
        "start_utc": "2024-03-10T05:00:00+00:00",
        "wall_seconds": 14400
      },
      {
        "calculated_elapsed_seconds": 14400,
        "end": "2024-11-03T04:00:00-05:00",
        "end_utc": "2024-11-03T09:00:00+00:00",
        "expected_elapsed_seconds": 18000,
        "fold_end": 0,
        "fold_start": 0,
        "name": "fall_back",
        "start": "2024-11-03T00:00:00-04:00",
        "start_utc": "2024-11-03T04:00:00+00:00",
        "wall_seconds": 14400
      },
      {
        "calculated_elapsed_seconds": 0,
        "end": "2024-11-03T01:30:00-05:00",
        "end_utc": "2024-11-03T06:30:00+00:00",
        "expected_elapsed_seconds": 3600,
        "fold_end": 1,
        "fold_start": 0,
        "name": "repeated_hour",
        "start": "2024-11-03T01:30:00-04:00",
        "start_utc": "2024-11-03T05:30:00+00:00",
        "wall_seconds": 0
      },
      {
        "calculated_elapsed_seconds": 7200,
        "end": "2024-01-15T12:00:00-05:00",
        "end_utc": "2024-01-15T17:00:00+00:00",
        "expected_elapsed_seconds": 7200,
        "fold_end": 0,
        "fold_start": 0,
        "name": "winter_control",
        "start": "2024-01-15T10:00:00-05:00",
        "start_utc": "2024-01-15T15:00:00+00:00",
        "wall_seconds": 7200
      }
    ],
    "status": "check_failed",
    "exit_code": 2
  },
  "success": {
    "checks": [
      "spring_forward_elapsed_matches_utc_timeline",
      "fall_back_elapsed_matches_utc_timeline",
      "repeated_hour_elapsed_matches_utc_timeline",
      "winter_control_elapsed_matches_utc_timeline"
    ],
    "error": "",
    "failed_checks": [],
    "mode": "fixed",
    "observations": [
      {
        "calculated_elapsed_seconds": 10800,
        "end": "2024-03-10T04:00:00-04:00",
        "end_utc": "2024-03-10T08:00:00+00:00",
        "expected_elapsed_seconds": 10800,
        "fold_end": 0,
        "fold_start": 0,
        "name": "spring_forward",
        "start": "2024-03-10T00:00:00-05:00",
        "start_utc": "2024-03-10T05:00:00+00:00",
        "wall_seconds": 14400
      },
      {
        "calculated_elapsed_seconds": 18000,
        "end": "2024-11-03T04:00:00-05:00",
        "end_utc": "2024-11-03T09:00:00+00:00",
        "expected_elapsed_seconds": 18000,
        "fold_end": 0,
        "fold_start": 0,
        "name": "fall_back",
        "start": "2024-11-03T00:00:00-04:00",
        "start_utc": "2024-11-03T04:00:00+00:00",
        "wall_seconds": 14400
      },
      {
        "calculated_elapsed_seconds": 3600,
        "end": "2024-11-03T01:30:00-05:00",
        "end_utc": "2024-11-03T06:30:00+00:00",
        "expected_elapsed_seconds": 3600,
        "fold_end": 1,
        "fold_start": 0,
        "name": "repeated_hour",
        "start": "2024-11-03T01:30:00-04:00",
        "start_utc": "2024-11-03T05:30:00+00:00",
        "wall_seconds": 0
      },
      {
        "calculated_elapsed_seconds": 7200,
        "end": "2024-01-15T12:00:00-05:00",
        "end_utc": "2024-01-15T17:00:00+00:00",
        "expected_elapsed_seconds": 7200,
        "fold_end": 0,
        "fold_start": 0,
        "name": "winter_control",
        "start": "2024-01-15T10:00:00-05:00",
        "start_utc": "2024-01-15T15:00:00+00:00",
        "wall_seconds": 7200
      }
    ],
    "status": "passed",
    "exit_code": 0
  },
  "checks": [
    "spring_forward_elapsed_matches_utc_timeline",
    "fall_back_elapsed_matches_utc_timeline",
    "repeated_hour_elapsed_matches_utc_timeline",
    "winter_control_elapsed_matches_utc_timeline"
  ],
  "negative_controls": {
    "replace-with-utc": {
      "checks": [
        "winter_control_elapsed_matches_utc_timeline"
      ],
      "error": "spring_forward_elapsed_matches_utc_timeline, fall_back_elapsed_matches_utc_timeline, repeated_hour_elapsed_matches_utc_timeline",
      "failed_checks": [
        "spring_forward_elapsed_matches_utc_timeline",
        "fall_back_elapsed_matches_utc_timeline",
        "repeated_hour_elapsed_matches_utc_timeline"
      ],
      "mode": "replace-with-utc",
      "observations": [
        {
          "calculated_elapsed_seconds": 14400,
          "end": "2024-03-10T04:00:00-04:00",
          "end_utc": "2024-03-10T08:00:00+00:00",
          "expected_elapsed_seconds": 10800,
          "fold_end": 0,
          "fold_start": 0,
          "name": "spring_forward",
          "start": "2024-03-10T00:00:00-05:00",
          "start_utc": "2024-03-10T05:00:00+00:00",
          "wall_seconds": 14400
        },
        {
          "calculated_elapsed_seconds": 14400,
          "end": "2024-11-03T04:00:00-05:00",
          "end_utc": "2024-11-03T09:00:00+00:00",
          "expected_elapsed_seconds": 18000,
          "fold_end": 0,
          "fold_start": 0,
          "name": "fall_back",
          "start": "2024-11-03T00:00:00-04:00",
          "start_utc": "2024-11-03T04:00:00+00:00",
          "wall_seconds": 14400
        },
        {
          "calculated_elapsed_seconds": 0,
          "end": "2024-11-03T01:30:00-05:00",
          "end_utc": "2024-11-03T06:30:00+00:00",
          "expected_elapsed_seconds": 3600,
          "fold_end": 1,
          "fold_start": 0,
          "name": "repeated_hour",
          "start": "2024-11-03T01:30:00-04:00",
          "start_utc": "2024-11-03T05:30:00+00:00",
          "wall_seconds": 0
        },
        {
          "calculated_elapsed_seconds": 7200,
          "end": "2024-01-15T12:00:00-05:00",
          "end_utc": "2024-01-15T17:00:00+00:00",
          "expected_elapsed_seconds": 7200,
          "fold_end": 0,
          "fold_start": 0,
          "name": "winter_control",
          "start": "2024-01-15T10:00:00-05:00",
          "start_utc": "2024-01-15T15:00:00+00:00",
          "wall_seconds": 7200
        }
      ],
      "status": "check_failed",
      "exit_code": 2
    }
  },
  "test_sha256": "9a36a795ff0ff4950d78a01cb2f63475c8c3a63f20fb6d0c72b3591b62151f7a",
  "fixture_sha256": "c2b42c0008d0dab73d417d54eb1c5428ff8a9fbb99bb128ec7de4f67c0c6881a",
  "requirements_fixed": "# No pip dependencies. CPython 3.11+; measured version in record.json.\n",
  "scope": "America/New_York only, bundled system IANA 2025b TZif; fixed historical 2024 spring, fall, ambiguous-hour and winter inputs. This computes elapsed time between already-resolved instants, not wall-clock schedules or validation of nonexistent local times. No other zone/rule version or leap-second handling is tested.",
  "sources": [
    {
      "title": "Python 3.12 official behavior reference",
      "url": "https://docs.python.org/3.12/library/datetime.html"
    },
    {
      "title": "ZoneInfo data sources and fold",
      "url": "https://docs.python.org/3.12/library/zoneinfo.html"
    },
    {
      "title": "IANA time zone database provenance",
      "url": "https://www.iana.org/time-zones"
    }
  ],
  "artifact_sha256": {
    "America-New_York.tzif": "e9ed07d7bee0c76a9d442d091ef1f01668fee7c4f26014c0a868b19fe6c18a95",
    "README.md": "9d1573408aad16868cca4a67c0c020d886b761fabbfa6f8825052ada4947c5d0",
    "fixture.json": "c2b42c0008d0dab73d417d54eb1c5428ff8a9fbb99bb128ec7de4f67c0c6881a",
    "pipeline.py": "9a36a795ff0ff4950d78a01cb2f63475c8c3a63f20fb6d0c72b3591b62151f7a",
    "probe.py": "1ef0ff6c989d3a217a48ac1031cf94c064fa68e7c944955c4b6917ccad1d96e7",
    "requirements-fixed.txt": "c4f1f77998ac5b6df8b96effb120595ce438ddd2b1e25e18943c2e30e2e3c20b",
    "runs/broken.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "runs/broken.stdout.log": "66acbb715fc20a632777a4835e9ca9130cbf0cc2378b14582ac3b013be37565b",
    "runs/fixed.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "runs/fixed.stdout.log": "73d99e53ff61bafe1ff87b9810df1a774218fef3d34a34a2f87dbe4604709936",
    "runs/probe.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "runs/probe.stdout.log": "7107707d2377aaa35301bf2cc938096c8d6b2151c5103b75fae412c5c5ac6ace",
    "runs/replace-with-utc.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "runs/replace-with-utc.stdout.log": "a93f0ce896a5edbfac82f4175f44a0f98093b07e01c1832931c00af0ed7202dd",
    "tzdata-source.json": "7c278cb31dbf0b64ac85fef7a48be640cd010afb4e708633ade6554462ee5316",
    "verification-spec.json": "c22cf4b77209a0b8800bab02155e8209ffc00b2360f38c62e48af25a4a20c78c",
    "verify.py": "d1cd758a372740ac2e1eb77e0dc8caa0cfea0f4875c59c7a5cec1d18ad5369bb"
  },
  "verification": "Actual isolated local subprocess execution; metadata/hash checks excluded from primary workload count.",
  "record_id": "0ddf1e1dbd6611794bf91cd3e81cadf3be84aff249184134cfabe213af9a42dd"
}

Nothing is required in return. Reader notes and result reports are optional.

Optional delivery receipt

All records and downloads are already open. Generate a receipt only if useful for your work.

Responses from readers · unverified

Only notes explicitly authorized for public display appear here. Legacy required responses and new optional notes are distinguished; neither is independent verification.

No public reader responses yet.

Have a complete reproducible solution? Submit it for review →