Skip to main content
Glama
pshempel

MCP Time Server Node

by pshempel
parseTimeInput.ts5.2 kB
import { parseISO, isValid } from 'date-fns'; import { toDate } from 'date-fns-tz'; import { DateParsingError } from '../adapters/mcp-sdk/errors'; import { debug } from './debug'; /** * Result of parsing a time input */ export interface ParseResult { /** The parsed Date object */ date: Date; /** The detected or specified timezone */ detectedTimezone: string; /** Whether the input had explicit timezone information */ hasExplicitTimezone: boolean; /** Offset in minutes if present in input (e.g., +05:00 = 300) */ offset?: number; } /** * Checks if a time string contains timezone information */ function hasTimezoneInfo(input: string): boolean { return input.includes('Z') || /[+-]\d{2}:\d{2}$/.test(input); } /** * Extracts timezone offset from a string * @returns Offset in minutes, or null if no offset found */ function extractOffset(input: string): number | null { const match = input.match(/([+-])(\d{2}):(\d{2})$/); if (!match) return null; const sign = match[1] === '+' ? 1 : -1; const hours = parseInt(match[2], 10); const minutes = parseInt(match[3], 10); return sign * (hours * 60 + minutes); } /** * Parse Unix timestamp string */ function parseUnixTimestamp(timeStr: string): ParseResult | null { if (!/^\d+$/.test(timeStr)) { return null; } const timestamp = parseInt(timeStr, 10); if (isNaN(timestamp)) { debug.error('Invalid Unix timestamp: %s', timeStr); throw new DateParsingError(`Invalid Unix timestamp: ${timeStr}`, { input: timeStr }); } // Heuristic: > 10 digits likely milliseconds (after year 2286) const multiplier = timeStr.length > 10 ? 1 : 1000; const date = new Date(timestamp * multiplier); debug.parsing('Parsed Unix timestamp:', { timestamp, multiplier, result: date.toISOString(), }); return { date, detectedTimezone: 'UTC', hasExplicitTimezone: true, }; } /** * Parse ISO string with timezone information */ function parseISOWithTimezone(timeStr: string): ParseResult | null { if (!hasTimezoneInfo(timeStr)) { return null; } const date = parseISO(timeStr); if (!isValid(date)) { debug.error('Invalid ISO date string: %s', timeStr); throw new DateParsingError(`Invalid ISO date string: ${timeStr}`, { input: timeStr }); } const offset = extractOffset(timeStr); debug.parsing('Parsed ISO with timezone:', { input: timeStr, hasZ: timeStr.includes('Z'), offset, result: date.toISOString(), }); return { date, detectedTimezone: timeStr.includes('Z') ? 'UTC' : 'offset', hasExplicitTimezone: true, ...(offset !== null && { offset }), }; } /** * Parse as local time in specified timezone */ function parseLocalTime(timeStr: string, timezone?: string): ParseResult { // Apply project convention: "" = UTC, undefined = local const effectiveTimezone = timezone === '' ? 'UTC' : timezone; let date: Date; try { if (effectiveTimezone) { // Parse as local time in specific timezone date = toDate(timeStr, { timeZone: effectiveTimezone }); } else { // Parse as system local time date = parseISO(timeStr); } } catch (error) { debug.error( 'Failed to parse date: %s in timezone: %s, error: %s', timeStr, timezone, String(error) ); throw new DateParsingError(`Failed to parse date: ${timeStr}`, { input: timeStr, timezone, error: String(error), }); } if (!isValid(date)) { debug.error('Invalid date format: %s in timezone: %s', timeStr, timezone); throw new DateParsingError(`Invalid date format: ${timeStr}`, { input: timeStr, timezone }); } debug.parsing('Parsed local time:', { input: timeStr, timezone: effectiveTimezone ?? 'local', result: date.toISOString(), }); return { date, detectedTimezone: effectiveTimezone ?? 'local', hasExplicitTimezone: false, }; } /** * Unified time input parser that handles: * - Unix timestamps (seconds and milliseconds) * - ISO 8601 strings with/without timezone * - Date-only strings * - Respects project timezone conventions: * - undefined = system local * - "" = UTC * - string = specific IANA timezone * * @param input - Time string, Unix timestamp, or number * @param timezone - Optional timezone (see conventions above) * @returns ParseResult with date and metadata * @throws TimeServerErrorCodes.INVALID_DATE_FORMAT for invalid input */ export function parseTimeInput( input: string | number | undefined | null, timezone?: string ): ParseResult { debug.parsing('parseTimeInput called with:', { input, timezone }); // Handle undefined/null/empty if (input == null || input === '') { debug.error('Input cannot be null, undefined, or empty: %O', input); throw new DateParsingError('Input cannot be null, undefined, or empty', { input }); } // Normalize to string const timeStr = String(input); // Try parsing strategies in order const unixResult = parseUnixTimestamp(timeStr); if (unixResult) return unixResult; const isoResult = parseISOWithTimezone(timeStr); if (isoResult) return isoResult; return parseLocalTime(timeStr, timezone); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pshempel/mcp-time-server-node'

If you have feedback or need assistance with the MCP directory API, please join our Discord server