Skip to content

format() fails with "Invalid offset format" on Microsoft Edge 32-bit (Chromium) #80

@Infern1

Description

@Infern1

Description

The format() function throws Error: Invalid offset format on Microsoft Edge 32-bit (Chromium-based, version 144.0.3719.82). The same code works perfectly on Edge 64-bit.

Root Cause

Edge 32-bit has a bug in Intl.DateTimeFormat.formatToParts() where time components are silently dropped when:

  1. A non-UTC timezone is specified (e.g., timeZone: 'Europe/Berlin')
  2. AND time options use '2-digit' format

This causes tempo's offset() function (in offset.mjs) to receive incomplete date parts, resulting in an invalid Date object and ultimately NaN values in the offset calculation.

Reproduction

// This works on Edge 64-bit but FAILS on Edge 32-bit
import { format } from '@formkit/tempo';

const date = new Date('2026-01-20T08:07:40.000Z');
const result = format(date, 'YYYY-MM-DD HH:mm:ss');
// Edge 32-bit throws: Error: Invalid offset format

Debug Information

Edge 32-bit behavior with Intl.DateTimeFormat:

// Using '2-digit' - BROKEN on Edge 32-bit
const formatter = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Europe/Berlin',
  year: 'numeric', month: '2-digit', day: '2-digit',
  hour: '2-digit', minute: '2-digit', second: '2-digit',
  hourCycle: 'h23'
});
console.log(formatter.formatToParts(new Date()));

// Output on Edge 32-bit (TIME PARTS MISSING!):
[
  { "type": "month", "value": "01" },
  { "type": "literal", "value": "/" },
  { "type": "day", "value": "20" },
  { "type": "literal", "value": "/" },
  { "type": "year", "value": "2026" }
]

// Using 'numeric' - WORKS on Edge 32-bit
const formatter2 = new Intl.DateTimeFormat('en-US', {
  timeZone: 'Europe/Berlin',
  year: 'numeric', month: '2-digit', day: '2-digit',
  hour: 'numeric', minute: 'numeric', second: 'numeric'
});
console.log(formatter2.formatToParts(new Date()));

// Output on Edge 32-bit (correct):
[
  { "type": "month", "value": "01" },
  { "type": "literal", "value": "/" },
  { "type": "day", "value": "20" },
  { "type": "literal", "value": "/" },
  { "type": "year", "value": "2026" },
  { "type": "literal", "value": ", " },
  { "type": "hour", "value": "10" },
  { "type": "literal", "value": ":" },
  { "type": "minute", "value": "47" },
  { "type": "literal", "value": ":" },
  { "type": "second", "value": "30" },
  { "type": "literal", "value": " " },
  { "type": "dayPeriod", "value": "AM" }
]

How tempo fails

  1. format() calls offset(inputDate, tz, "utc") in format.mjs:30
  2. offset() uses relativeTime() which calls Intl.DateTimeFormat(...).formatToParts()
  3. On Edge 32-bit, formatToParts() returns only date parts (no hour/minute/second)
  4. relativeTime() constructs: "2026-01-20T${undefined}:${undefined}:${undefined}Z"
  5. new Date(...) returns Invalid Date
  6. getTime() returns NaN
  7. secsToOffset(NaN) produces "+NaN:NaN:NaN"
  8. fixedLengthByOffset("+NaN:NaN:NaN") throws "Invalid offset format"

Environment

  • Browser: Microsoft Edge 144.0.3719.82 (Official build) (32-bit) - Chromium-based
  • OS: Windows
  • @formkit/tempo version: 1.0.0

Suggested Fix

Option 1: Add try/catch in format() with graceful degradation

Option 2: In offset.mjs, validate that relativeTime() returns a valid Date before calculating offset

Option 3: Consider using 'numeric' instead of '2-digit' for internal Intl.DateTimeFormat options (though this may affect output formatting)

Workaround

We've implemented a wrapper that catches the error and falls back to native Date formatting:

import { format as tempoFormat } from '@formkit/tempo';

export function format(date, formatStr) {
  try {
    return tempoFormat(date, formatStr);
  } catch {
    // Native fallback for Edge 32-bit
    const pad = (n) => n.toString().padStart(2, '0');
    return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
  }
}

Related

This is a Chromium/Edge bug that should also be reported to Microsoft, but tempo could be more resilient to malformed Intl responses.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions