44from pathlib import Path
55from typing import TYPE_CHECKING , Sequence , cast
66
7- import dateutil
87import pkg_resources
9- import pytz
10- from bubop import format_datetime_tz , logger
8+ from bubop import logger
119from googleapiclient import discovery
1210from googleapiclient .http import HttpError
1311
1412from syncall .google .google_side import GoogleSide
1513from syncall .sync_side import SyncSide
1614
15+ from .common import parse_google_datetime
16+
1717if TYPE_CHECKING :
1818 from syncall .types import GTasksItem , GTasksList
1919
@@ -229,7 +229,7 @@ def last_modification_key(cls) -> str:
229229 def _parse_dt_or_none (item : GTasksItem , field : str ) -> datetime .datetime | None :
230230 """Return the datetime on which task was completed in datetime format."""
231231 if (dt := item .get (field )) is not None :
232- dt_dt = GTasksSide . parse_datetime (dt )
232+ dt_dt = parse_google_datetime (dt )
233233 assert isinstance (dt_dt , datetime .datetime )
234234 return dt_dt
235235
@@ -245,74 +245,14 @@ def get_task_completed_time(item: GTasksItem) -> datetime.datetime | None:
245245 """Return the datetime on which task was completed in datetime format."""
246246 return GTasksSide ._parse_dt_or_none (item = item , field = "completed" )
247247
248- @staticmethod
249- def format_datetime (dt : datetime .datetime ) -> str :
250- assert isinstance (dt , datetime .datetime )
251- return format_datetime_tz (dt )
252-
253- @classmethod
254- def parse_datetime (cls , dt : str | dict | datetime .datetime ) -> datetime .datetime :
255- """Parse datetime given in the GTasks format(s):
256- - string with ('T', 'Z' separators).
257- - (dateTime, dateZone) dictionary
258- - datetime object
259-
260- Usage::
261-
262- >>> GTasksSide.parse_datetime("2019-03-05T00:03:09Z")
263- datetime.datetime(2019, 3, 5, 0, 3, 9)
264- >>> GTasksSide.parse_datetime("2019-03-05")
265- datetime.datetime(2019, 3, 5, 0, 0)
266- >>> GTasksSide.parse_datetime("2019-03-05T00:03:01.1234Z")
267- datetime.datetime(2019, 3, 5, 0, 3, 1, 123400)
268- >>> GTasksSide.parse_datetime("2019-03-08T00:29:06.602Z")
269- datetime.datetime(2019, 3, 8, 0, 29, 6, 602000)
270-
271- >>> from tzlocal import get_localzone_name
272- >>> tz = get_localzone_name()
273- >>> a = GTasksSide.parse_datetime({"dateTime": "2021-11-14T22:07:49Z", "timeZone": tz})
274- >>> b = GTasksSide.parse_datetime({"dateTime": "2021-11-14T22:07:49.000000Z"})
275- >>> b
276- datetime.datetime(2021, 11, 14, 22, 7, 49)
277- >>> from bubop.time import is_same_datetime
278- >>> is_same_datetime(a, b) or (print(a) or print(b))
279- True
280- >>> GTasksSide.parse_datetime({"dateTime": "2021-11-14T22:07:49.123456"})
281- datetime.datetime(2021, 11, 14, 22, 7, 49, 123456)
282- >>> a = GTasksSide.parse_datetime({"dateTime": "2021-11-14T22:07:49Z", "timeZone": tz})
283- >>> GTasksSide.parse_datetime(a).isoformat() == a.isoformat()
284- True
285- """
286- if isinstance (dt , str ):
287- return dateutil .parser .parse (dt ).replace (tzinfo = None ) # type: ignore
288-
289- if isinstance (dt , dict ):
290- date_time = dt .get ("dateTime" )
291- if date_time is None :
292- raise RuntimeError (f"Invalid structure dict: { dt } " )
293- dt_dt = GTasksSide .parse_datetime (date_time )
294- time_zone = dt .get ("timeZone" )
295- if time_zone is not None :
296- timezone = pytz .timezone (time_zone )
297- dt_dt = timezone .localize (dt_dt )
298-
299- return dt_dt
300-
301- if isinstance (dt , datetime .datetime ):
302- return dt
303-
304- raise TypeError (
305- f"Unexpected type of a given date item, type: { type (dt )} , contents: { dt } " ,
306- )
307-
308248 @classmethod
309249 def items_are_identical (cls , item1 , item2 , ignore_keys : Sequence [str ] = []) -> bool :
310250 for item in [item1 , item2 ]:
311251 for key in cls ._date_keys :
312252 if key not in item :
313253 continue
314254
315- item [key ] = cls . parse_datetime (item [key ])
255+ item [key ] = parse_google_datetime (item [key ])
316256
317257 return SyncSide ._items_are_identical (
318258 item1 ,
0 commit comments