将 UTC 日期时间字符串转换为本地日期时间
- 2024-12-17 08:30:00
- admin 原创
- 158
问题描述:
我从未需要将时间转换为 UTC 或从 UTC 转换为 UTC。最近有人要求我的应用能够识别时区,但我一直都不知道该怎么做。关于将本地时间转换为 UTC 的信息很多,我觉得这相当基础(也许我做错了),但我找不到任何关于如何轻松地将 UTC 时间转换为最终用户时区的信息。
简而言之,android 应用程序向我发送(appengine 应用程序)数据,并且该数据中包含一个时间戳。为了将该时间戳存储为 utc 时间,我使用:
datetime.utcfromtimestamp(timestamp)
这似乎有效。当我的应用存储数据时,它会被存储为提前 5 小时的数据(我的是 EST -5)
数据存储在 appengine 的 BigTable 中,检索时会以字符串形式显示,如下所示:
"2011-01-21 02:37:21"
如何将此字符串转换为用户正确时区的 DateTime?
另外,建议如何存储用户的时区信息?(您通常如何存储 tz 信息,即:“-5:00”或“EST”等等?)我确信我的第一个问题的答案可能包含一个回答第二个问题的参数。
解决方案 1:
如果您不想提供自己的tzinfo
对象,请查看python-dateutil库。它tzinfo
在zoneinfo (Olson) 数据库之上提供实现,以便您可以通过一个有点规范的名称来引用时区规则。
from datetime import datetime
from dateutil import tz
# METHOD 1: Hardcode zones:
from_zone = tz.gettz('UTC')
to_zone = tz.gettz('America/New_York')
# METHOD 2: Auto-detect zones:
from_zone = tz.tzutc()
to_zone = tz.tzlocal()
# Since datetime.utcnow() is deprecated since version 3.12 use datetime.now()
# utc = datetime.now()
utc = datetime.strptime('2011-01-21 02:37:21', '%Y-%m-%d %H:%M:%S')
# Tell the datetime object that it's in UTC time zone since
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)
# Convert time zone
central = utc.astimezone(to_zone)
编辑扩展示例以显示strptime
用法
编辑 2修复 API 使用问题,以显示更好的入口点方法
编辑 3包含时区自动检测方法(Yarin)
解决方案 2:
这是一种不依赖任何外部库的弹性方法:
from datetime import datetime
import time
def datetime_from_utc_to_local(utc_datetime):
now_timestamp = time.time()
offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
return utc_datetime + offset
这避免了 DelboyJay 示例中的时间问题。以及 Erik van Oosten 修正案中较小的时间问题。
有趣的是,上面计算的时区偏移量可能与以下看似等效的表达式不同,这可能是由于夏令时规则的变化:
offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!
更新:此代码片段的缺点是使用当前时间的 UTC 偏移量,这可能与输入日期时间的 UTC 偏移量不同。请参阅此答案的评论以了解另一种解决方案。
为了解决不同的时间问题,请从传入的时间中获取纪元时间。这是我所做的:
def utc2local(utc):
epoch = time.mktime(utc.timetuple())
offset = datetime.fromtimestamp(epoch) - datetime.utcfromtimestamp(epoch)
return utc + offset
解决方案 3:
已更新为最新的 Python 3 支持(请参阅旧答案的编辑历史):
从 Python 3.9 开始,内置zoneinfo
库中提供了时区信息:
该模块提供了具体的时区实现,以支持PEP 615
zoneinfo
中最初指定的 IANA 时区数据库。默认情况下,如果可用,则使用系统的时区数据;如果没有可用的系统时区数据,则库将回退到使用 PyPI 上可用的第一方包。zoneinfo
`tzdata`
请参阅zoneinfo.available_timezones()
时区名称列表。
这是一个简单的例子:
# "pip install -U tzdata" for latest zone support required on some OSes
import datetime as dt
import zoneinfo as zi
GMT = zi.ZoneInfo('GMT')
ExT = zi.ZoneInfo('US/Eastern')
print(dt.datetime.now(tz=GMT).strftime('%m/%d/%Y %H:%M:%S %Z'))
print(dt.datetime.now(tz=ExT).strftime('%m/%d/%Y %H:%M:%S %Z'))
t = dt.datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S')
t = t.replace(tzinfo=GMT)
print(t)
print(t.astimezone(ExT))
# Preferred way now instead of utcfromtimestamp().
# See https://docs.python.org/3/library/datetime.html#datetime.datetime.utcfromtimestamp.
d = dt.datetime.fromtimestamp(1714365725, tz=dt.UTC) # time zone-aware
# Formatting in different zones
print(d.strftime('%Y-%m-%d %I:%M:%S %p %Z'))
print(d.astimezone(ExT).strftime('%Y-%m-%d %I:%M:%S %p %Z'))
print(d.astimezone(zi.ZoneInfo('US/Pacific')).strftime('%Y-%m-%d %I:%M:%S %p %Z'))
输出:
04/29/2024 04:46:19 GMT
04/29/2024 00:46:19 EDT
2011-01-21 02:37:21+00:00
2011-01-20 21:37:21-05:00
2024-04-29 04:42:05 AM UTC
2024-04-29 12:42:05 AM EDT
2024-04-28 09:42:05 PM PDT
解决方案 4:
如果您想要获得正确的结果,即使对于对应于模糊的本地时间(例如,在 DST 转换期间)的时间和/或本地 utc 偏移量在您本地时区的不同时间不同,请使用pytz
时区:
#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz
import tzlocal # $ pip install tzlocal
local_timezone = tzlocal.get_localzone() # get pytz tzinfo
utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone)
解决方案 5:
如果您不想使用除此之外的任何其他模块,这个答案应该会有所帮助datetime
。
datetime.utcfromtimestamp(timestamp)
返回一个简单datetime
对象(不是感知对象)。感知对象可以感知时区,简单对象则不能。如果您想在时区之间进行转换(例如在 UTC 和本地时间之间),则需要一个感知对象。
如果您不是首先实例化日期的人,但仍然可以datetime
在 UTC 时间中创建一个简单对象,则可能需要尝试使用此 Python 3.x 代码进行转换:
import datetime
d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object
d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time.
d=d.astimezone() #Convert it to your local timezone (still aware)
print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choice
请注意不要误以为,如果您的时区当前为 MDT,则夏令时不适用于上述代码,因为它会打印 MST。您会注意到,如果您将月份更改为 8 月,它会打印 MDT。
获取感知datetime
对象的另一种简单方法(在 Python 3.x 中也是如此)是在创建时指定时区。以下是使用 UTC 的示例:
import datetime, sys
aware_utc_dt_obj=datetime.datetime.now(datetime.timezone.utc) #create an aware datetime object
dt_obj_local=aware_utc_dt_obj.astimezone() #convert it to local time
#The following section is just code for a directive I made that I liked.
if sys.platform=="win32":
directive="%#d %b %Y (%#I:%M:%S:%f %p) %Z"
else:
directive="%-d %b %Y (%-I:%M:%S:%f %p) %Z"
print(dt_obj_local.strftime(directive))
如果您使用 Python 2.x,您可能必须进行子类化datetime.tzinfo
并使用它来帮助您创建一个感知datetime
对象,因为datetime.timezone
在 Python 2.x 中不存在。
解决方案 6:
如果使用Django,可以使用该timezone.localtime
方法:
from django.utils import timezone
date
# datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>)
timezone.localtime(date)
# datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)
解决方案 7:
以下内容在美国西部的云环境中对我有用:
import datetime
import pytz
#set the timezone
tzInfo = pytz.timezone('America/Los_Angeles')
dt = datetime.datetime.now(tz=tzInfo)
print(dt)
解决方案 8:
将franksands的答案整合成一种方便的方法。
import calendar
import datetime
def to_local_datetime(utc_dt):
"""
convert from utc datetime to a locally aware datetime according to the host timezone
:param utc_dt: utc datetime
:return: local timezone datetime
"""
return datetime.datetime.fromtimestamp(calendar.timegm(utc_dt.timetuple()))
解决方案 9:
您可以使用箭头
from datetime import datetime
import arrow
now = datetime.utcnow()
print(arrow.get(now).to('local').format())
# '2018-04-04 15:59:24+02:00'
你可以输入arrow.get()
任何东西。时间戳、iso 字符串等
解决方案 10:
从这里的答案中,您可以使用时间模块将 utc 转换为计算机中设置的本地时间:
utc_time = time.strptime("2018-12-13T10:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
utc_seconds = calendar.timegm(utc_time)
local_time = time.localtime(utc_seconds)
解决方案 11:
这对我有用:
from django.utils import timezone
from datetime import timedelta,datetime
ist_time = timezone.now() + timedelta(hours=5,minutes=30)
#second method
ist_time = datetime.now() + timedelta(hours=5,minutes=30)
解决方案 12:
您可以使用calendar.timegm
将时间转换为自 Unix 纪元以来的秒数,然后time.localtime
转换回来:
import calendar
import time
time_tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
t = calendar.timegm(time_tuple)
print time.ctime(t)
给予Fri Jan 21 05:37:21 2011
(因为我处于 UTC+03:00 时区)。
解决方案 13:
import datetime
def utc_str_to_local_str(utc_str: str, utc_format: str, local_format: str):
"""
:param utc_str: UTC time string
:param utc_format: format of UTC time string
:param local_format: format of local time string
:return: local time string
"""
temp1 = datetime.datetime.strptime(utc_str, utc_format)
temp2 = temp1.replace(tzinfo=datetime.timezone.utc)
local_time = temp2.astimezone()
return local_time.strftime(local_format)
utc_tz_example_str = '2018-10-17T00:00:00.111Z'
utc_fmt = '%Y-%m-%dT%H:%M:%S.%fZ'
local_fmt = '%Y-%m-%dT%H:%M:%S+08:00'
# call my function here
local_tz_str = utc_str_to_local_str(utc_tz_example_str, utc_fmt, local_fmt)
print(local_tz_str) # 2018-10-17T08:00:00+08:00
当我输入utc_tz_example_str
= 2018-10-17T00:00:00.111Z,(UTC +00:00)
时,我将得到local_tz_str
= 2018-10-17T08:00:00+08:00 (我的目标时区+08:00)
参数utc_format
是你具体确定的格式utc_tz_example_str
。
参数local_fmt
是最终想要的格式。
就我而言,我想要的格式是%Y-%m-%dT%H:%M:%S+08:00
(+08:00 时区)。您应该构建所需的格式。
解决方案 14:
我传统上将其推迟到前端 - 从后端发送时间作为时间戳或 UTC 中的其他日期时间格式,然后让客户端找出时区偏移量并在适当的时区中呈现该数据。
对于 web 应用程序来说,这在 javascript 中很容易实现——您可以使用内置方法轻松找出浏览器的时区偏移量,然后正确地从后端呈现数据。
解决方案 15:
首先确保您的计算机/服务器具有正确的时区,有时您可能会看到正确的时间,但使用错误的时区,因为系统根据互联网调整时间。
这是我的工作代码,允许时区自动检测并支持 DST 时区:
from datetime import datetime, timedelta
def datetime_from_utc_to_local(utc_string ): #"2023-09-30T17:49:06.000Z"
# Extract the offset from the input string, assuming it's always in the format "-HHMM"
local_offset_str = datetime.now().astimezone().isoformat(timespec="seconds")[-6:]
# Convert the offset string to an integer representing hours an minutes
offset_hours = int(local_offset_str[:3])
offset_minutes = int(local_offset_str[4:])
# Create a datetime object from the input string, excluding the "Z" character
utc_datetime = datetime.fromisoformat(utc_string[:-1])
# Apply the offset to convert the GMT datetime to the local time
local_datetime = utc_datetime + timedelta(hours=offset_hours, minutes=offset_minutes)
return local_datetime
解决方案 16:
这是一个快速而粗糙的版本,它使用本地系统设置来计算时差。注意:如果您需要转换为当前系统未运行的时区,则此方法将不起作用。我已经使用 BST 时区下的英国设置对此进行了测试
from datetime import datetime
def ConvertP4DateTimeToLocal(timestampValue):
assert isinstance(timestampValue, int)
# get the UTC time from the timestamp integer value.
d = datetime.utcfromtimestamp( timestampValue )
# calculate time difference from utcnow and the local system time reported by OS
offset = datetime.now() - datetime.utcnow()
# Add offset to UTC time and return it
return d + offset
扫码咨询,免费领取项目管理大礼包!