1- from datetime import datetime
1+ from datetime import datetime , timedelta
22from enum import Enum
33import json
44from typing import Sequence
55
6- import pytz
7- from tzlocal import get_localzone
6+ from zoneinfo import ZoneInfo
87from mcp .server import Server
98from mcp .server .stdio import stdio_server
109from mcp .types import Tool , TextContent , ImageContent , EmbeddedResource
10+ from mcp .shared .exceptions import McpError
1111
1212from pydantic import BaseModel
1313
@@ -34,17 +34,29 @@ class TimeConversionInput(BaseModel):
3434 time : str
3535 target_tz_list : list [str ]
3636
37- def get_local_tz (local_tz_override : str | None = None ) -> pytz .timezone :
38- return pytz .timezone (local_tz_override ) if local_tz_override else get_localzone ()
37+
38+ def get_local_tz (local_tz_override : str | None = None ) -> ZoneInfo :
39+ if local_tz_override :
40+ return ZoneInfo (local_tz_override )
41+
42+ # Get local timezone from datetime.now()
43+ tzinfo = datetime .now ().astimezone (tz = None ).tzinfo
44+ if tzinfo is not None :
45+ return ZoneInfo (str (tzinfo ))
46+ raise McpError ("Could not determine local timezone - tzinfo is None" )
47+
48+
49+ def get_zoneinfo (timezone_name : str ) -> ZoneInfo :
50+ try :
51+ return ZoneInfo (timezone_name )
52+ except Exception as e :
53+ raise McpError (f"Invalid timezone: { str (e )} " )
54+
3955
4056class TimeServer :
4157 def get_current_time (self , timezone_name : str ) -> TimeResult :
4258 """Get current time in specified timezone"""
43- try :
44- timezone = pytz .timezone (timezone_name )
45- except pytz .exceptions .UnknownTimeZoneError as e :
46- raise ValueError (f"Unknown timezone: { str (e )} " )
47-
59+ timezone = get_zoneinfo (timezone_name )
4860 current_time = datetime .now (timezone )
4961
5062 return TimeResult (
@@ -57,30 +69,28 @@ def convert_time(
5769 self , source_tz : str , time_str : str , target_tz : str
5870 ) -> TimeConversionResult :
5971 """Convert time between timezones"""
60- try :
61- source_timezone = pytz .timezone (source_tz )
62- except pytz .exceptions .UnknownTimeZoneError as e :
63- raise ValueError (f"Unknown source timezone: { str (e )} " )
64-
65- try :
66- target_timezone = pytz .timezone (target_tz )
67- except pytz .exceptions .UnknownTimeZoneError as e :
68- raise ValueError (f"Unknown target timezone: { str (e )} " )
72+ source_timezone = get_zoneinfo (source_tz )
73+ target_timezone = get_zoneinfo (target_tz )
6974
7075 try :
7176 parsed_time = datetime .strptime (time_str , "%H:%M" ).time ()
7277 except ValueError :
7378 raise ValueError ("Invalid time format. Expected HH:MM [24-hour format]" )
7479
7580 now = datetime .now (source_timezone )
76- source_time = source_timezone .localize (
77- datetime (now .year , now .month , now .day , parsed_time .hour , parsed_time .minute )
81+ source_time = datetime (
82+ now .year ,
83+ now .month ,
84+ now .day ,
85+ parsed_time .hour ,
86+ parsed_time .minute ,
87+ tzinfo = source_timezone ,
7888 )
7989
8090 target_time = source_time .astimezone (target_timezone )
81- hours_difference = (
82- target_time .utcoffset () - source_time . utcoffset ()
83- ).total_seconds () / 3600
91+ source_offset = source_time . utcoffset () or timedelta ()
92+ target_offset = target_time .utcoffset () or timedelta ()
93+ hours_difference = ( target_offset - source_offset ).total_seconds () / 3600
8494
8595 if hours_difference .is_integer ():
8696 time_diff_str = f"{ hours_difference :+.1f} h"
@@ -114,7 +124,7 @@ async def list_tools() -> list[Tool]:
114124 return [
115125 Tool (
116126 name = TimeTools .GET_CURRENT_TIME .value ,
117- description = f "Get current time in a specific timezones" ,
127+ description = "Get current time in a specific timezones" ,
118128 inputSchema = {
119129 "type" : "object" ,
120130 "properties" : {
@@ -128,7 +138,7 @@ async def list_tools() -> list[Tool]:
128138 ),
129139 Tool (
130140 name = TimeTools .CONVERT_TIME .value ,
131- description = f "Convert time between timezones" ,
141+ description = "Convert time between timezones" ,
132142 inputSchema = {
133143 "type" : "object" ,
134144 "properties" : {
@@ -179,7 +189,9 @@ async def call_tool(
179189 case _:
180190 raise ValueError (f"Unknown tool: { name } " )
181191
182- return [TextContent (type = "text" , text = json .dumps (result .model_dump (), indent = 2 ))]
192+ return [
193+ TextContent (type = "text" , text = json .dumps (result .model_dump (), indent = 2 ))
194+ ]
183195
184196 except Exception as e :
185197 raise ValueError (f"Error processing mcp-server-time query: { str (e )} " )
0 commit comments