【问题标题】:Why will to_datetime handle positive timezones (UTC+) fine, but not negative timezones (UTC-)?为什么 datetime 可以处理正时区 (UTC) 而不是负时区 (UTC-)?
【发布时间】:2020-12-17 18:26:41
【问题描述】:

我一直在使用 Pandas 将 .CSV 文件转换为可在另一个系统上读取的格式,并且我即将完成它,但我无法让它与负时区 (UTC- 1、-2 等)

这是我正在使用的代码,它不是最整洁的,但它可以完成 UTC+ 时区的工作,你知道为什么它可能无法正确处理 UTC- 时区吗?

import pandas as pd
from datetime import datetime
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
pd.set_option('display.width', 1000)

import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')

df = pd.read_csv('CONCACAF_First_Round.csv', index_col=False)
df['starttime'] = df['starttime'].str.replace('\s+', '')
df.insert(loc=2, column='season', value='2020')
df.insert(loc=6, column='awayscore', value='')
df.insert(loc=8, column='round_a', value='1')
df['venue'] = df['venue'].str.split(',').str[0]
df[['homescore', 'awayscore']] = df['homescore'].str.split('–',expand=True)
df['awayscore'] = df['awayscore'].str.split(' ').str[0]
df['starttime'] = df['starttime'].str.replace('UTC', ' UTC')
df['datepicker'] = df['datepicker'] + (' ') + df['starttime']
del df['starttime']
df[['datepicker', 'time', 'UTC']] = df.datepicker.str.split(" ", expand=True)
df['datepicker'] = df['datepicker'] + ' ' + df['time']
del df['time']
df['datepicker'] = df['datepicker'] + ' ' + df['UTC']
df['datepicker'] = df['datepicker'].str.replace('±', '+')
df['datepicker'] = df['datepicker'].str.replace('UTC', '')
del df['UTC']
df['datepicker'] = pd.to_datetime(df['datepicker'], utc=True)
df.insert(loc=1, column='starttime', value='')
df['starttime'] = df['datepicker'].dt.strftime('%H:%M:%S')
df['datepicker'] = df['datepicker'].dt.strftime('%Y-%m-%d')
print(df.head(10))

这是它返回的负时区

dateutil.parser._parser.ParserError: Unknown string format: 2015-03-25 19:30 −4

这是它在 UTC+ 时区正常工作时返回的内容

datepicker starttime season  hometeam awayteam homescore awayscore              venue round_a
0  2019-09-04  13:00:00   2020  Ethiopia  Lesotho         0         0  Bahir Dar Stadium       1

数据:CONCACAF_First_Round.csv

# copy the data to the clipboard and read with
df = pd.read_clipboard(sep=',')

datepicker,starttime,hometeam,awayteam,homescore,venue
2015-03-25,19:30 UTC−4,Bahamas,Bermuda,0–5,"Thomas Robinson Stadium, Nassau"
2015-03-29,15:00 UTC−3,Bermuda,Bahamas,3–0,"Bermuda National Stadium, Devonshire"
2015-03-26,19:00 UTC−4,British Virgin Islands,Dominica,2–3,"Windsor Park, Roseau (Dominica)[note 2]"
2015-03-29,17:00 UTC−4,Dominica,British Virgin Islands,0–0,"Windsor Park, Roseau"
2015-03-22,19:00 UTC−4,Barbados,U.S. Virgin Islands,0–1,"Barbados National Stadium, Bridgetown"
2015-03-26,15:30 UTC−4,U.S. Virgin Islands,Barbados,0–4,"Addelita Cancryn Junior High School Ground, Charlotte Amalie"
2015-03-23,20:00 UTC−4,Saint Kitts and Nevis,Turks and Caicos Islands,6–2,"Warner Park, Basseterre"
2015-03-26,19:00 UTC−4,Turks and Caicos Islands,Saint Kitts and Nevis,2–6,"TCIFA National Academy, Providenciales"
2015-03-23,18:00 UTC−6,Nicaragua,Anguilla,5–0,"Nicaragua National Football Stadium, Managua"
2015-03-29,17:00 UTC−4,Anguilla,Nicaragua,0–3,"Ronald Webster Park, The Valley"
2015-03-25,20:00 UTC−6,Belize,Cayman Islands,0–0,"FFB Stadium, Belmopan"
2015-03-29,19:00 UTC−5,Cayman Islands,Belize,1–1,"Truman Bodden Sports Complex, George Town"
2015-03-27,20:00 UTC−4,Curaçao,Montserrat,2–1,"Ergilio Hato Stadium, Willemstad"
2015-03-31,19:00 UTC−4,Montserrat,Curaçao,2–2,"Blakes Estate Stadium, St. John's"

【问题讨论】:

    标签: python pandas datetime timezone


    【解决方案1】:

    您的“减号”并不都是减号。例如在您的错误消息中:

    Unknown string format: 2015-03-25 19:30 −4
    

    如果您将看起来像减号的倒数第二个字符作为字符串复制到 Python 中,您将看到:

    >>> '−'
    '\xe2\x88\x92'
    

    那是 U+2212,一个特殊的Unicode "minus sign",它与键盘上的“-”不同。

    您需要将那些 Unicode“减号”替换为纯 ASCII 减号,然后它应该可以工作。

    有一个Python-ideas discussion about this in 2013,“Unicode 减号在数字转换中”,其中one person said

    就支持非 ASCII 加号和减号而言,我原则上很热衷,但在实践中不冷不热。我认为这将是一个很好的选择,如果有人确定应该接受哪些字符,我会支持将其添加为新功能。但我不认为缺乏对非 ASCII 数字符号的支持是一个错误。

    这个话题最终没有结果,因为每个人都多次将他们的爱好马打死,还带着诸如泰国数字是否应该在float() 中使用这样的附带话题。如果有人接手这项任务,更专注于支持 U+2212 和一些 Unicode“加号”符号可能会更好。

    【讨论】:

    • 这解决了我的问题,我以后在抓取互联网数据时会更加厌倦特殊符号。也谢谢你的历史课,挺有意思的。
    【解决方案2】:

    fix_starttime击穿

    • 数据的主要问题是 不是正确的符号-。请注意,它会稍长一些。
      • '−' 替换为'-'
      • ' UTC' 替换为':00 '
      • '19:30 UTC−4' 转换为'19:30:00 -4'
    • fix_date 函数使用'19:30:00 -4' 执行以下操作
      • y = v.split(' ')y = ['19:30:00', '-4']
      • z= y[1][0] + y[1][1:].zfill(2) + '00'z = '-' + '0400'z = '-0400'
        • str.zfill 用零填充 str 以适应长度 width,在这种情况下为 2。所以'4' 变为'04''10' 保持'10'
      • t = y[0]t = '19:30:00'
      • return 19:30:00-0400
    • datepicker 和格式正确的starttime 组合在一起,并将其转换为datetime64[ns, UTC] 格式的列。
    import pandas as pd
    
    # read the file
    df = pd.read_csv('CONCACAF_First_Round.csv')
    
    # function
    def fix_starttime(v: str) -> str:
        y = v.split(' ')
        z = y[1][0] + y[1][1:].zfill(2) + '00'
        t = y[0]
        return t + z
    
    
    # fix starttime
    df['starttime'] = df.starttime.str.replace('−', '-').str.replace(' UTC', ':00 ').apply(fix_starttime)
    
    # create datetime column in datetime64[ns, UTC] format
    df['utc_datetime'] = pd.to_datetime(df.datepicker + 'T' + df.starttime, utc=True)
    

    合并

    # read the file
    df = pd.read_csv('CONCACAF_First_Round.csv')
    
    # fix starttime
    df['starttime'] = df.starttime.str.replace('−', '-').str.replace(' UTC', ':00 ').str.split(' ').apply(lambda y: y[0] + y[1][0] + y[1][1:].zfill(2) + '00')
    
    # create datetime column in datetime64[ns, UTC] format
    df['utc_datetime'] = pd.to_datetime(df.datepicker + 'T' + df.starttime, utc=True)
    

    附加功能

    • 一旦有日期时间格式的列,使用 pandas .dt accessor 提取日期时间组件。
    # extract time from utc_datetime
    df.utc_datetime.dt.time
    
    # extract date from utc_datetime
    df.utc_datetime.dt.date
    

    结果

     datepicker      starttime                  hometeam                  awayteam homescore                                                         venue              utc_datetime
     2015-03-25  19:30:00-0400                   Bahamas                   Bermuda       0–5                               Thomas Robinson Stadium, Nassau 2015-03-25 23:30:00+00:00
     2015-03-29  15:00:00-0300                   Bermuda                   Bahamas       3–0                          Bermuda National Stadium, Devonshire 2015-03-29 18:00:00+00:00
     2015-03-26  19:00:00-0400    British Virgin Islands                  Dominica       2–3                       Windsor Park, Roseau (Dominica)[note 2] 2015-03-26 23:00:00+00:00
     2015-03-29  17:00:00-0400                  Dominica    British Virgin Islands       0–0                                          Windsor Park, Roseau 2015-03-29 21:00:00+00:00
     2015-03-22  19:00:00-0400                  Barbados       U.S. Virgin Islands       0–1                         Barbados National Stadium, Bridgetown 2015-03-22 23:00:00+00:00
     2015-03-26  15:30:00-0400       U.S. Virgin Islands                  Barbados       0–4  Addelita Cancryn Junior High School Ground, Charlotte Amalie 2015-03-26 19:30:00+00:00
     2015-03-23  20:00:00-0400     Saint Kitts and Nevis  Turks and Caicos Islands       6–2                                       Warner Park, Basseterre 2015-03-24 00:00:00+00:00
     2015-03-26  19:00:00-0400  Turks and Caicos Islands     Saint Kitts and Nevis       2–6                        TCIFA National Academy, Providenciales 2015-03-26 23:00:00+00:00
     2015-03-23  18:00:00-0600                 Nicaragua                  Anguilla       5–0                  Nicaragua National Football Stadium, Managua 2015-03-24 00:00:00+00:00
     2015-03-29  17:00:00-0400                  Anguilla                 Nicaragua       0–3                               Ronald Webster Park, The Valley 2015-03-29 21:00:00+00:00
     2015-03-25  20:00:00-0600                    Belize            Cayman Islands       0–0                                         FFB Stadium, Belmopan 2015-03-26 02:00:00+00:00
     2015-03-29  19:00:00-0500            Cayman Islands                    Belize       1–1                     Truman Bodden Sports Complex, George Town 2015-03-30 00:00:00+00:00
     2015-03-27  20:00:00-0400                   Curaçao                Montserrat       2–1                              Ergilio Hato Stadium, Willemstad 2015-03-28 00:00:00+00:00
     2015-03-31  19:00:00-0400                Montserrat                   Curaçao       2–2                             Blakes Estate Stadium, St. John's 2015-03-31 23:00:00+00:00
    

    【讨论】:

    • 这不是我第一次被一个符号与所需的符号略有不同,我以后会特别注意。
    • 我不确定第二个要点部分的用途是什么,因为我已经设法解决了第一个要点部分的问题。感谢您向我提供帮助。
    • @SpingoTakagi 我不确定问题的全部范围,因此如果需要,我还对转换进行了细分。 Consolidated 只是将函数转换为 1-liner 用于修复 starttime 列。
    • 感谢您加倍努力,我什至不知道这是可能的。
    猜你喜欢
    • 2020-02-06
    • 2019-06-09
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    相关资源
    最近更新 更多