Skip to main content
Glama

Time Tracking MCP

by markwharton
duration-parser.ts2.77 kB
// src/services/duration-parser.ts import type { Duration } from '../types/index.js'; /** * Parse duration string into decimal hours * Supports multiple formats: * - "2h", "2 hours", "2.5h" * - "90m", "90 minutes" * - "PT2H30M" (ISO 8601) * - "half an hour", "quarter hour" */ export function parseDuration(input: string): Duration { const normalized = input.toLowerCase().trim(); // Handle natural language if (normalized.match(/half\s*(an?\s*)?hour/)) { return { hours: 0.5, formatted: '0.5h' }; } if (normalized.match(/quarter\s*(of\s*an?\s*)?hour/)) { return { hours: 0.25, formatted: '0.25h' }; } // Parse hours: "2h", "2 hours", "2.5h" const hoursMatch = normalized.match(/^(\d+(?:\.\d+)?)\s*(hour|hr|h)s?$/); if (hoursMatch) { const hours = parseFloat(hoursMatch[1]); return { hours, formatted: `${hours}h` }; } // Parse minutes: "90m", "90 minutes" const minutesMatch = normalized.match(/^(\d+)\s*(minute|min|m)s?$/); if (minutesMatch) { const minutes = parseInt(minutesMatch[1]); const hours = minutes / 60; return { hours, formatted: `${hours.toFixed(2)}h` }; } // Parse ISO 8601 duration: PT2H30M const isoMatch = normalized.match(/^pt(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?$/); if (isoMatch) { const [, hoursStr, minutesStr, secondsStr] = isoMatch; let totalHours = 0; if (hoursStr) totalHours += parseInt(hoursStr); if (minutesStr) totalHours += parseInt(minutesStr) / 60; if (secondsStr) totalHours += parseFloat(secondsStr) / 3600; return { hours: totalHours, formatted: `${totalHours.toFixed(2)}h` }; } // Try just a number (assume hours) const numberMatch = normalized.match(/^(\d+(?:\.\d+)?)$/); if (numberMatch) { const hours = parseFloat(numberMatch[1]); return { hours, formatted: `${hours}h` }; } throw new Error(`Unable to parse duration: "${input}". Try formats like "2h", "90m", or "1.5h"`); } /** * Format hours as readable duration * Examples: 2.5 → "2.5h", 0.75 → "0.75h" */ export function formatDuration(hours: number): string { // Use 1 decimal place if needed, otherwise no decimals if (hours % 1 === 0) { return `${hours}h`; } return `${hours.toFixed(1)}h`; } /** * Convert hours to hours and minutes * Example: 2.5 → "2h 30m" */ export function formatDurationDetailed(hours: number): string { const wholeHours = Math.floor(hours); const minutes = Math.round((hours - wholeHours) * 60); if (minutes === 0) { return `${wholeHours}h`; } if (wholeHours === 0) { return `${minutes}m`; } return `${wholeHours}h ${minutes}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/markwharton/time-tracking-mcp'

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