Skip to content

Instantly share code, notes, and snippets.

@AlmightyOatmeal
Last active May 8, 2018 23:02
Show Gist options
  • Save AlmightyOatmeal/6f7c0adbc0e089e3bc24f165ead2d61f to your computer and use it in GitHub Desktop.
Save AlmightyOatmeal/6f7c0adbc0e089e3bc24f165ead2d61f to your computer and use it in GitHub Desktop.
Fun with Python datetime objects! Works on Python 2.7.x.
import datetime
import pytz
def convert_dt_to_milliseconds(dt_obj):
"""Convert datetime object to a Unix epoch timestamp in milliseconds.
:param dt_obj: Datetime object to be converted.
:type dt_obj: instance
:return: Milliseconds since the Unix epoch.
:rtype: int or long
"""
return int((dt_obj - datetime.datetime(1970, 1, 1)).total_seconds() * 1000)
def convert_utc_milliseconds_to_dt(utc_ms):
"""Convert Unix epoch timestamp in milliseconds to a datetime object.
:param utc_ms: Timestamp in milliseconds.
:type utc_ms: int or long
:return: Datetime.datetime() instance.
:rtype: instance
"""
return pytz.utc.localize(datetime.datetime.utcfromtimestamp(utc_ms / 1000))
def get_utcnow_in_milliseconds():
"""Get the current UTC time and convert it to a Unix epoch timestamp in milliseconds.
:return: Milliseconds since the Unix epoch.
:rtype: int or long
"""
return int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds() * 1000)
def get_utcnow_date_str(datetime_obj=None):
"""Get the date in ISO format.
:param datetime_obj: (optional) If specified, returns the ISO format of the `datetime` instance.
(default: None)
:type datetime_obj: datetime.datetime, datetime.date
:return: Date string.
:rtype: str
"""
if datetime_obj is None:
datetime_obj = datetime.datetime.utcnow()
return datetime_obj.date().isoformat()
def convert_local_dt_to_utc_dt(local_dt):
"""Convert local `datetime.datetime` instance to UTC.
:param local_dt: Local `datetime.datetime` instance.
:type local_dt: datetime.datetime
:return: UTC `datetime.datetime` instance.
:rtype: datetime.datetime
"""
if time.daylight:
offset = time.altzone / 3600
else:
offset = time.timezone / 3600
return local_dt + datetime.timedelta(hours=offset)
def datetime_utc_to_timezone_traverse(obj, path=None, callback=None, convert_to_tz=None):
"""Recursively looks for a key in a dictionary and returns the value, if found.
convert_to_tz='US/Pacific'
:param obj: Dictionary to iterate through.
:return: Result or None.
:rtype: str, unicode, int, float, long, or NoneType
"""
# TODO: Fix this docstring.
if path is None:
path = []
if isinstance(obj, dict):
value = {k: datetime_utc_to_timezone_traverse(v, path + [k], callback, convert_to_tz) for k, v in obj.items()}
elif isinstance(obj, (list, set)):
value = [datetime_utc_to_timezone_traverse(elem, path + [[]], callback, convert_to_tz) for elem in obj]
elif isinstance(obj, (datetime.datetime, datetime.time)):
# value = obj.replace(tzinfo=pytz.utc)
# TODO: Add checking to see if a timezone is already set then localize if not else obj.astimezone(...)
# value = pytz.utc.localize(obj).astimezone(pytz.timezone(convert_to_tz))
value = obj.astimezone(pytz.timezone(convert_to_tz))
else:
value = obj
if callback is None: # if a callback is provided, call it to get the new value
return value
else:
return callback(path, value)
def timestamp_to_str_traverse(obj, path=None, callback=None):
"""Recursively looks for datetime objects and converts them to ISO formatted strings.
:param obj: Dictionary to iterate through.
:param key: Key to look for.
:return: Result or None.
:rtype: str, unicode, int, float, long, or NoneType
"""
# TODO: Fix this docstring.
if path is None:
path = []
if isinstance(obj, dict):
value = {k: timestamp_to_str_traverse(v, path + [k], callback) for k, v in obj.items()}
elif isinstance(obj, (list, set)):
value = [timestamp_to_str_traverse(elem, path + [[]], callback) for elem in obj]
else:
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
obj.isoformat()
else:
value = obj
if callback is None: # if a callback is provided, call it to get the new value
return value
else:
return callback(path, value)
# Thanks ZenDesk -- Convert "2016-10-10T14:21:54Z" to datetime object.
import re
regex_timestamp_zendesk = re.compile('^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[A-Za-z]+$')
regex_timestamp_iso = re.compile('^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$')
regex_timestamp_iso_tz = re.compile('^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.{0,1}[0-9]*[+\-][0-9]{2}:?[0-9]{2}$')
regex_timestamp_ms = re.compile('\.\d+')
def timestamp_to_datetime_traverse(obj, path=None, callback=None, convert_to_tz=None):
"""Recursively looks for a key in a dictionary and returns the value, if found.
convert_to_tz='US/Pacific'
:param obj: Dictionary to iterate through.
:param key: Key to look for.
:return: Result or None.
:rtype: str, unicode, int, float, long, or NoneType
"""
# TODO: Fix this docstring.
if path is None:
path = []
if isinstance(obj, dict):
value = {k: timestamp_to_datetime_traverse(v, path + [k], callback, convert_to_tz) for k, v in obj.items()}
elif isinstance(obj, (list, set)):
value = [timestamp_to_datetime_traverse(elem, path + [[]], callback, convert_to_tz) for elem in obj]
else:
if isinstance(obj, (str, unicode)):
# Convert '2017-10-04T21:09:43.717000Z' to '2017-10-04T21:09:43Z'
if '.' in obj and obj.endswith('Z'):
obj_split = obj.split('.')
obj = '{}Z'.format(obj_split[0])
if regex_timestamp_zendesk.match(obj):
value = pytz.utc.localize(datetime.datetime.strptime(obj, '%Y-%m-%dT%H:%M:%SZ'))
if convert_to_tz:
value = value.astimezone(pytz.timezone(convert_to_tz))
elif regex_timestamp_iso.match(obj):
value = pytz.utc.localize(datetime.datetime.strptime(obj, '%Y-%m-%dT%H:%M:%S'))
if convert_to_tz:
value = value.astimezone(pytz.timezone(convert_to_tz))
elif regex_timestamp_iso_tz.match(obj):
# The Python 2 strptime() function indeed does not the support %z format for timezones
# (because the underlying time.strptime() function doesn't support it) so skip it.
# TODO: Add support for determining the timezone just in-case some wise-ass isn't using UTC...
if obj.endswith('00:00'):
value = pytz.utc.localize(datetime.datetime.strptime(obj[:19], '%Y-%m-%dT%H:%M:%S'))
if convert_to_tz:
value = value.astimezone(pytz.timezone(convert_to_tz))
elif obj.endswith(':00'):
# obj = re.sub('\.\d+', '', obj)
obj = regex_timestamp_ms.sub('', obj)
# THIS SHOULD REMEDY THE TO-DO FROM ABOVE...
ret = datetime.datetime.strptime(obj[0:18], '%Y-%m-%dT%H:%M:%S')
if obj[19] == '+':
ret -= datetime.timedelta(hours=int(obj[20:22]), minutes=int(obj[23:]))
elif obj[19] == '-':
ret += datetime.timedelta(hours=int(obj[20:22]), minutes=int(obj[23:]))
value = pytz.utc.localize(ret)
if convert_to_tz:
value = value.astimezone(pytz.timezone(convert_to_tz))
else:
value = pytz.utc.localize(datetime.datetime.strptime(obj, '%Y-%m-%dT%H:%M:%SZ'))
if convert_to_tz:
value = value.astimezone(pytz.timezone(convert_to_tz))
else:
value = obj
else:
value = obj
if callback is None: # if a callback is provided, call it to get the new value
return value
else:
return callback(path, value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment