Files
upstream-zulip/zerver/lib/timestamp.py
upstream-mirror 64898b2c79
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
2026-09-15 15:05:30 +05:00

98 lines
2.9 KiB
Python

from datetime import datetime, timedelta, timezone
from functools import cache
import icu
from django.utils.translation import get_language
class TimeZoneNotUTCError(Exception):
pass
class TimeZoneMissingError(Exception):
pass
def verify_UTC(dt: datetime) -> None:
if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) != timezone.utc.utcoffset(dt):
raise TimeZoneNotUTCError(f"Datetime {dt} does not have a UTC time zone.")
def convert_to_UTC(dt: datetime) -> datetime:
if dt.tzinfo is None:
return dt.replace(tzinfo=timezone.utc)
return dt.astimezone(timezone.utc)
def floor_to_hour(dt: datetime) -> datetime:
verify_UTC(dt)
return datetime(*dt.timetuple()[:4], tzinfo=timezone.utc)
def floor_to_day(dt: datetime) -> datetime:
verify_UTC(dt)
return datetime(*dt.timetuple()[:3], tzinfo=timezone.utc)
def ceiling_to_hour(dt: datetime) -> datetime:
floor = floor_to_hour(dt)
if floor == dt:
return floor
return floor + timedelta(hours=1)
def ceiling_to_day(dt: datetime) -> datetime:
floor = floor_to_day(dt)
if floor == dt:
return floor
return floor + timedelta(days=1)
def timestamp_to_datetime(timestamp: float) -> datetime:
return datetime.fromtimestamp(float(timestamp), tz=timezone.utc)
def datetime_to_timestamp(dt: datetime) -> int:
verify_UTC(dt)
return int(dt.timestamp())
def datetime_to_global_time(dt: datetime) -> str:
if dt.tzinfo is None:
raise TimeZoneMissingError(f"Datetime {dt} does not have a time zone.")
return f"<time:{dt.isoformat(timespec='seconds')}>"
@cache
def get_date_time_pattern_generator(language: str) -> icu.DateTimePatternGenerator:
return icu.DateTimePatternGenerator.createInstance(icu.Locale(language))
@cache
def get_icu_time_zone(time_zone: str) -> icu.TimeZone:
return icu.TimeZone.createTimeZone(time_zone)
@cache
def get_date_time_format(language: str, use_twenty_four_hour_time: bool) -> icu.SimpleDateFormat:
skeleton = f"yMMMEd{'H' if use_twenty_four_hour_time else 'h'}mz"
pattern = get_date_time_pattern_generator(language).getBestPattern(skeleton)
return icu.SimpleDateFormat(pattern, icu.Locale(language))
def format_datetime_to_string(dt: datetime, use_twenty_four_hour_time: bool) -> str:
assert dt.tzinfo is not None
time_zone = getattr(dt.tzinfo, "key", None)
if time_zone is None:
offset = dt.tzinfo.utcoffset(dt)
assert offset is not None
sign = "-" if offset < timedelta(0) else "+"
hours, rest = divmod(abs(offset), timedelta(hours=1))
minutes, rest = divmod(rest, timedelta(minutes=1))
assert rest == timedelta(0)
time_zone = f"GMT{sign}{hours:02}:{minutes:02}"
language = get_language()
calendar = icu.Calendar.createInstance(get_icu_time_zone(time_zone), icu.Locale(language))
calendar.setTime(dt)
return get_date_time_format(language, use_twenty_four_hour_time).format(calendar)