Files
supabase/apps/studio/lib/migration-utils.ts
Jordi Enric d2017189e1 fix(migrations): parse migration version timestamps as UTC SU-353303 (#44655)
## Problem

The "INSERTED AT (UTC)" column in the Database Migrations UI showed
local time instead of UTC. For a user in Buenos Aires (UTC-3), a
migration timestamped at UTC 08:33:31 would show 05:33:31 in the table.
The tooltip's relative time also showed "in 3 hours" (future) for a
migration that had already run, because the UTC offset was applied in
the wrong direction.

Root cause: `parseMigrationVersion` parsed the version string (format
`YYYYMMDDHHmmss`, which the Supabase CLI generates in UTC) using
`dayjs()` without the UTC flag, so dayjs interpreted the digits as local
time.

## Fix

- Changed `parseMigrationVersion` to use `dayjs.utc()` so the version
string is correctly interpreted as a UTC timestamp.
- Updated the label formatter in `Migrations.tsx` to use
`.utc().format()`, so the displayed time matches the column header
("INSERTED AT (UTC)").
- Added the dayjs UTC plugin setup to the test file and added a
regression test that asserts `toISOString()` returns the correct UTC
time.

## Before
<img width="1102" height="658" alt="CleanShot 2026-04-08 at 12 41 18@2x"
src="https://github.com/user-attachments/assets/5eccdfb1-757c-4794-b24f-6a2c71f483dc"
/>

## After
<img width="1126" height="612" alt="CleanShot 2026-04-08 at 12 42 03@2x"
src="https://github.com/user-attachments/assets/6f3da69f-ace5-4758-b025-b49d8b325034"
/>


## How to test

- Set your browser/OS timezone to something other than UTC (e.g.
America/Buenos_Aires, UTC-3).
- Open the Database Migrations page for a project that has migrations.
- The "INSERTED AT (UTC)" column should show the UTC time matching the
version number digits (e.g. version `20260406083331` should show `06 Apr
2026, 08:33:31`).
- Hover over the timestamp. The tooltip should show the same value for
"UTC", a correctly offset value for your local timezone, and a relative
time that reflects the past (e.g. "3 hours ago", not "in 3 hours").

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Migration timestamps now parsed and displayed in UTC for consistent,
accurate labels; unparsable versions show "Unknown".

* **New Features**
* Improved migration version labeling for clearer, uniformly formatted
date/time shown in the UI.

* **Tests**
* Expanded tests for migration parsing and label formatting; test setup
updated for UTC handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 16:54:31 +02:00

39 lines
1.4 KiB
TypeScript

import dayjs, { Dayjs } from 'dayjs'
/**
* Safely parses a migration version string as a date.
* Migration versions are typically in the format YYYYMMDDHHmmss (e.g., "20231128095400").
* However, some projects may have custom version formats (e.g., "001", "002") that cannot be parsed as dates.
*
* @param version - Migration version string
* @returns Dayjs object (UTC mode) if the version is a valid datetime, undefined otherwise
*
* @example
* const parsed = parseMigrationVersion('20231128095400')
* if (parsed) {
* console.log(parsed.fromNow()) // "2 hours ago"
* console.log(parsed.format('DD MMM YYYY')) // "28 Nov 2023"
* }
*
* @example
* const invalid = parseMigrationVersion('001') // returns undefined
*/
export function parseMigrationVersion(version: string | null | undefined): Dayjs | undefined {
if (!version) return undefined
// Must contain only digits
if (!/^\d{14}$/.test(version)) return undefined
const parsed = dayjs.utc(version, 'YYYYMMDDHHmmss', true)
return parsed.isValid() ? parsed : undefined
}
/**
* Formats a migration version string as a human-readable UTC date label.
* Returns 'Unknown' if the version cannot be parsed.
*/
export function formatMigrationVersionLabel(version: string | null | undefined): string {
const parsed = parseMigrationVersion(version)
return parsed ? parsed.format('DD MMM YYYY, HH:mm:ss') : 'Unknown'
}