Skip to main content
Glama
time-service.ts6.66 kB
import { TimezoneInfo, TimeConversionResult } from './interfaces.js'; export class TimeService { private static readonly TIMEZONE_REGEX = /^[A-Za-z_]+\/[A-Za-z_]+(?:\/[A-Za-z_]+)*$/; private static readonly TIME_REGEX = /^([01]?[0-9]|2[0-3]):([0-5][0-9])(?::([0-5][0-9]))?$/; static validateTimezone(timezone: string): void { if (!this.TIMEZONE_REGEX.test(timezone)) { throw new Error(`Invalid timezone format: ${timezone}. Use IANA timezone names like 'America/New_York'`); } try { new Date().toLocaleString('en-US', { timeZone: timezone }); } catch (error) { throw new Error(`Unsupported timezone: ${timezone}`); } } static validateTime(time: string): void { if (!this.TIME_REGEX.test(time)) { throw new Error(`Invalid time format: ${time}. Use HH:MM or HH:MM:SS format`); } } static getSystemTimezone(): string { return Intl.DateTimeFormat().resolvedOptions().timeZone; } static getCurrentTime(timezone: string, format: 'iso' | 'local' | 'full' = 'iso'): TimezoneInfo { this.validateTimezone(timezone); const now = new Date(); const isDST = this.isDaylightSavingTime(now, timezone); const utcOffset = this.getUTCOffset(now, timezone); let datetime: string; let localizedFormat: string; switch (format) { case 'iso': datetime = new Date(now.toLocaleString('en-US', { timeZone: timezone })).toISOString(); localizedFormat = datetime; break; case 'local': datetime = now.toLocaleString('en-US', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }); localizedFormat = datetime; break; case 'full': datetime = now.toLocaleString('en-US', { timeZone: timezone }); localizedFormat = now.toLocaleString('en-US', { timeZone: timezone, weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'long' }); break; } return { timezone, datetime, isDST, utcOffset, localizedFormat }; } static convertTime( sourceTimezone: string, targetTimezone: string, time: string, date?: string ): TimeConversionResult { this.validateTimezone(sourceTimezone); this.validateTimezone(targetTimezone); this.validateTime(time); const baseDate = date ? new Date(date) : new Date(); const [hours, minutes, seconds = 0] = time.split(':').map(Number); const sourceDate = new Date(baseDate); sourceDate.setHours(hours, minutes, seconds, 0); const sourceUTC = new Date(sourceDate.toLocaleString('en-US', { timeZone: 'UTC' })); const sourceLocal = new Date(sourceDate.toLocaleString('en-US', { timeZone: sourceTimezone })); const offset = sourceUTC.getTime() - sourceLocal.getTime(); const adjustedDate = new Date(sourceDate.getTime() + offset); const targetDate = new Date(adjustedDate.toLocaleString('en-US', { timeZone: targetTimezone })); const sourceInfo: TimezoneInfo = { timezone: sourceTimezone, datetime: sourceDate.toLocaleString('en-US', { timeZone: sourceTimezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }), isDST: this.isDaylightSavingTime(sourceDate, sourceTimezone), utcOffset: this.getUTCOffset(sourceDate, sourceTimezone), localizedFormat: sourceDate.toLocaleString('en-US', { timeZone: sourceTimezone, weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }) }; const targetInfo: TimezoneInfo = { timezone: targetTimezone, datetime: targetDate.toLocaleString('en-US', { timeZone: targetTimezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }), isDST: this.isDaylightSavingTime(adjustedDate, targetTimezone), utcOffset: this.getUTCOffset(adjustedDate, targetTimezone), localizedFormat: adjustedDate.toLocaleString('en-US', { timeZone: targetTimezone, weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZoneName: 'short' }) }; const timeDifference = this.calculateTimeDifference( new Date(`2000-01-01T${time}`), targetDate ); return { source: sourceInfo, target: targetInfo, timeDifference }; } private static isDaylightSavingTime(date: Date, timezone: string): boolean { const jan = new Date(date.getFullYear(), 0, 1); const jul = new Date(date.getFullYear(), 6, 1); const janOffset = this.getTimezoneOffset(jan, timezone); const julOffset = this.getTimezoneOffset(jul, timezone); const currentOffset = this.getTimezoneOffset(date, timezone); return Math.max(janOffset, julOffset) === currentOffset; } private static getTimezoneOffset(date: Date, timezone: string): number { const utc = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' })); const target = new Date(date.toLocaleString('en-US', { timeZone: timezone })); return (utc.getTime() - target.getTime()) / (1000 * 60); } private static getUTCOffset(date: Date, timezone: string): string { const offsetMinutes = this.getTimezoneOffset(date, timezone); const sign = offsetMinutes >= 0 ? '+' : '-'; const absMinutes = Math.abs(offsetMinutes); const hours = Math.floor(absMinutes / 60); const minutes = absMinutes % 60; return `${sign}${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; } private static calculateTimeDifference(sourceTime: Date, targetTime: Date): string { const diffMs = Math.abs(targetTime.getTime() - sourceTime.getTime()); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60)); const sign = targetTime.getTime() >= sourceTime.getTime() ? '+' : '-'; return `${sign}${diffHours}h ${diffMinutes}m`; } }

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/davidan90/time-node-mcp'

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