diff --git a/src/helpers/format-date.ts b/src/helpers/format-date.ts index bb20506..3d7cce2 100644 --- a/src/helpers/format-date.ts +++ b/src/helpers/format-date.ts @@ -104,8 +104,32 @@ export const formatNullableDateRange = ( return startEnd; }; -export const dateSameAcrossTimezones = (date: Date): boolean => { - const endDayUserTZ = dayjs(date); - const endDayUTC = dayjs(date).utc(true); - return endDayUserTZ.isSame(endDayUTC); +/** + * Formats a dayjs date in UTC timezone. + * This is needed because formatDate() uses toLocaleTimeString() which always + * formats in local timezone. This function formats directly in UTC using dayjs. + * + * Only shows the date if UTC falls on a different calendar day than local + * (e.g., "Today, 8pm PST Feb 6, 4am UTC"). If same day, just shows time + * (e.g., "Today, 10am PST 6pm UTC"). + */ +export const formatDateAsUTC = (date: Dayjs): string => { + const utcDate = date.utc(); + const localDate = date; + + // Format time: "4pm" or "4:30pm" + const timeStr = + utcDate.minute() === 0 ? utcDate.format("ha") : utcDate.format("h:mma"); + + // Only show date if UTC and local fall on different calendar days + const sameCalendarDay = + utcDate.date() === localDate.date() && + utcDate.month() === localDate.month() && + utcDate.year() === localDate.year(); + + if (sameCalendarDay) { + return `${timeStr} UTC`; + } + + return `${utcDate.format("MMM D")}, ${timeStr} UTC`; }; diff --git a/src/helpers/units.ts b/src/helpers/units.ts index 9d36687..4213981 100644 --- a/src/helpers/units.ts +++ b/src/helpers/units.ts @@ -5,7 +5,7 @@ import dayjs from "dayjs"; import timezone from "dayjs/plugin/timezone"; import utc from "dayjs/plugin/utc"; import type { Nullable } from "../types/empty.ts"; -import { dateSameAcrossTimezones, formatDate } from "./format-date.ts"; +import { formatDate, formatDateAsUTC } from "./format-date.ts"; dayjs.extend(utc); dayjs.extend(timezone); @@ -158,11 +158,7 @@ export async function selectTime( const suggestedHigherUserTZ = `${formatDate(suggestedHigher.toDate(), { forceIncludeTime: true, })} ${dayjs(suggestedHigher).format("z")}`; - const suggestedHigherUTC = `${formatDate(suggestedHigher.utc(true).toDate(), { - today: suggestedHigher.toDate(), - showToday: dateSameAcrossTimezones(suggestedHigher.toDate()), - forceIncludeTime: true, - })} UTC`; + const suggestedHigherUTC = formatDateAsUTC(suggestedHigher); // If the lower boundary is in the past, suggest "NOW" if (suggestedLower.isBefore(dayjs(new Date()))) { @@ -192,11 +188,7 @@ export async function selectTime( const suggestedLowerUserTZ = `${formatDate(suggestedLower.toDate(), { forceIncludeTime: true, })} ${dayjs(suggestedLower).format("z")}`; - const suggestedLowerUTC = `${formatDate(suggestedLower.utc(true).toDate(), { - today: suggestedLower.toDate(), - showToday: dateSameAcrossTimezones(suggestedLower.toDate()), - forceIncludeTime: true, - })} UTC`; + const suggestedLowerUTC = formatDateAsUTC(suggestedLower); const maxLength = Math.max( suggestedLowerUserTZ.length,