1
- from datetime import datetime
1
+ from datetime import datetime , timedelta
2
2
from enum import Enum
3
3
import json
4
4
from typing import Sequence
5
5
6
- import pytz
7
- from tzlocal import get_localzone
6
+ from zoneinfo import ZoneInfo
8
7
from mcp .server import Server
9
8
from mcp .server .stdio import stdio_server
10
9
from mcp .types import Tool , TextContent , ImageContent , EmbeddedResource
10
+ from mcp .shared .exceptions import McpError
11
11
12
12
from pydantic import BaseModel
13
13
@@ -34,17 +34,29 @@ class TimeConversionInput(BaseModel):
34
34
time : str
35
35
target_tz_list : list [str ]
36
36
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
+
39
55
40
56
class TimeServer :
41
57
def get_current_time (self , timezone_name : str ) -> TimeResult :
42
58
"""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 )
48
60
current_time = datetime .now (timezone )
49
61
50
62
return TimeResult (
@@ -57,30 +69,28 @@ def convert_time(
57
69
self , source_tz : str , time_str : str , target_tz : str
58
70
) -> TimeConversionResult :
59
71
"""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 )
69
74
70
75
try :
71
76
parsed_time = datetime .strptime (time_str , "%H:%M" ).time ()
72
77
except ValueError :
73
78
raise ValueError ("Invalid time format. Expected HH:MM [24-hour format]" )
74
79
75
80
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 ,
78
88
)
79
89
80
90
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
84
94
85
95
if hours_difference .is_integer ():
86
96
time_diff_str = f"{ hours_difference :+.1f} h"
@@ -114,7 +124,7 @@ async def list_tools() -> list[Tool]:
114
124
return [
115
125
Tool (
116
126
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" ,
118
128
inputSchema = {
119
129
"type" : "object" ,
120
130
"properties" : {
@@ -128,7 +138,7 @@ async def list_tools() -> list[Tool]:
128
138
),
129
139
Tool (
130
140
name = TimeTools .CONVERT_TIME .value ,
131
- description = f "Convert time between timezones" ,
141
+ description = "Convert time between timezones" ,
132
142
inputSchema = {
133
143
"type" : "object" ,
134
144
"properties" : {
@@ -179,7 +189,9 @@ async def call_tool(
179
189
case _:
180
190
raise ValueError (f"Unknown tool: { name } " )
181
191
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
+ ]
183
195
184
196
except Exception as e :
185
197
raise ValueError (f"Error processing mcp-server-time query: { str (e )} " )
0 commit comments