mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	Sort of a hacky hammer, but * The original design of the analytics system mistakenly attempted to play nicely with non-UTC datetimes. * Timezone errors are really hard to find and debug, and don't jump out that easily when reading code. I don't know of any outstanding errors, but putting a few "assert this timezone is in UTC" around will hopefully reduce the chance that there are any current or future timezone errors. Note that none of these functions are called outside of the analytics code (and tests). This commit also doesn't change any current behavior, assuming a database where all datetimes have been being stored in UTC.
		
			
				
	
	
		
			53 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			53 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import datetime
 | 
						|
import calendar
 | 
						|
from django.utils.timezone import utc as timezone_utc
 | 
						|
 | 
						|
class TimezoneNotUTCException(Exception):
 | 
						|
    pass
 | 
						|
 | 
						|
def verify_UTC(dt):
 | 
						|
    # type: (datetime.datetime) -> None
 | 
						|
    if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) != timezone_utc.utcoffset(dt):
 | 
						|
        raise TimezoneNotUTCException("Datetime %s does not have a UTC timezone." % (dt,))
 | 
						|
 | 
						|
def convert_to_UTC(dt):
 | 
						|
    # type: (datetime.datetime) -> datetime.datetime
 | 
						|
    if dt.tzinfo is None:
 | 
						|
        return dt.replace(tzinfo=timezone_utc)
 | 
						|
    return dt.astimezone(timezone_utc)
 | 
						|
 | 
						|
def floor_to_hour(dt):
 | 
						|
    # type: (datetime.datetime) -> datetime.datetime
 | 
						|
    verify_UTC(dt)
 | 
						|
    return datetime.datetime(*dt.timetuple()[:4]) \
 | 
						|
                   .replace(tzinfo=timezone_utc)
 | 
						|
 | 
						|
def floor_to_day(dt):
 | 
						|
    # type: (datetime.datetime) -> datetime.datetime
 | 
						|
    verify_UTC(dt)
 | 
						|
    return datetime.datetime(*dt.timetuple()[:3]) \
 | 
						|
                   .replace(tzinfo=timezone_utc)
 | 
						|
 | 
						|
def ceiling_to_hour(dt):
 | 
						|
    # type: (datetime.datetime) -> datetime.datetime
 | 
						|
    floor = floor_to_hour(dt)
 | 
						|
    if floor == dt:
 | 
						|
        return floor
 | 
						|
    return floor + datetime.timedelta(hours=1)
 | 
						|
 | 
						|
def ceiling_to_day(dt):
 | 
						|
    # type: (datetime.datetime) -> datetime.datetime
 | 
						|
    floor = floor_to_day(dt)
 | 
						|
    if floor == dt:
 | 
						|
        return floor
 | 
						|
    return floor + datetime.timedelta(days=1)
 | 
						|
 | 
						|
def timestamp_to_datetime(timestamp):
 | 
						|
    # type: (float) -> datetime.datetime
 | 
						|
    return datetime.datetime.fromtimestamp(float(timestamp), tz=timezone_utc)
 | 
						|
 | 
						|
def datetime_to_timestamp(dt):
 | 
						|
    # type: (datetime.datetime) -> int
 | 
						|
    verify_UTC(dt)
 | 
						|
    return calendar.timegm(dt.timetuple())
 |