如何将东部标准时间/东部夏令时转换为格林威治标准时间?

9

我有一列记录,这些记录代表东部标准时间(EST)或东部夏令时(EDT)。我需要将这些时间转换为格林威治标准时间(GMT)。时间的格式如下:

10/1/2010   0:0:0
10/1/2010   0:6:0
...
10/1/2010   23:54:0
...
10/3/2010   0:0:0
...

有人能帮我解决这个问题吗?谢谢


5
那些看起来像日期(2010年10月1日),而不是时间……请解释一下。 - John Machin
1
你为什么一直问同样的问题?你之前尝试过什么,有什么问题吗?http://stackoverflow.com/questions/5490141/how-to-format-time-and-convert-to-gmt-time和https://dev59.com/qm035IYBdhLWcg3wW-z1。如果你能问出你**真正的**问题,而不是这些错误的问题,也许会更简单。 - S.Lott
@S.Lott:在这篇第二篇帖子中,我试图手动将时间转换为GMT时间,结果证明效率低下。对于第一篇帖子,我只是认为人们停止查看那篇帖子了。我考虑删除第一个帖子,但无法删除因为它已经有答案了。 - widget
6个回答

18

我知道的最简单、最可靠的时区转换方法是使用第三方pytz模块:

import pytz
import datetime as dt

utc=pytz.utc
eastern=pytz.timezone('US/Eastern')
fmt='%Y-%m-%d %H:%M:%S %Z%z'

text='''\
10/1/2010   0:0:0
10/1/2010   0:6:0
10/1/2010   23:54:0
10/3/2010   0:0:0
'''

for datestring in text.splitlines():
    date=dt.datetime.strptime(datestring,"%m/%d/%Y %H:%M:%S")
    date_eastern=eastern.localize(date,is_dst=None)
    date_utc=date_eastern.astimezone(utc)
    print(date_utc.strftime(fmt))
产生:
2010-10-01 04:00:00 UTC+0000
2010-10-01 04:06:00 UTC+0000
2010-10-02 03:54:00 UTC+0000
2010-10-03 04:00:00 UTC+0000

请注意,您的数据没有指定日期时间是在美国东部标准时间(EST)还是夏令时(EDT)。 如果不指定EST或EDT,则某些时间是模棱两可的。例如,“10/27/2002 1:30:00”将是模棱两可的:

>>> eastern.localize(datetime(2002, 10, 27, 1, 30, 00), is_dst=None)
AmbiguousTimeError: 2002-10-27 01:30:00

由于夏令时的影响,这个时间会发生两次。此外,一些日期时间,比如2002-04-07 02:30:00是不存在的。详见这个链接关于处理本地时间时出现的这些以及更奇怪的问题的讨论。

如果您愿意忽略这些棘手的情况,并且您的计算机设置在本地时区(例如EST / EDT),则有一种方法可以在本地和UTC时区之间进行转换,而不需要安装pytz。这个想法是将datetime --> timetuple --> timestamp --> UTC datetime进行转换。这些转换是通过以下方式完成的:

dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))
例如:
import time
import datetime as dt
import pytz

utc=pytz.utc
eastern=pytz.timezone('US/Eastern')
fmt='%Y-%m-%d %H:%M:%S %Z%z'

text='''\
10/1/2010   0:0:0
10/1/2010   0:6:0
10/1/2010   23:54:0
10/3/2010   0:0:0
3/13/2011   1:55:0
3/13/2011   3:00:0
'''
for datestring in text.splitlines():
    date=dt.datetime.strptime(datestring,"%m/%d/%Y %H:%M:%S")
    date_est=eastern.localize(date,is_dst=None)
    date_utc=date_est.astimezone(utc)
    date_utc2=dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))
    print('{d} --> {d_utc}    {d_utc2}'.format(
        d=date.strftime(fmt),
        d_utc=date_utc.strftime(fmt),
        d_utc2=date_utc2.strftime(fmt),
        ))
    assert date_utc.hour == date_utc2.hour
产生。
2010-10-01 00:00:00 EDT-0400 --> 2010-10-01 04:00:00 UTC+0000    2010-10-01 04:00:00 
2010-10-01 00:06:00 EDT-0400 --> 2010-10-01 04:06:00 UTC+0000    2010-10-01 04:06:00 
2010-10-01 23:54:00 EDT-0400 --> 2010-10-02 03:54:00 UTC+0000    2010-10-02 03:54:00 
2010-10-03 00:00:00 EDT-0400 --> 2010-10-03 04:00:00 UTC+0000    2010-10-03 04:00:00 
2011-03-13 01:55:00 EST-0500 --> 2011-03-13 06:55:00 UTC+0000    2011-03-13 06:55:00 
2011-03-13 03:00:00 EDT-0400 --> 2011-03-13 07:00:00 UTC+0000    2011-03-13 07:00:00 

上述测试的最后两个日期表明,该转换即使在 EST 和 EDT 之间切换的时间非常接近时,也能正常工作。


总之,使用另一种方法(不使用pytz),以下是将表示本地时间的datetime对象转换为表示GMT时间的datetime对象,以及相反操作的方法:

In [83]: import datetime as dt
In [84]: import time
In [85]: import calendar

In [86]: date=dt.datetime(2010,12,1,0,0,0)    
In [87]: date
Out[87]: datetime.datetime(2010, 12, 1, 0, 0)

In [88]: date_utc=dt.datetime.utcfromtimestamp(time.mktime(date.timetuple()))    
In [89]: date_utc
Out[89]: datetime.datetime(2010, 12, 1, 5, 0)

In [90]: date_local=dt.datetime.fromtimestamp(calendar.timegm(date_utc.timetuple()))    
In [91]: date_local
Out[91]: datetime.datetime(2010, 12, 1, 0, 0)

@unutbu: 我刚刚试了你的代码(第二种方法)。第一种方法的问题在于我没有 pytz 包。对于第二种方法,现在我的结果是 2010-12-01 05:00:00 转换自 '12/1/2010 0:0:0',所以看起来很完美。不管怎样,有没有办法将其转换回原始格式:'12/1/2010 5:0:0'?现在我知道要将其他格式转换为日期格式,可以使用类似 date=dt.datetime.strptime(text,"%m/%d/%Y %H:%M:%S") 的方法,但不知道如何将日期格式转换为其他格式。另外,如果我有一个 GMT 时间并想将其转换为 EST/EDT 时间,该怎么办呢? - widget
@widget:您可以在此处查看可用的strftime格式字符串指令:http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior。 - unutbu
@widget:请尝试按照这里的说明进行操作:http://pytz.sourceforge.net/#installation。如果遇到问题,请打开一个新的问题,并包括您使用的操作系统信息。 - unutbu
@widget:你的日期格式化问题已经得到回答了吗,还是你还在寻找其他的解决方案? - unutbu
@unutbu: 我在你的代码中发现了一个关于pytz包的问题:date_est=eastern.localize(date,is_dst=None)。如果这是一系列不同的日期,你如何简单地使用is_dst=None来本地化naive datetime?它并没有正确转换时间。如果将其设置为None,则无论是EDT还是EST,它都会将所有时间加5个小时。您能否解释一下?谢谢。 - widget
显示剩余3条评论

2

假设我们有一个日期时间字符串,格式为"2019-04-09T23:59:55ET",所在时区为美国东部时间。

以下是将字符串转换为UTC的函数:

Original Answer翻译成"最初的回答"

from datetime import datetime
import pytz

eastern = pytz.timezone('US/Eastern')

def convent_est_to_utc(datetime_str):
    dt = datetime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%SET')
    return dt.replace(tzinfo=eastern).astimezone(pytz.utc)

# testing
convent_est_to_utc("2019-04-09T23:59:55ET")

# The result: 2019-04-10 04:55:55+00:00


2

每个记录的伪代码:

生成时间戳字符串:field[0].strip() + " " + field[1].strip()

使用datetime.datetime.strptime()将其转换为datetime.datetime实例

添加timedelta,例如timedelta(hours=-4),到您的时间戳

使用timestamp.strftime()生成所需的任何字符串表示形式的输出。

对于时间字段为空的情况:如果意味着0:0:0,则修改上述内容以适应。如果它表示“时间未知”,则需要做其他事情...


1

如果没有关联的时间,时区就无关紧要...日期也无法转换为不同的时区。另一列中是否有相关的时间?

编辑:好了,既然现在有时间了,我会让 Python 大师接手。 ;]


如果您要添加一个新的时间列,只需使用4:00 AM并将时区更改为GMT(EST为GMT-4:00)。这意味着日期是12:00AM EST。我认为您不需要做任何其他花哨的事情。 - Joe McBride
你还没有考虑好当输入和输出时间戳跨越一个月边界时该怎么办。 - John Machin
@John Machin:我确实考虑过这个问题,但是我把它留给小部件自己去练习了。 - Joe McBride

1
你可以像这样使用pandas.DataFrame.tz_convert()
import pandas as pd
from datetime import datetime

df = pd.read_csv("your_data_file_path.csv", index_col=False, engine='python')
df['Date'] = pd.to_datetime(df['Date'])
df['Date'] = df['Date'].dt.tz_localize('US/Eastern').dt.tz_convert('UTC')
df['Date'] = df['Date'].apply(lambda x: datetime.replace(x, tzinfo=None))

最后一行的作用是从日期时间对象中移除时区信息,这样你就可以仅操作日期和时间(不用担心,这不会再次改变时区,它只是从时间戳字符串中剥离它)。

0

我不得不在Python中创建一个自定义函数来将EST转换为GMT,这是我编写的代码:

#convert est time to gmt. Make sure you assign the current EST values
#to the following variables
        est_year
        est_month
        est_day
        est_hour
        est_min

        gmt_year = est_year
        gmt_month = est_month
        gmt_day = est_day
        gmt_hour = est_hour + 5 #gmt is ahead by 5 hrs
        gmt_min = est_min

        if gmt_hour > 23:
          gmt_hour = gmt_hour - 23
          gmt_day = est_day + 1

        days_in_month = calendar.monthrange(est_year,est_month)[1] #in case the no days becomes 32..

        if gmt_day > days_in_month:
          gmt_day = 1
          gmt_month = gmt_month + 1

        if gmt_month > 12:
          gmt_month = 1
          gmt_year = gmt_year + 1

        gmttime = datetime.datetime(gmt_year, gmt_month, gmt_day, gmt_hour, gmt_min, 0)

我还没有添加EDT支持。现在是二月份,正在遵循EST。欢迎任何更改或纠正!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接