Как преобразовать строки даты / времени, которые имеют 24 в качестве значения часа, в datetime в Pandas? - PullRequest
0 голосов
/ 09 февраля 2019

Я импортирую электронные письма в виде текстовых файлов из обычного почтового приложения (Mac OS X).К сожалению, многие даты в письмах имеют время, например "24:01:01", которое недопустимо (должно быть "00:01:01").

Есть ли простой способ конвертировать их?

Обычная строка даты / времени работает нормально:

>>> pd.to_datetime("March 23, 2011 at 23:42:46  PDT")
Timestamp('2011-03-23 23:42:46-0700', tz='pytz.FixedOffset(-420)')

Ненормальная строка даты:

>>> pd.to_datetime("March 23, 2011 at 24:42:46  PDT")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/anaconda/envs/pyqt/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object)
   1860         try:
-> 1861             values, tz_parsed = conversion.datetime_to_datetime64(data)
   1862             # If tzaware, these values represent unix timestamps, so we

pandas/_libs/tslibs/conversion.pyx in pandas._libs.tslibs.conversion.datetime_to_datetime64()

TypeError: Unrecognized value type: <class 'str'>

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-38-4cb009b21802> in <module>
----> 1 pd.to_datetime("March 23, 2011 at 24:42:46  PDT")

~/anaconda/envs/pyqt/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in to_datetime(arg, errors, dayfirst, yearfirst, utc, box, format, exact, unit, infer_datetime_format, origin, cache)
    609             result = convert_listlike(arg, box, format)
    610     else:
--> 611         result = convert_listlike(np.array([arg]), box, format)[0]
    612 
    613     return result

~/anaconda/envs/pyqt/lib/python3.6/site-packages/pandas/core/tools/datetimes.py in _convert_listlike_datetimes(arg, box, format, name, tz, unit, errors, infer_datetime_format, dayfirst, yearfirst, exact)
    300             arg, dayfirst=dayfirst, yearfirst=yearfirst,
    301             utc=utc, errors=errors, require_iso8601=require_iso8601,
--> 302             allow_object=True)
    303 
    304     if tz_parsed is not None:

~/anaconda/envs/pyqt/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object)
   1864             return values.view('i8'), tz_parsed
   1865         except (ValueError, TypeError):
-> 1866             raise e
   1867 
   1868     if tz_parsed is not None:

~/anaconda/envs/pyqt/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object)
   1855             dayfirst=dayfirst,
   1856             yearfirst=yearfirst,
-> 1857             require_iso8601=require_iso8601
   1858         )
   1859     except ValueError as e:

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime_object()

pandas/_libs/tslib.pyx in pandas._libs.tslib.array_to_datetime_object()

pandas/_libs/tslibs/parsing.pyx in pandas._libs.tslibs.parsing.parse_datetime_string()

~/anaconda/envs/pyqt/lib/python3.6/site-packages/dateutil/parser/_parser.py in parse(timestr, parserinfo, **kwargs)
   1354         return parser(parserinfo).parse(timestr, **kwargs)
   1355     else:
-> 1356         return DEFAULTPARSER.parse(timestr, **kwargs)
   1357 
   1358 

~/anaconda/envs/pyqt/lib/python3.6/site-packages/dateutil/parser/_parser.py in parse(self, timestr, default, ignoretz, tzinfos, **kwargs)
    651             raise ValueError("String does not contain a date:", timestr)
    652 
--> 653         ret = self._build_naive(res, default)
    654 
    655         if not ignoretz:

~/anaconda/envs/pyqt/lib/python3.6/site-packages/dateutil/parser/_parser.py in _build_naive(self, res, default)
   1225                 repl['day'] = monthrange(cyear, cmonth)[1]
   1226 
-> 1227         naive = default.replace(**repl)
   1228 
   1229         if res.weekday is not None and not res.day:

ValueError: hour must be in 0..23

1 Ответ

0 голосов
/ 09 февраля 2019

Сначала преобразуйте хорошие даты с to_datetime с errors='coerce' - получите NaT для плохих значений.Так что отфильтруйте это, replace 24 и добавьте один день.Последняя fillna для замены отсутствующими значениями на нее:

d = ["March 23, 2011 at 24:42:46  PDT",
     "March 23, 2011 at 23:42:46  PDT"]

s = pd.Series(d)

s1 = pd.to_datetime(s, errors='coerce')
m = s1.isna()

s2 = (pd.to_datetime(s[m].replace('at 24:', 'at 00:', regex=True),  errors='coerce') +
         pd.Timedelta(1, unit='d'))

s = s1.fillna(s2)
print (s)
0   2011-03-24 00:42:46
1   2011-03-23 23:42:46
dtype: datetime64[ns]

Другая идея - извлечь дни и время для разделения столбцов и добавить timedelta s:

s1 = pd.to_datetime(s, errors='coerce')
m = s1.isna()

df2 = s[m].str.split(' at ', expand=True)
df2.columns = ['date','time']
df2['date'] = pd.to_datetime(df2['date'], errors='coerce')
df2['time'] = pd.to_timedelta(df2['time'].str.extract('(\d+:\d+:\d+)', expand=False))
df2['date1'] = df2['date'] + df2['time']
print (df2)
        date            time               date1
0 2011-03-23 1 days 00:42:46 2011-03-24 00:42:46

s = s1.fillna(df2['date1'])
print (s)
0   2011-03-24 00:42:46
1   2011-03-23 23:42:46
dtype: datetime64[ns]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...