Lattice Grid Buy a licence

demo D22

Dates, times and zones

The same instant in four time zones

timeZone

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.0/lattice-grid.min.css">

<div id="grid"></div>

<script type="module">
  import React from 'https://esm.sh/react@18';
  import { createRoot } from 'https://esm.sh/react-dom@18/client';
  import { createGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.0/lattice-grid.esm.min.js';
  import createLatticeGrid from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.27.0/modules/react.esm.min.js';

  const LatticeGrid = createLatticeGrid({ React, createGrid });

  // An instant type that keeps the zone: it stores the ISO string with its Z and
  // compares on the parsed moment, so one field reads as the same instant for
  // every viewer, shown in whichever zone each column names.
  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 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' },
    },
  ];

  const rows = [/* nodes, each with a lastSeen instant */];

  function App() {
    return (
      <LatticeGrid
        rowKey="id"
        toolPanel={{ side: 'left', panels: ['columns', 'filters', 'views', 'quick'],
          actions: ['undo', 'redo', 'export', 'restore', 'maximise'], exportName: 'lattice-demo' }}
        dataTypes={{ instant }}
        columns={columns}
        rows={rows}
        style={{ height: '540px' }}
      />
    );
  }

  createRoot(document.getElementById('grid')).render(<App />);
</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 at the column level with the timeZone option: set it on a date or datetime column and every cell formats its value against the named zone, independent of the browser’s local zone. 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. Columns without timeZone set fall back to the viewer’s local zone, so one grid can mix a local-time column with fixed-zone columns side by side, each formatting independently from the same underlying instant.

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 timeZone 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 column definition to an IANA zone name, such as 'Europe/London' or 'Asia/Singapore'. Lattice Grid formats every value in that column 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.