mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			88 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			88 lines
		
	
	
		
			2.7 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
 | 
						|
 | 
						|
 | 
						|
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())
 | 
						|
 | 
						|
 | 
						|
@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)
 |