1
1
import base64
2
2
import os
3
+ import re
3
4
import gptscript
4
5
from filetype import guess_mime
6
+ from datetime import datetime , timezone , timedelta
7
+ from zoneinfo import ZoneInfo
5
8
from email .mime .text import MIMEText
6
9
from email .mime .multipart import MIMEMultipart
7
10
from email .mime .base import MIMEBase
@@ -104,6 +107,7 @@ def client(service_name: str, version: str):
104
107
async def list_messages (service , query , max_results ):
105
108
all_messages = []
106
109
next_page_token = None
110
+ query = format_query_dates (service , query )
107
111
try :
108
112
while True :
109
113
if next_page_token :
@@ -357,7 +361,7 @@ def format_reply_gmail_style(original_from, original_date, original_body_html):
357
361
358
362
if original_body_html is None :
359
363
original_body_html = ""
360
-
364
+
361
365
# Format date as "Mon, Mar 18, 2024 at 10:30 AM"
362
366
formatted_date = original_date
363
367
try :
@@ -373,3 +377,61 @@ def format_reply_gmail_style(original_from, original_date, original_body_html):
373
377
reply_html = f'<br><br>On { formatted_date } , <b>{ original_from } </b> wrote:<br>{ quoted_body_html } '
374
378
375
379
return reply_html
380
+
381
+ def format_query_dates (service , query ):
382
+ """
383
+ Converts date strings in Gmail search queries to Unix timestamps for correct timezone handling.
384
+ - before: uses beginning of day (00:00:00)
385
+ - after: uses end of day (23:59:59)
386
+ """
387
+ if not query :
388
+ return query
389
+
390
+ # Get user's timezone
391
+ user_tz_str = get_user_timezone (service )
392
+
393
+ # Use UTC if timezone is invalid
394
+ try :
395
+ user_tz = ZoneInfo (user_tz_str )
396
+ except :
397
+ user_tz = timezone .utc
398
+
399
+ def replace_date (match ):
400
+ operator , quote1 , date_str , quote2 = match .groups ()
401
+ date_str = date_str .replace ('/' , '-' )
402
+
403
+ try :
404
+ # Parse date parts
405
+ year , month , day = map (int , date_str .split ('-' ))
406
+
407
+ if operator == "before" :
408
+ # For 'before:', use beginning of day (00:00:00)
409
+ dt = datetime (year , month , day , 0 , 0 , 0 , tzinfo = user_tz )
410
+ else : # after
411
+ # For 'after:', use end of day (23:59:59)
412
+ dt = datetime (year , month , day , 23 , 59 , 59 , tzinfo = user_tz )
413
+
414
+ timestamp = int (dt .timestamp ())
415
+ return f"{ operator } :{ quote1 } { timestamp } { quote2 } "
416
+ except :
417
+ return match .group (0 )
418
+
419
+ # Replace dates with timestamps
420
+ pattern = r'(before|after):(["\']?)(\d{4}[-/]\d{1,2}[-/]\d{1,2})(["\']?)'
421
+ return re .sub (pattern , replace_date , query )
422
+
423
+
424
+ def get_obot_user_timezone ():
425
+ return os .getenv ("OBOT_USER_TIMEZONE" , "UTC" ).strip ()
426
+
427
+ def get_user_timezone (service ):
428
+ """Fetches the authenticated user's time zone from User's Google Calendar settings."""
429
+ try :
430
+ settings = service .settings ().get (setting = "timezone" ).execute ()
431
+ return settings .get ("value" , get_obot_user_timezone ()) # Default to Obot's user timezone if not found
432
+ except HttpError as err :
433
+ if err .status_code == 403 :
434
+ raise Exception (f"HttpError retrieving user timezone: { err } " )
435
+ return "UTC"
436
+ except Exception as e :
437
+ return "UTC"
0 commit comments