Skip to main content
Glama
pshempel

MCP Time Server Node

by pshempel
daysUntil.test.ts8.32 kB
import { daysUntil } from '../../src/tools/daysUntil'; import { addDays, subDays, format } from 'date-fns'; import { ValidationError, DateParsingError, TimezoneError, } from '../../src/adapters/mcp-sdk/errors'; describe('daysUntil', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('Basic functionality', () => { it('should calculate days until a future date', () => { // Use format to get consistent local date string const futureDate = addDays(new Date(), 7); const dateString = format(futureDate, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString }); expect(result).toBe(7); }); it('should return 0 for today', () => { const today = format(new Date(), 'yyyy-MM-dd'); const result = daysUntil({ target_date: today }); expect(result).toBe(0); }); it('should return negative days for past dates', () => { const pastDate = subDays(new Date(), 5); const dateString = format(pastDate, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString }); expect(result).toBe(-5); }); it('should handle dates far in the future', () => { const result = daysUntil({ target_date: '2030-01-01' }); expect(result).toBeGreaterThan(1000); // At least 1000 days away }); }); describe('Date format handling', () => { it('should accept ISO date format', () => { const tomorrow = addDays(new Date(), 1); const isoDate = format(tomorrow, 'yyyy-MM-dd'); const result = daysUntil({ target_date: isoDate }); expect(result).toBe(1); }); it('should accept ISO datetime format', () => { const tomorrow = addDays(new Date(), 1); const isoDateTime = tomorrow.toISOString(); const result = daysUntil({ target_date: isoDateTime }); expect(result).toBe(1); }); it('should handle natural language dates', () => { // This might need adjustment based on parseISO capabilities const tomorrow = addDays(new Date(), 1); const dateString = format(tomorrow, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString }); expect(result).toBe(1); }); }); describe('Timezone handling', () => { it('should use system timezone when not specified', () => { const tomorrow = addDays(new Date(), 1); const dateOnly = format(tomorrow, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateOnly }); expect(result).toBe(1); }); it('should use UTC when timezone is empty string', () => { const tomorrowUTC = addDays(new Date(), 1); const utcString = tomorrowUTC.toISOString(); const result = daysUntil({ target_date: utcString, timezone: '', }); expect(result).toBe(1); }); it('should use specified timezone', () => { // Testing with a known future date in specific timezone const futureDate = '2025-12-25T00:00:00'; const result = daysUntil({ target_date: futureDate, timezone: 'America/New_York', }); // Should be a positive number (exact value depends on current date) expect(result).toBeGreaterThan(0); }); }); describe('Formatting options', () => { it('should return plain number by default', () => { const tomorrow = addDays(new Date(), 1); const dateString = format(tomorrow, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString }); expect(typeof result).toBe('number'); expect(result).toBe(1); }); it('should format as "Today" when format_result is true', () => { const today = format(new Date(), 'yyyy-MM-dd'); const result = daysUntil({ target_date: today, format_result: true, }); expect(result).toBe('Today'); }); it('should format as "Tomorrow" for next day', () => { const tomorrow = addDays(new Date(), 1); const dateString = format(tomorrow, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString, format_result: true, }); expect(result).toBe('Tomorrow'); }); it('should format as "Yesterday" for previous day', () => { const yesterday = subDays(new Date(), 1); const dateString = format(yesterday, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString, format_result: true, }); expect(result).toBe('Yesterday'); }); it('should format as "in N days" for future dates', () => { const futureDate = addDays(new Date(), 10); const dateString = format(futureDate, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString, format_result: true, }); expect(result).toBe('in 10 days'); }); it('should format as "N days ago" for past dates', () => { const pastDate = subDays(new Date(), 5); const dateString = format(pastDate, 'yyyy-MM-dd'); const result = daysUntil({ target_date: dateString, format_result: true, }); expect(result).toBe('5 days ago'); }); }); describe('Edge cases', () => { it('should handle same day different times as 0 days', () => { const now = new Date(); const laterToday = new Date(now); laterToday.setHours(23, 59, 59); const result = daysUntil({ target_date: laterToday.toISOString(), }); expect(result).toBe(0); }); it('should handle leap year dates', () => { // Feb 29, 2024 was a leap day const result = daysUntil({ target_date: '2024-02-29' }); expect(typeof result).toBe('number'); // Should be negative (in the past) expect(result).toBeLessThan(0); }); it('should handle year boundaries', () => { const newYear2026 = '2026-01-01'; const result = daysUntil({ target_date: newYear2026 }); expect(result).toBeGreaterThan(0); }); }); describe('Error handling', () => { it('should throw error for missing target_date', () => { expect(() => daysUntil({} as any)).toThrow(); try { daysUntil({} as any); } catch (e: any) { expect(e).toBeInstanceOf(ValidationError); expect(e.code).toBe('VALIDATION_ERROR'); expect(e.message).toContain('target_date is required'); } }); it('should throw error for invalid date', () => { expect(() => daysUntil({ target_date: 'not-a-date' })).toThrow(); try { daysUntil({ target_date: 'not-a-date' }); } catch (e: any) { expect(e).toBeInstanceOf(DateParsingError); expect(e.code).toBe('DATE_PARSING_ERROR'); expect(e.message).toContain('Invalid target_date format'); } }); it('should throw error for invalid timezone', () => { expect(() => daysUntil({ target_date: '2025-12-25', timezone: 'Invalid/Timezone', }) ).toThrow(); try { daysUntil({ target_date: '2025-12-25', timezone: 'Invalid/Timezone', }); } catch (e: any) { expect(e).toBeInstanceOf(TimezoneError); expect(e.code).toBe('TIMEZONE_ERROR'); expect(e.message).toContain('Invalid timezone'); } }); }); describe('Real-world scenarios', () => { it('should calculate days until Christmas 2025', () => { const result = daysUntil({ target_date: '2025-12-25', format_result: false, }); // This will vary based on when test runs expect(result).toBeGreaterThan(0); expect(result).toBeLessThan(365); }); it('should handle event planning scenario', () => { // Event 30 days from now at 6 PM in New York const eventDate = addDays(new Date(), 30); eventDate.setHours(18, 0, 0, 0); const result = daysUntil({ target_date: eventDate.toISOString(), timezone: 'America/New_York', format_result: true, }); expect(result).toBe('in 30 days'); }); it('should handle deadline tracking', () => { // Project due in 14 days const deadline = addDays(new Date(), 14); const result = daysUntil({ target_date: format(deadline, 'yyyy-MM-dd'), }); expect(result).toBe(14); }); }); });

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