MCP DateTime
by odgrim
- src
// Common timezones to ensure they're always available
export const COMMON_TIMEZONES = [
"UTC",
"Europe/London",
"Europe/Paris",
"Europe/Berlin",
"America/New_York",
"America/Chicago",
"America/Denver",
"America/Los_Angeles",
"Asia/Tokyo",
"Asia/Shanghai",
"Asia/Kolkata",
"Australia/Sydney",
"Pacific/Auckland"
];
/**
* Get all available timezones using the Intl API
* @returns Array of timezone strings
*/
export function getAvailableTimezones(): string[] {
try {
const timezones = new Set<string>(Intl.supportedValuesOf('timeZone'));
// Ensure common timezones are always included
COMMON_TIMEZONES.forEach(tz => timezones.add(tz));
return Array.from(timezones).sort();
} catch (error) {
console.error("Error getting timezones from Intl API:", error);
// Fallback to common timezones if the Intl API fails
return COMMON_TIMEZONES;
}
}
/**
* Format the list of available timezones as a string
* @param prefix Optional prefix text to include before the list (default: "Available timezones")
* @returns Formatted string with timezone count and comma-separated list
*/
export function getFormattedTimezoneList(prefix: string = "Available timezones"): string {
const timezones = getAvailableTimezones();
return `${prefix} (${timezones.length}): ${timezones.join(', ')}`;
}
/**
* Check if a timezone is valid
* @param timezone Timezone string to validate
* @returns boolean indicating if the timezone is valid
*/
export function isValidTimezone(timezone: string): boolean {
try {
// Try to use the timezone with Intl.DateTimeFormat
Intl.DateTimeFormat(undefined, { timeZone: timezone });
return true;
} catch (error) {
return false;
}
}
/**
* Get the current system timezone
* @returns The current system timezone string, or "UTC" as fallback
*/
export function getCurrentTimezone(): string {
try {
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
return processTimezone(timezone);
} catch (error) {
console.error("Error getting current timezone:", error);
return "UTC"; // Default to UTC if there's an error
}
}
// Export this function to make it testable
export function processTimezone(timezone: string): string {
// Verify it's a valid timezone
if (isValidTimezone(timezone)) {
return timezone;
}
return handleInvalidTimezone(timezone);
}
// Export this function to make it testable
export function handleInvalidTimezone(timezone: string): string {
console.warn(`System timezone ${timezone} is not valid, falling back to UTC`);
return "UTC";
}
/**
* Format the current date and time for a given timezone in ISO8601 format
* @param timezone Timezone string
* @returns Formatted date-time string in ISO8601 format
*/
export function getCurrentTimeInTimezone(timezone: string): string {
try {
const date = new Date();
// Create a formatter that includes the timezone
const options: Intl.DateTimeFormatOptions = {
timeZone: timezone,
timeZoneName: 'short'
};
// Get the timezone offset from the formatter
const formatter = new Intl.DateTimeFormat('en-US', options);
const formattedDate = formatter.format(date);
const timezonePart = formattedDate.split(' ').pop() || '';
// Format the date in ISO8601 format with the timezone
// First get the date in the specified timezone
const tzFormatter = new Intl.DateTimeFormat('en-US', {
timeZone: timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false,
fractionalSecondDigits: 3
});
const parts = tzFormatter.formatToParts(date);
const dateParts: Record<string, string> = {};
parts.forEach(part => {
if (part.type !== 'literal') {
dateParts[part.type] = part.value;
}
});
// Format as YYYY-MM-DDTHH:MM:SS.sss±HH:MM (ISO8601)
const isoDate = `${dateParts.year}-${dateParts.month}-${dateParts.day}T${dateParts.hour}:${dateParts.minute}:${dateParts.second}.${dateParts.fractionalSecond || '000'}`;
// For proper ISO8601, we need to add the timezone offset
// We can use the Intl.DateTimeFormat to get the timezone offset
const tzOffset = new Date().toLocaleString('en-US', { timeZone: timezone, timeZoneName: 'longOffset' }).split(' ').pop() || '';
// Format the final ISO8601 string
return `${isoDate}${tzOffset.replace('GMT', '')}`;
} catch (error) {
console.error(`Error formatting time for timezone ${timezone}:`, error);
return 'Invalid timezone';
}
}