diff --git a/src/lib/nodes/list.tsx b/src/lib/nodes/list.tsx index caf5630..73984af 100644 --- a/src/lib/nodes/list.tsx +++ b/src/lib/nodes/list.tsx @@ -23,6 +23,7 @@ import { DEFAULT_NODE_LS_LIMIT, getLastVM, getStatusColor, + getTimezoneAbbreviation, getVMStatusColor, jsonOption, pluralizeNodes, @@ -49,6 +50,9 @@ function VMTable({ vms }: { vms: NonNullable["data"] }) { const vmsToShow = sortedVms.slice(0, 5); const remainingVms = sortedVms.length - 5; + // Get timezone abbreviation for the header + const timezoneAbbr = getTimezoneAbbreviation(); + return ( {/* Build table as columns */} @@ -143,10 +147,16 @@ function VMTable({ vms }: { vms: NonNullable["data"] }) { borderLeft={false} borderRight={false} borderColor="gray" + gap={1} > Start/End + {timezoneAbbr && ( + + ({timezoneAbbr}) + + )} {vmsToShow.map((vm) => { const startDate = vm.start_at ? dayjs.unix(vm.start_at) : null; diff --git a/src/lib/nodes/utils.ts b/src/lib/nodes/utils.ts index 0af8da4..e532d8f 100644 --- a/src/lib/nodes/utils.ts +++ b/src/lib/nodes/utils.ts @@ -4,11 +4,49 @@ import chalk from "chalk"; import { parseDate } from "chrono-node"; import Table from "cli-table3"; import dayjs from "dayjs"; +import timezone from "dayjs/plugin/timezone.js"; +import utc from "dayjs/plugin/utc.js"; import { parseDurationArgument } from "../../helpers/duration.ts"; import { logAndQuit } from "../../helpers/errors.ts"; import { formatNullableDateRange } from "../../helpers/format-date.ts"; import { parseStartDateOrNow } from "../../helpers/units.ts"; +dayjs.extend(utc); +dayjs.extend(timezone); + +/** + * Get the timezone abbreviation for display purposes + * @param useUTC - If true, return "UTC" instead of local timezone + * @returns Timezone abbreviation (e.g., "PST", "EST", "UTC") + */ +export function getTimezoneAbbreviation(useUTC = false) { + if (useUTC) { + return "UTC"; + } + + try { + // Get the user's local timezone + const userTimezone = dayjs.tz.guess(); + + // Use Intl.DateTimeFormat to get the timezone abbreviation + // This is more reliable than dayjs.format("z") in Node.js + const dateFormatter = new Intl.DateTimeFormat("en-US", { + timeZone: userTimezone, + timeZoneName: "short", + }); + const parts = dateFormatter.formatToParts(new Date()); + const timeZonePart = parts.find((part) => part.type === "timeZoneName"); + + if (timeZonePart?.value) { + return timeZonePart.value; + } + } catch { + // Fall through to return UTC + } + + return null; +} + export function printNodeStatus(status: SFCNodes.Node["status"]): string { switch (status) { case "awaitingcapacity": @@ -103,6 +141,9 @@ export function createNodesTable( nodes: SFCNodes.Node[], limit: number = DEFAULT_NODE_LS_LIMIT, ): string { + // Get timezone abbreviation for the header + const timezoneAbbr = getTimezoneAbbreviation(); + const table = new Table({ head: [ chalk.cyan("NAME"), @@ -111,7 +152,8 @@ export function createNodesTable( chalk.cyan("CURRENT VM"), chalk.cyan("GPU"), chalk.cyan("ZONE"), - chalk.cyan("START/END"), + chalk.cyan("START/END") + + (timezoneAbbr ? ` ${chalk.white(`(${timezoneAbbr})`)}` : ""), chalk.cyan("MAX PRICE"), ], style: {