我一直在阅读有关在Python中处理日期时间并将其存储到postgresql中的最佳做法(我尽可能多地使用utc,使用pytz进行转换,避免在datetime构造函数中使用tzinfo参数,等等)。
但是我现在的疑问是,我没有找到有关 datetime.time 对象及其最佳做法的任何信息,我感到很惊讶。
为例,假设我只想存储一个时间,例如20:30,因为我每周计划在该时间的几天进行一些任务,但是一周中的某天可能会每周更改。可能用户已经输入了他/她所在时区的时间。在我的情况下,它将是西班牙时区“欧洲/马德里”的用户。
我的问题是:
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数据库中?一世 知道有时间和timetz数据类型。我想我应该储存 时间为UTC。时区重要吗?我应该以某种方式存储它吗?
答案 0 :(得分:1)
2)[H]现在我可以正确地天真地定位本地时间吗?
datetime.datetime
使用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)如何将一个
datetime.time
对象从时区转换为另一个时区?
请考虑以下情况:我们知道时间为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被“转换”为19:30,但是当日期为CEST时,时间被转换为18:30。 在没有先知道日期的情况下,没有(简单的)答案来回答您的问题。
4a)如何将
datetime.time
存储在postgresql数据库中?我知道有时间和timetz数据类型。
每the docs:
time with time zone
类型是由SQL标准定义的,但是该定义具有的属性会导致有用的疑问。
我认为文档暗示了上面显示的问题。不要使用time with
time zone
。如果要存储时间,请使用PostgreSQL纯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
在给定本地日期时间和特定时区的情况下,可能存在无法代表的日期时间。
上面的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)我想我应该将时间存储为UTC。时区重要吗?我应该以某种方式存储它吗?
由于上述原因,UTC中没有时间(无日期)。 但是,您可以通过简单地将 datetimes 存储在UTC中来避免上述问题。
如果您创建的表的数据类型为timestamptz
,则
您可以使用诸如psycopg2
之类的数据库适配器来存储可识别Python时区的日期时间
作为PostgreSQL timestamptz
。查询数据库时,psycopg2
会将timestamptz
转换为
您知道的时区日期时间。
在内部,PostgreSQL在UTC中存储所有timestamptz
,但它报告有关
PostgreSQL用户的时区设置。在Python方面,给定时区感知日期时间,
您可以使用其astimezone
方法将其转换为所需的任何时区。
除非您要报告,否则无需分别存储时区 相对于不同时区的不同日期时间。
5)如何在不经过日期时间的情况下从字符串中解析时间?
您可以使用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位数字。
或者,第三方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
这里有很多要消化的东西,可能还有更多要说的 关于这些问题。将来,您可能需要将帖子拆分为 多个问题。这将降低那些希望 回答一个问题,但不能全部回答,将帮助您更快地获得更多答案。