UNPKG

@siva-sub/mcp-public-transport

Version:

A Model Context Protocol server for Singapore transport data with real-time information and routing

180 lines (179 loc) 7.28 kB
import { logger } from '../utils/logger.js'; export class SingaporeTimeService { timezone = 'Asia/Singapore'; businessHours = { weekdays: { start: 9, end: 18 }, saturday: { start: 9, end: 13 }, sunday: { closed: true } }; rushHours = { morning: { start: 7, end: 9 }, evening: { start: 17, end: 19 }, weekendsOnly: false }; getCurrentTime() { try { const now = new Date(); // Create a proper Singapore time Date object const singaporeTime = new Date(now.toLocaleString("en-US", { timeZone: this.timezone })); return { timezone: this.timezone, datetime: now.toISOString(), // Keep original UTC ISO string timestamp: now.getTime(), formatted: { date: now.toLocaleDateString('en-SG', { timeZone: this.timezone }), time: now.toLocaleTimeString('en-SG', { timeZone: this.timezone }), full: now.toLocaleString('en-SG', { timeZone: this.timezone }), }, businessContext: { isBusinessHours: this.isBusinessHours(singaporeTime), isRushHour: this.isRushHour(singaporeTime), isWeekend: this.isWeekend(singaporeTime), isPublicHoliday: false, // TODO: Implement holiday detection } }; } catch (error) { logger.error('Failed to get Singapore time', error); throw new Error('Failed to get Singapore time'); } } formatForOneMap(date) { try { const singaporeDate = new Date(date.toLocaleString("en-US", { timeZone: this.timezone })); return { date: this.formatDateForOneMap(singaporeDate), time: this.formatTimeForOneMap(singaporeDate), }; } catch (error) { logger.error('Failed to format time for OneMap', error); throw new Error('Failed to format time for OneMap'); } } formatDateForOneMap(date) { // OneMap expects MM-DD-YYYY format const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const year = date.getFullYear(); return `${month}-${day}-${year}`; } formatTimeForOneMap(date) { // OneMap expects HH:MM:SS format const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${hours}:${minutes}:${seconds}`; } isBusinessHours(date) { const hour = date.getHours(); const day = date.getDay(); // 0 = Sunday, 1 = Monday, etc. if (day === 0) { // Sunday return !this.businessHours.sunday.closed; } else if (day === 6) { // Saturday return hour >= this.businessHours.saturday.start && hour < this.businessHours.saturday.end; } else { // Weekdays (Monday to Friday) return hour >= this.businessHours.weekdays.start && hour < this.businessHours.weekdays.end; } } isRushHour(date) { const hour = date.getHours(); const day = date.getDay(); if (this.rushHours.weekendsOnly && (day === 0 || day === 6)) { return false; // No rush hour on weekends } return (hour >= this.rushHours.morning.start && hour < this.rushHours.morning.end) || (hour >= this.rushHours.evening.start && hour < this.rushHours.evening.end); } isWeekend(date) { const day = date.getDay(); return day === 0 || day === 6; // Sunday or Saturday } getRushHourInfo(date) { const targetDate = date || new Date(); const singaporeTime = new Date(targetDate.toLocaleString("en-US", { timeZone: this.timezone })); const hour = singaporeTime.getHours(); const day = singaporeTime.getDay(); const current = this.isRushHour(singaporeTime); let type; if (current) { if (hour >= this.rushHours.morning.start && hour < this.rushHours.morning.end) { type = 'morning'; } else if (hour >= this.rushHours.evening.start && hour < this.rushHours.evening.end) { type = 'evening'; } } let nextRushHour; if (!current && day >= 1 && day <= 5) { // Weekdays only if (hour < this.rushHours.morning.start) { // Next rush hour is morning rush today nextRushHour = { start: `${this.rushHours.morning.start}:00`, end: `${this.rushHours.morning.end}:00` }; } else if (hour < this.rushHours.evening.start) { // Next rush hour is evening rush today nextRushHour = { start: `${this.rushHours.evening.start}:00`, end: `${this.rushHours.evening.end}:00` }; } else { // Next rush hour is tomorrow morning (if it's a weekday) const tomorrow = new Date(singaporeTime); tomorrow.setDate(tomorrow.getDate() + 1); if (tomorrow.getDay() >= 1 && tomorrow.getDay() <= 5) { nextRushHour = { start: `${this.rushHours.morning.start}:00 (tomorrow)`, end: `${this.rushHours.morning.end}:00 (tomorrow)` }; } } } return { current, nextRushHour, type }; } getNextBusinessHours(date) { const targetDate = date || new Date(); const singaporeTime = new Date(targetDate.toLocaleString("en-US", { timeZone: this.timezone })); const hour = singaporeTime.getHours(); const day = singaporeTime.getDay(); if (this.isBusinessHours(singaporeTime)) { return 'Currently business hours'; } if (day >= 1 && day <= 5) { // Weekdays if (hour < this.businessHours.weekdays.start) { return `${this.businessHours.weekdays.start}:00 today`; } else { return `${this.businessHours.weekdays.start}:00 tomorrow`; } } else if (day === 6) { // Saturday if (hour < this.businessHours.saturday.start) { return `${this.businessHours.saturday.start}:00 today`; } else { return `${this.businessHours.weekdays.start}:00 Monday`; } } else { // Sunday return `${this.businessHours.weekdays.start}:00 Monday`; } } // Utility method to create a Singapore time from UTC fromUTC(utcDate) { return new Date(utcDate.toLocaleString("en-US", { timeZone: this.timezone })); } // Utility method to get Singapore offset from UTC getSingaporeOffset() { return '+08:00'; // Singapore is always UTC+8 } }