diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-11-13 10:49:01 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-11-13 10:49:01 -0500 |
| commit | e345864506346700dc4c21ff21bfc18f2c047831 (patch) | |
| tree | 803be3ff188c475be2a88887236702ac767ba27d /doc/build/core | |
| parent | be2cd2791ea65fb76b193a34752361f1e76d68b2 (diff) | |
| download | sqlalchemy-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.rst | 36 |
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 |
