Reputation: 19
I am working on an application in which events occur at specific times. The event creator can create events in a time zone where daylight saving time might or might not be applicable. Therefore, the creator always needs to see the events in their local time zone.
This part is pretty simple; I'm storing the time in UTC and the user's region. So, I can always show the user the time according to their clock.
Now, the problem is that there can be viewers of the event, and they have their own time zones. They might be observing daylight saving time or not. The creator and the viewer might not be observing daylight saving time at the same time (e.g., UK, US).
Lastly, all of this needs to be handled for events in the past and the future. Users should be able to see events in the past and future, and all of the logic needs to work accordingly. It seems to be a lot of conditions if you try to do it manually.
This is my current logic which fails when a visitor views
def convert_event_time_to_local(current_date: datetime, event: Event, timezone: str):
"""
Convert event datetime to local datetime.
Args:
current_date (datetime): The current date and time.
event (Event): The Event object to modify.
timezone (str): The timezone to use for the offset calculation.
Examples:
>>> check_daylight_and_add_offset(datetime(2022, 1, 1, 10, 0), event_obj, 'Eastern (UTC-05:00)')
"""
current_date_offset = (
current_date.astimezone(pytz.timezone(timezone)).dst().seconds
)
event_date_offset = event.from_date.astimezone(pytz.timezone(timezone).dst().seconds)
if current_date_offset != event_date_offset:
offset_seconds = 3600 if current_date_offset == 0 else -3600
event.date += timedelta(seconds=offset_seconds)`
I want the time to appear correctly locally for all users according to the created time weather or not the creator or the visitor are affected by daylight, even if the event was in the past
Upvotes: 1
Views: 65
Reputation: 178031
Create the event in the time zone the event takes place (an "aware" datetime
) and display it in the time zone of the viewer. No need for UTC conversion. This is ideal for, e.g., an online meeting where worldwide participants need to know the local time to call in.
Note the use of the recommended built-in zoneinfo
module which is aware of time zone rule changes in the past:
The zoneinfo module provides a concrete time zone implementation to support the IANA time zone database as originally specified in PEP 615. By default, zoneinfo uses the system’s time zone data if available; if no system time zone data is available, the library will fall back to using the first-party tzdata package available on PyPI.
Example:
# "pip install -U tzdata" for latest DST info for OSes that require it (e.g. Windows)
import datetime as dt
import zoneinfo as zi # Uses tzdata if present for latest DST info
def display_zone(event_time, tz):
print(f'{tz:20} {event_time.astimezone(zi.ZoneInfo(tz)): %c %Z (UTC%z)}')
# A date on the US West coast during daylight savings time.
event_time = dt.datetime(2024, 3, 10, 10, 0, tzinfo=zi.ZoneInfo('US/Pacific'))
display_zone(event_time, 'US/Pacific')
display_zone(event_time, 'US/Arizona') # no DST
display_zone(event_time, 'US/Mountain')
display_zone(event_time, 'US/Central')
display_zone(event_time, 'US/Eastern')
display_zone(event_time, 'Europe/Amsterdam')
display_zone(event_time, 'Asia/Karachi')
print()
# Same date in a past year. DST hadn't started yet.
event_time = dt.datetime(2022, 3, 10, 10, 0, tzinfo=zi.ZoneInfo('US/Pacific'))
display_zone(event_time, 'US/Pacific')
display_zone(event_time, 'US/Arizona') # no DST
display_zone(event_time, 'US/Mountain')
display_zone(event_time, 'US/Central')
display_zone(event_time, 'US/Eastern')
display_zone(event_time, 'Europe/Amsterdam')
display_zone(event_time, 'Asia/Karachi')
Output (note the PDT/MDT/CDT/EDT zones on the first date and PST/MST/CST/EST zones on the second):
US/Pacific Sun Mar 10 10:00:00 2024 PDT (UTC-0700)
US/Arizona Sun Mar 10 10:00:00 2024 MST (UTC-0700)
US/Mountain Sun Mar 10 11:00:00 2024 MDT (UTC-0600)
US/Central Sun Mar 10 12:00:00 2024 CDT (UTC-0500)
US/Eastern Sun Mar 10 13:00:00 2024 EDT (UTC-0400)
Europe/Amsterdam Sun Mar 10 18:00:00 2024 CET (UTC+0100)
Asia/Karachi Sun Mar 10 22:00:00 2024 PKT (UTC+0500)
US/Pacific Thu Mar 10 10:00:00 2022 PST (UTC-0800)
US/Arizona Thu Mar 10 11:00:00 2022 MST (UTC-0700)
US/Mountain Thu Mar 10 11:00:00 2022 MST (UTC-0700)
US/Central Thu Mar 10 12:00:00 2022 CST (UTC-0600)
US/Eastern Thu Mar 10 13:00:00 2022 EST (UTC-0500)
Europe/Amsterdam Thu Mar 10 19:00:00 2022 CET (UTC+0100)
Asia/Karachi Thu Mar 10 23:00:00 2022 PKT (UTC+0500)
Upvotes: 0