+def is_timezone_aware(dt: datetime.datetime) -> bool:
+ """See: https://docs.python.org/3/library/datetime.html
+ #determining-if-an-object-is-aware-or-naive
+
+ >>> is_timezone_aware(datetime.datetime.now())
+ False
+
+ >>> is_timezone_aware(now_pacific())
+ True
+
+ """
+ return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
+
+
+def is_timezone_naive(dt: datetime.datetime) -> bool:
+ """Inverse of is_timezone_aware.
+
+ >>> is_timezone_naive(datetime.datetime.now())
+ True
+
+ >>> is_timezone_naive(now_pacific())
+ False
+
+ """
+ return not is_timezone_aware(dt)
+
+
+def strip_timezone(dt: datetime.datetime) -> datetime.datetime:
+ """Remove the timezone from a datetime. Does not change the
+ hours, minutes, seconds, months, days, years, etc... Thus the
+ instant to which this timestamp refers will change. Silently
+ ignores datetimes which are already timezone naive.
+
+ >>> now = now_pacific()
+ >>> now.tzinfo == None
+ False
+
+ >>> dt = strip_timezone(now)
+ >>> dt == now
+ False
+
+ >>> dt.tzinfo == None
+ True
+
+ >>> dt.hour == now.hour
+ True
+
+ """
+ if is_timezone_naive(dt):
+ return dt
+ return replace_timezone(dt, None)
+
+
+def add_timezone(dt: datetime.datetime, tz: datetime.tzinfo) -> datetime.datetime:
+ """
+ Adds a timezone to a timezone naive datetime. This does not
+ change the instant to which the timestamp refers. See also:
+ replace_timezone.
+
+ >>> now = datetime.datetime.now()
+ >>> is_timezone_aware(now)
+ False
+
+ >>> now_pacific = add_timezone(now, pytz.timezone('US/Pacific'))
+ >>> is_timezone_aware(now_pacific)
+ True
+
+ >>> now.hour == now_pacific.hour
+ True
+ >>> now.minute == now_pacific.minute
+ True
+