+def is_timezone_aware(dt: datetime.datetime) -> bool:
+ """Returns true if the datetime argument is timezone aware or
+ False if not.
+
+ See: https://docs.python.org/3/library/datetime.html
+ #determining-if-an-object-is-aware-or-naive
+
+ Args:
+ dt: The datetime object to check
+
+ >>> 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 -- returns true if the dt argument
+ is timezone naive.
+
+ See: https://docs.python.org/3/library/datetime.html
+ #determining-if-an-object-is-aware-or-naive
+
+ Args:
+ dt: The datetime object to check
+
+ >>> 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.
+
+ .. warning::
+
+ This 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
+