summaryrefslogtreecommitdiff
path: root/doc/build/core
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2019-11-13 10:49:01 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2019-11-13 10:49:01 -0500
commite345864506346700dc4c21ff21bfc18f2c047831 (patch)
tree803be3ff188c475be2a88887236702ac767ba27d /doc/build/core
parentbe2cd2791ea65fb76b193a34752361f1e76d68b2 (diff)
downloadsqlalchemy-e345864506346700dc4c21ff21bfc18f2c047831.tar.gz
Add TypeDecorator recipe for timezone aware/UTC conversion
Change-Id: I59e6c76a4a53ce3782bcfc4aecdeb1b4fdd7b941 References: https://github.com/sqlalchemy/sqlalchemy/issues/4980
Diffstat (limited to 'doc/build/core')
-rw-r--r--doc/build/core/custom_types.rst36
1 files changed, 36 insertions, 0 deletions
diff --git a/doc/build/core/custom_types.rst b/doc/build/core/custom_types.rst
index 7cccf4e6b..b7d0eef93 100644
--- a/doc/build/core/custom_types.rst
+++ b/doc/build/core/custom_types.rst
@@ -128,6 +128,42 @@ many decimal places. Here's a recipe that rounds them down::
value = value.quantize(self.quantize)
return value
+Store Timezone Aware Timestamps as Timezone Naive UTC
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Timestamps in databases should always be stored in a timezone-agnostic way. For
+most databases, this means ensuring a timestamp is first in the UTC timezone
+before it is stored, then storing it as timezone-naive (that is, without any
+timezone associated with it; UTC is assumed to be the "implicit" timezone).
+Alternatively, database-specific types like PostgreSQLs "TIMESTAMP WITH
+TIMEZONE" are often preferred for their richer functionality; however, storing
+as plain UTC will work on all databases and drivers. When a
+timezone-intelligent database type is not an option or is not preferred, the
+:class:`.TypeDecorator` can be used to create a datatype that convert timezone
+aware timestamps into timezone naive and back again. Below, Python's
+built-in ``datetime.timezone.utc`` timezone is used to normalize and
+denormalize::
+
+ import datetime
+
+ class TZDateTime(TypeDecorator):
+ impl = DateTime
+
+ def process_bind_param(self, value, dialect):
+ if value is not None:
+ if not value.tzinfo:
+ raise TypeError("tzinfo is required")
+ value = value.astimezone(datetime.timezone.utc).replace(
+ tzinfo=None
+ )
+ return value
+
+ def process_result_value(self, value, dialect):
+ if value is not None:
+ value = value.replace(tzinfo=datetime.timezone.utc)
+ return value
+
+
.. _custom_guid_type:
Backend-agnostic GUID Type