Lattice Grid Buy a licence

demo D22

Dates, times and zones: JavaScript Data Grid Demo

The same instant in four time zones

timeZone

This grid shows the same instant rendered in four different time zones at once. It lets each reader see the clock time that makes sense for them from one stored value, so a timestamp never means the wrong moment for someone in another place.

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.css">
<script src="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.js"></script>

<div id="grid" style="height: 540px"></div>

<script>
  // A type is a map entry. `instant` exists because the shipped `datetime`
  // drops the zone: it stores the ISO string with its Z and compares on the
  // parsed epoch, so the same field means one moment to every reader.
  const instant = {
    base: 'text',
    storage: 'dictionary',
    compare: (a, b) => {
      const x = a == null ? NaN : Date.parse(String(a));
      const y = b == null ? NaN : Date.parse(String(b));
      if (Number.isNaN(x)) return Number.isNaN(y) ? 0 : 1;
      if (Number.isNaN(y)) return -1;
      return x - y;
    },
    defaults: { filter: 'text', align: 'start' },
  };

  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    toolPanel: {
      side: 'left',
      panels: ['columns', 'filters', 'views', 'quick'],
      actions: ['undo', 'redo', 'export', 'restore', 'maximise'],
      exportName: 'lattice-demo',
    },
    dataTypes: { instant },
    columns: [
      { field: 'hostname', title: 'Hostname', layout: { width: 260, pin: 'start' } },
      { field: 'lastSeen', id: 'raw', title: 'Stored', type: 'instant', layout: { width: 210 } },
      { field: 'lastSeen', id: 'utc', title: 'UTC', type: 'instant', layout: { width: 160 }, format: { type: 'date', timeZone: 'UTC', pattern: 'yyyy-MM-dd HH:mm' } },
      { field: 'lastSeen', id: 'lon', title: 'Europe/London', type: 'instant', layout: { width: 170 }, format: { type: 'date', timeZone: 'Europe/London', pattern: 'yyyy-MM-dd HH:mm' } },
      { field: 'lastSeen', id: 'nyc', title: 'America/New_York', type: 'instant', layout: { width: 180 }, format: { type: 'date', timeZone: 'America/New_York', pattern: 'yyyy-MM-dd HH:mm' } },
      { field: 'lastSeen', id: 'tyo', title: 'Asia/Tokyo', type: 'instant', layout: { width: 160 }, format: { type: 'date', timeZone: 'Asia/Tokyo', pattern: 'yyyy-MM-dd HH:mm' } },
      {
        field: 'lastSeen', id: 'rel', title: 'Relative', type: 'instant', layout: { width: 150 },
        // Falls back to an absolute date once the gap passes the threshold,
        // which is what stops a list of old rows reading "412 days ago".
        format: { type: 'date', relative: { threshold: 7 } },
      },
      {
        field: 'commissioned', title: 'Commissioned', type: 'dateString', layout: { width: 160 },
        // A day, not an instant. It has no zone to convert and should not
        // get one: 4 March is 4 March in Tokyo too.
        format: { type: 'date', dateStyle: 'medium' },
      },
    ],
    rows,  // nodes, each with a lastSeen instant
  });
</script>

Rendering the same instant correctly across time zones

A date value stored in a row is a single instant, but a reader in London and a reader in Singapore need to see two different clock times for it. Lattice Grid handles this with the grid’s timeZone setting: name an IANA zone and every date and timestamp in the grid reads in it, independent of the browser’s local zone. A timestamp column can also pin its own display zone with typeOptions.timeZone, so one grid can show the same instant in several zones side by side. This matters for a JavaScript data grid used by a distributed team, an operations dashboard tracking events across regions, or an audit log where the recorded instant must read out consistently regardless of viewer. A timestamp column with no zone of its own takes the grid’s zone, and a grid with none takes the viewer’s local zone.

Formatting runs through Intl.DateTimeFormat, so zone names follow the IANA database rather than fixed UTC offsets, keeping daylight saving transitions correct without the grid tracking them itself. The formatter for a given zone and locale pairing is built once per column and reused across every row, so scrolling a long list of timestamped rows does not repeat that setup cost per cell. Sorting and filtering compare the underlying instant, not the formatted string, so a timestamp column sorts correctly even when the displayed hour rolls past midnight differently between zones.

How do you display a date column in a fixed time zone in a data grid?

Set timeZone on the grid to an IANA zone name, such as 'Europe/London' or 'Asia/Singapore', to show every date in that zone. To pin one timestamp column to a different zone, set typeOptions: { timeZone: 'Asia/Tokyo' } on it. Lattice Grid formats every value against the named zone using Intl.DateTimeFormat, independent of the viewer’s local zone, while sorting and filtering continue to operate on the underlying instant rather than the formatted display string.