Search code examples
pythonlocalized

date value out of range when localize datetime


I am trying to localize a time string as Asia/Taipei timezone by python, and save the data to mongo.

But when I tried to localize the time by localize function, I got following error: OverflowError: date value out of range, I think it might because of the time I tried to set is the max limit: 9999/12/31, cause while I set other time string like 2024/01/01 it works perfectly.

So I tried to set the time by .replace(tzinfo=tz) function, but got an incorrect result of time zone as UTC +08:06 not the correct +08:00.

Currently I applied method 3, add 6 minutes to the date time after replace timezone, but I am not sure if it's a good method.

Do you have any suggestions to set the time the the correct timezone? Any suggestion is welcome, following is my code:


import pytz
from datetime import datetime, date
tz = pytz.timezone('Asia/Taipei')
date_string = '9999/12/31'

# method 1
# date_localized = datetime.strptime(date_string, '%Y/%m/%d')
# date_localized = tz.localize(date_localized)
# OverflowError: date value out of range

# method 2
date_localized = datetime.strptime(date_string, '%Y/%m/%d').replace(tzinfo=tz)
# 9999-12-30T15:54:00.000+00:00 in mongo

# method 3
date_localized = datetime.strptime(date_string, '%Y/%m/%d').replace(tzinfo=tz)
tag_disableDtm = tag_disableDtm + timedelta(minutes=6)
# 9999-12-30T16:00:00.000+00:00 in mongo


Solution

  • As of Python 3.9, PyTZ is deprecated. Use zoneinfo from the standard library instead:

    from datetime import datetime, timezone
    from zoneinfo import ZoneInfo
    
    tz = ZoneInfo('Asia/Taipei')
    date_string = '9999/12/31'
    
    # method 2
    date_localized = datetime.strptime(date_string, '%Y/%m/%d').replace(tzinfo=tz)
    # datetime.datetime(9999, 12, 31, 0, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Taipei'))
    # 9999-12-30T16:00:00.000+00:00 in MongoDB
    
    date_localized.astimezone(timezone.utc)
    # datetime.datetime(9999, 12, 30, 16, 0, tzinfo=datetime.timezone.utc)
    

    Also, I would recommend that you store the High Date 9999-12-31 as UTC and at midnight. Otherwise the localised conversion from different locations will always be different times on 30th or 31st Dec, leading to different times in the DB for that same date.

    HIGH_DATE = datetime(9999, 12, 31, tzinfo=timezone.utc)
    HIGH_DATE.astimezone(ZoneInfo('Asia/Taipei'))
    # datetime.datetime(9999, 12, 31, 8, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Taipei'))
    # 9999-12-31T00:00:00.000+00:00 in MongoDB
    
    datetime(9999, 12, 31, 8, tzinfo=ZoneInfo('Asia/Taipei')) == HIGH_DATE
    # True
    datetime.strptime('9999/12/31 8:0:0', '%Y/%m/%d %H:%M:%S').replace(tzinfo=tz) == HIGH_DATE
    # True
    

    Ideally, High date should also be 11:59:59 PM on 31st Dec 9999 but if that's in UTC then all timezones ahead of UTC, like Taipei, would overflow.