我应该如何使用 python3 在 postgresql 中存储带时区的时间?
How should I store times with timezones in postgresql using python3?
我一直在阅读有关在 Python 中处理日期时间并将它们存储到 postgresql 中的最佳实践(尽可能多地使用 utc,使用 pytz 进行转换,避免 datetime 构造函数中的 tzinfo 参数,等等...).
但我现在的疑问是,我很惊讶没有找到任何关于 datetime.time 对象及其最佳实践的信息。
举个例子,假设我只想存储一个时间,比如 20:30,因为我每周都会在那个时间的几天安排一些任务,但是一周中的那一天每周都可以改变。并且可能用户输入了 his/her 时区的时间。在我的情况下,它将是西班牙时区 'Europe/Madrid'.
的用户
我的问题是:
1) 一旦我得到时间作为 datetime.time,我应该如何存储
时区信息到 datetime.time 变量中。可以用吗
datetime.time(h, m, s, ms, tzinfo=pytz_spanish_timezone)
???
2) 如果不是前者
代码行,我如何正确地本地化一个天真的时间? datetime.datetime 使用
my_datetime.localize(pytz_spanish_timezone)
3) 如何将一个 datetime.time 对象从时区转换为
另一个,考虑到 datetime 和 pytz 它将使用
new_tz_datetime = my_datetime.astimezone(pytz_spanish_timezone)
但随着时间的推移没有类似的方法
4) 我应该如何将 datetime.time 存储在 postgresql 数据库中?我
知道有 time 和 timetz 数据类型。我想我应该存储
时间为 UTC。时区重要吗?我应该以某种方式存储它吗?
- 5) 如何在不通过日期时间的情况下从字符串中解析时间? (我已经让自己成为一个函数,但我确信一定存在某种使用 datetime 的方法或一些可能涵盖我不具备的情况的强大模块)。
2) [H]ow do I localize properly a naive time? datetime.datetime
uses my_datetime.localize(pytz_spanish_timezone)
其实恰恰相反。 localize
是 pytz 时区方法,而不是 datetime
方法:
import pytz
madrid = pytz.timezone('Europe/Madrid')
aware_datetime = madrid.localize(naive_datetime)
这里需要 datetime.datetime
。 datetime.time
对象没有等效项。原因见下文。
3) How do I convert one datetime.time
object from a timezone to another?
考虑以下情况:我们知道时间是 20:30,时区是 Europe/Madrid
,我们希望将其转换为 UTC。
根据日期是否属于夏令时 (CEST) 或不属于 (CET),结果会有所不同:
例如,
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
utc = pytz.utc
CET_date = madrid.localize(DT.datetime(2019, 3, 30, 20, 30, 0), is_dst=None)
# the most recent transition occurred at `2019-03-31 02:00:00+01:00 CEST`
CEST_date = madrid.localize(DT.datetime(2019, 3, 31, 20, 30, 0), is_dst=None)
print(CET_date.astimezone(utc))
print(CEST_date.astimezone(utc))
# 2019-03-30 19:30:00+00:00
# 2019-03-31 18:30:00+00:00
注意当日期是CET时,时间20:30是"converted"到19:30,但是当日期是CEST时,时间被转换成18:30.
如果不知道日期,就无法(简单)回答您的问题。
4a) How should I store the datetime.time
in postgresql database? I know there are time and timetz data types.
根据 the docs:
The type time with time zone
is defined by the SQL standard, but the definition exhibits properties which lead to questionable usefulness.
我认为文档暗示了上面显示的问题。不要使用 time with
time zone
。如果要存储时间,请使用 PostgreSQL plain time
类型。
您可以将 time
和 timezone
存储在数据库中,然后重新构造
约会后的时区感知日期时间。但请注意,有
陷阱:
本地日期时间不明确
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=None)
加注 pytz.exceptions.AmbiguousTimeError: 2019-10-27 02:00:00
。
要避免 AmbiguousTimeError
,必须明确指定 is_dst
:
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=False)
print(date)
date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=True)
print(date)
# 2019-10-27 02:00:00+01:00
# 2019-10-27 02:00:00+02:00
不存在本地日期时间
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=None)
加注pytz.exceptions.NonExistentTimeError: 2019-03-31 02:00:00
您可以通过指定本地时间是否指 DST(夏令时)期间的时间来避免 NonExistentTimeError:
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
date = madrid.normalize(madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=False))
print(date)
date = madrid.normalize(madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=True))
print(date)
# 2019-03-31 03:00:00+02:00
# 2019-03-31 01:00:00+01:00
在给定本地日期时间和特定时区的情况下,可能存在无法表示的日期时间table。
上面的AmbiguousTimeError
和NonExistentTimeError
说明了指定is_dst
值的重要性。
为避免这些错误,您需要在数据库中存储布尔值 is_dst
以及 time
和 timezone
。
您可能认为只要选择一个值就可以避免这个问题
is_dst
所有时间。但你会错的。这是一个特殊的例子
(取自 the pytz docs)如果你
始终选择 is_dst = False
(或 is_dst = True
)可以有 UTC 日期时间
这不能只给定一个天真的本地时间和一个时区来表达!
import datetime as DT
import pytz
warsaw = pytz.timezone('Europe/Warsaw')
utc = pytz.utc
date1 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 35, 59), is_dst=False).astimezone(utc)
date2 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 36, 0), is_dst=False).astimezone(utc)
print('Datetimes between {} and {} can not be expressed if we assume is_dist=False.'.format(date1, date2))
date3 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 59, 59), is_dst=True).astimezone(utc)
date4 = warsaw.localize(DT.datetime(1915, 8, 5, 0, 0, 0), is_dst=True).astimezone(utc)
print('Datetimes between {} and {} can not be expressed if we assume is_dist=True.'.format(date1, date2))
打印
Datetimes between 1915-08-04 22:11:59+00:00 and 1915-08-04 22:36:00+00:00 can not be expressed if we assume is_dist=False.
Datetimes between 1915-08-04 22:11:59+00:00 and 1915-08-04 22:36:00+00:00 can not be expressed if we assume is_dist=True.
4b) I suppose I should store the time as UTC. Would the timezone matter? Should I store it somehow?
由于上述原因,UTC 中没有时间(没有日期)这样的东西。
但是您可以通过简单地在 UTC 中存储 datetimes 来避免上述问题。
如果您创建一个 table 并且列的数据类型为 timestamptz
,则
您可以使用 psycopg2
等数据库适配器来存储 Python 时区感知日期时间
作为 PostgreSQL timestamptz
s。当您查询数据库时,psycopg2
会将 timestamptz
转换回
为您提供时区感知日期时间。
在内部,PostgreSQL 以 UTC 格式存储所有 timestamptz
s,但它报告的值是关于
PostgreSQL 用户的时区设置。在 Python 方面,给定一个时区感知日期时间,
您可以使用其 astimezone
方法将其转换为您喜欢的任何时区。
除非你想报告,否则你不需要单独存储时区
不同时区的不同日期时间。
5) How to parse a time from a string without going through datetime?
您可以使用 regex 来解析时间字符串:
import re
import datetime as DT
atime = DT.time(*map(int, re.search(r'(\d{,2}):(\d{,2}):(\d{,2})', 'blueberry jam at 13:32:02').groups()))
print(repr(atime))
# datetime.time(13, 32, 2)
上面,正则表达式模式 \d
匹配单个数字。 \d{1,2}
匹配 1 或 2 个数字。
或者,第 3 方 dateutil package 可以解析
多种格式的时间字符串:
import dateutil.parser as DP
print(DP.parse("13:32:02").time())
# 13:32:02
print(DP.parse("blueberry jam at 13:32:02", fuzzy=True).time())
# 13:32:02
print(DP.parse("30 minutes 12 hours").time())
# 12:30:00
print(DP.parse("2:30pm").time())
# 14:30:00
这里有很多东西要消化,可能还有更多可以说的
关于这些问题中的每一个。将来,您可能希望将 post 拆分为
多个问题。这将降低那些可能希望
回答一个问题而不是全部问题,将帮助您更快地获得更多答案。
我一直在阅读有关在 Python 中处理日期时间并将它们存储到 postgresql 中的最佳实践(尽可能多地使用 utc,使用 pytz 进行转换,避免 datetime 构造函数中的 tzinfo 参数,等等...).
但我现在的疑问是,我很惊讶没有找到任何关于 datetime.time 对象及其最佳实践的信息。
举个例子,假设我只想存储一个时间,比如 20:30,因为我每周都会在那个时间的几天安排一些任务,但是一周中的那一天每周都可以改变。并且可能用户输入了 his/her 时区的时间。在我的情况下,它将是西班牙时区 'Europe/Madrid'.
的用户我的问题是:
1) 一旦我得到时间作为 datetime.time,我应该如何存储 时区信息到 datetime.time 变量中。可以用吗
datetime.time(h, m, s, ms, tzinfo=pytz_spanish_timezone)
???2) 如果不是前者 代码行,我如何正确地本地化一个天真的时间? datetime.datetime 使用
my_datetime.localize(pytz_spanish_timezone)
3) 如何将一个 datetime.time 对象从时区转换为 另一个,考虑到 datetime 和 pytz 它将使用
new_tz_datetime = my_datetime.astimezone(pytz_spanish_timezone)
但随着时间的推移没有类似的方法
4) 我应该如何将 datetime.time 存储在 postgresql 数据库中?我 知道有 time 和 timetz 数据类型。我想我应该存储 时间为 UTC。时区重要吗?我应该以某种方式存储它吗?
- 5) 如何在不通过日期时间的情况下从字符串中解析时间? (我已经让自己成为一个函数,但我确信一定存在某种使用 datetime 的方法或一些可能涵盖我不具备的情况的强大模块)。
2) [H]ow do I localize properly a naive time?
datetime.datetime
usesmy_datetime.localize(pytz_spanish_timezone)
其实恰恰相反。 localize
是 pytz 时区方法,而不是 datetime
方法:
import pytz
madrid = pytz.timezone('Europe/Madrid')
aware_datetime = madrid.localize(naive_datetime)
这里需要 datetime.datetime
。 datetime.time
对象没有等效项。原因见下文。
3) How do I convert one
datetime.time
object from a timezone to another?
考虑以下情况:我们知道时间是 20:30,时区是 Europe/Madrid
,我们希望将其转换为 UTC。
根据日期是否属于夏令时 (CEST) 或不属于 (CET),结果会有所不同:
例如,
import datetime as DT
import pytz
madrid = pytz.timezone('Europe/Madrid')
utc = pytz.utc
CET_date = madrid.localize(DT.datetime(2019, 3, 30, 20, 30, 0), is_dst=None)
# the most recent transition occurred at `2019-03-31 02:00:00+01:00 CEST`
CEST_date = madrid.localize(DT.datetime(2019, 3, 31, 20, 30, 0), is_dst=None)
print(CET_date.astimezone(utc))
print(CEST_date.astimezone(utc))
# 2019-03-30 19:30:00+00:00
# 2019-03-31 18:30:00+00:00
注意当日期是CET时,时间20:30是"converted"到19:30,但是当日期是CEST时,时间被转换成18:30. 如果不知道日期,就无法(简单)回答您的问题。
4a) How should I store the
datetime.time
in postgresql database? I know there are time and timetz data types.
根据 the docs:
The type
time with time zone
is defined by the SQL standard, but the definition exhibits properties which lead to questionable usefulness.
我认为文档暗示了上面显示的问题。不要使用 time with
time zone
。如果要存储时间,请使用 PostgreSQL plain time
类型。
您可以将 time
和 timezone
存储在数据库中,然后重新构造
约会后的时区感知日期时间。但请注意,有
陷阱:
本地日期时间不明确
import datetime as DT import pytz madrid = pytz.timezone('Europe/Madrid') date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=None)
加注
pytz.exceptions.AmbiguousTimeError: 2019-10-27 02:00:00
。 要避免AmbiguousTimeError
,必须明确指定is_dst
:import datetime as DT import pytz madrid = pytz.timezone('Europe/Madrid') date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=False) print(date) date = madrid.localize(DT.datetime(2019, 10, 27, 2, 0, 0), is_dst=True) print(date) # 2019-10-27 02:00:00+01:00 # 2019-10-27 02:00:00+02:00
不存在本地日期时间
import datetime as DT import pytz madrid = pytz.timezone('Europe/Madrid') madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=None)
加注
pytz.exceptions.NonExistentTimeError: 2019-03-31 02:00:00
您可以通过指定本地时间是否指 DST(夏令时)期间的时间来避免 NonExistentTimeError:
import datetime as DT import pytz madrid = pytz.timezone('Europe/Madrid') date = madrid.normalize(madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=False)) print(date) date = madrid.normalize(madrid.localize(DT.datetime(2019, 3, 31, 2, 0, 0), is_dst=True)) print(date) # 2019-03-31 03:00:00+02:00 # 2019-03-31 01:00:00+01:00
在给定本地日期时间和特定时区的情况下,可能存在无法表示的日期时间table。
上面的
AmbiguousTimeError
和NonExistentTimeError
说明了指定is_dst
值的重要性。 为避免这些错误,您需要在数据库中存储布尔值is_dst
以及time
和timezone
。您可能认为只要选择一个值就可以避免这个问题
is_dst
所有时间。但你会错的。这是一个特殊的例子 (取自 the pytz docs)如果你 始终选择is_dst = False
(或is_dst = True
)可以有 UTC 日期时间 这不能只给定一个天真的本地时间和一个时区来表达!import datetime as DT import pytz warsaw = pytz.timezone('Europe/Warsaw') utc = pytz.utc date1 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 35, 59), is_dst=False).astimezone(utc) date2 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 36, 0), is_dst=False).astimezone(utc) print('Datetimes between {} and {} can not be expressed if we assume is_dist=False.'.format(date1, date2)) date3 = warsaw.localize(DT.datetime(1915, 8, 4, 23, 59, 59), is_dst=True).astimezone(utc) date4 = warsaw.localize(DT.datetime(1915, 8, 5, 0, 0, 0), is_dst=True).astimezone(utc) print('Datetimes between {} and {} can not be expressed if we assume is_dist=True.'.format(date1, date2))
打印
Datetimes between 1915-08-04 22:11:59+00:00 and 1915-08-04 22:36:00+00:00 can not be expressed if we assume is_dist=False. Datetimes between 1915-08-04 22:11:59+00:00 and 1915-08-04 22:36:00+00:00 can not be expressed if we assume is_dist=True.
4b) I suppose I should store the time as UTC. Would the timezone matter? Should I store it somehow?
由于上述原因,UTC 中没有时间(没有日期)这样的东西。 但是您可以通过简单地在 UTC 中存储 datetimes 来避免上述问题。
如果您创建一个 table 并且列的数据类型为 timestamptz
,则
您可以使用 psycopg2
等数据库适配器来存储 Python 时区感知日期时间
作为 PostgreSQL timestamptz
s。当您查询数据库时,psycopg2
会将 timestamptz
转换回
为您提供时区感知日期时间。
在内部,PostgreSQL 以 UTC 格式存储所有 timestamptz
s,但它报告的值是关于
PostgreSQL 用户的时区设置。在 Python 方面,给定一个时区感知日期时间,
您可以使用其 astimezone
方法将其转换为您喜欢的任何时区。
除非你想报告,否则你不需要单独存储时区 不同时区的不同日期时间。
5) How to parse a time from a string without going through datetime?
您可以使用 regex 来解析时间字符串:
import re
import datetime as DT
atime = DT.time(*map(int, re.search(r'(\d{,2}):(\d{,2}):(\d{,2})', 'blueberry jam at 13:32:02').groups()))
print(repr(atime))
# datetime.time(13, 32, 2)
上面,正则表达式模式 \d
匹配单个数字。 \d{1,2}
匹配 1 或 2 个数字。
或者,第 3 方 dateutil package 可以解析 多种格式的时间字符串:
import dateutil.parser as DP
print(DP.parse("13:32:02").time())
# 13:32:02
print(DP.parse("blueberry jam at 13:32:02", fuzzy=True).time())
# 13:32:02
print(DP.parse("30 minutes 12 hours").time())
# 12:30:00
print(DP.parse("2:30pm").time())
# 14:30:00
这里有很多东西要消化,可能还有更多可以说的 关于这些问题中的每一个。将来,您可能希望将 post 拆分为 多个问题。这将降低那些可能希望 回答一个问题而不是全部问题,将帮助您更快地获得更多答案。