Как преобразовать строку в формат DatetimeWithNanoseconds с помощью python?

#python #datetime #timestamp #nanotime

Вопрос:

У меня есть несколько строк, представляющих метки времени. Несколькими примерами могут быть : 19551231 (%Y%m%d) или 20210216154500 (%Y%m%d%H%M%S). Как вы можете видеть, формат может отличаться.

Я ищу способ преобразовать все эти разные строки в уникальный формат DatetimeWithNanoseconds.

Я знаю, что могу преобразовать метку времени в дату с точностью до наносекунд, используя целые числа, подобные этому: DatetimeWithNanoseconds(2020, 6, 22, 17, 1, 30, nanosecond=0) .

Означает ли это, что я должен вручную анализировать каждую полученную строку, чтобы получить соответствующие целые числа ? Есть ли лучший способ сделать это ? Например, как strptime работает функция (использование строк, например %Y%m%d , для определения расположения строки)

Ответ №1:

Я узнал, что из datetime формата легко извлечь часы, например, просто позвонив date.hour (то же самое для года, месяца и т. Д.).

Зная это, способ преобразования строки в формат DatetimeWithNanoseconds состоит из следующих 2 простых шагов:

  1. Преобразуйте строку в формат даты и времени:
 date = '19551231'
date = datetime.datetime.strptime(date, '%Y%m%d')
 
  1. Преобразование в дату и время в наносекундах:
 nano = DatetimeWithNanoseconds(date.year, date.month, date.day, date.hour, date.minute, date.second, nanosecond=0)
 

Ответ №2:

Вы предложили примеры временных меток из 8 и 14 символов. Похоже, вы хотите добавить 9 или более нулей, преобразовав их в единообразные 23-символьные метки времени, читаемые человеком. В этот момент было бы просто перевести его в формат rfc 3339 и позвонить from_rfc3339() , чтобы получить время с точностью до наносекунд.

Рассмотрите возможность использования простого while цикла:

 while len(ts) < 23:
    ts  = '0'
return ts
 

Лучший способ сделать то же самое:

 return ts   '0' * (23 - len(ts))
 

Редактировать

Вам понадобится пара помощников здесь. Каждый из них поддается модульному тестированию и предлагает очень простой API.

Первый из них превращает все в единообразные 23-символьные метки времени, читаемые человеком, как я упоминал выше.

Второй взял бы первые 14 символов и превратил бы их в целые секунды с момента эпохи. Затем переключитесь на наносекунды. У меня есть что-то вроде этого на уме:

 import datetime as dt

def to_nanosec(stamp: str):
    assert 23 == len(stamp), stamp
    d = dt.datetime.strptime(stamp[:14], '%Y%d%m%H%M%S')
    return 1e9 * d.timestamp()   int(stamp) % 1e9
 

Эквивалентно, что 2-й термин может быть … int(stamp[14:])

Предпочитаю int(1e9) , или 1_000_000_000 , если возвращение int важно.

Вы , конечно, могли бы разбить диапазоны символов и поставить знаки препинания, такие как : двоеточие и Z между ними, перед вызовом from_rfc3339() , но .strptime() здесь может быть удобнее.


Стоит отметить, что numpy предлагает поддержку наносекундной точности.

Комментарии:

1. К сожалению from_rfc3339() , поднимите ValueError , потому что он не принимает мою строку 19551231 , так как формат не соответствует чему-то вроде этого : 2019-10-12T07:20:50.52Z . Добавление нуля в конце моей строки не помогает моей строке быть rfc3339. Есть ли способ правильно преобразовать его ? strptime() здесь это не помогает, потому что оно преобразуется 19551231 в 1955-12-31 00:00:00 то, что все еще не принимается from_rfc3339() функцией.

2. Плюс: функция from_rfc3339() возвращает a <class 'datetime.datetime'> , а не a <class 'proto.datetime_helpers.DatetimeWithNanoseconds'>

3. Ой! Мы получим обратно микросекундное время даты и времени, которое не будет поддерживать наносекунду? Вздох!