синтаксический анализ строки из json в объект datetime

#python #json #datetime #parsing

#python #json #datetime #синтаксический анализ

Вопрос:

я пытаюсь проанализировать строки времени из файла json, сохранить только те строки, которые могут быть проанализированы с использованием стандарта ISO datetime с помощью strptime, принять значения createdAt, которые уже есть в стандарте ISO datetime, и преобразовать их обратно в строки (в часовом поясе UTC) с помощью strftime .

вот как выглядят мои данные json, где createdAt для четвертого заголовка уже находится в стандарте ISO datetime, но пятый заголовок должен быть удален, поскольку 12345678 является недопустимым объектом времени.

 {"title_text": "Fourth title", "createdAt": "2020-10-17T02:56:51 07:00", "text": "Some post content", "author": "cereal"}
{"title_text": "Fifth title", "createdAt": "12345678", "text": "Some post content", "author": "ninja"}
  

и это два фрагмента кода, с которыми я работал.

 datetime_formats = ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S%Z")

for time in range(len(data)):
    for format in datetime_formats:
        try:
            data[time]['createdAt'] = datetime.strptime(str(time), format).replace(tzinfo=pytz.UTC)
        except ValueError:
            pass 
        else:
            break
    else:
        data.remove(time)
  

^ этот фрагмент кода выдает мне ошибку ValueError: list.remove(x): x отсутствует в списке

 def parse_createdAt_time(output_format="%Y-%m-%dT%H:%M:%S%Z"):
    datetime_formats = ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S%Z")
    
    for time in data[1]['createdAt']:
        for format in datetime_formats:
            try: 
                time = datetime.strptime(time, format).replace(tzinfo=datetime.timezone.utc)
                return time.strftime(output_format)
            except ValueError:
                pass
            else:
                break
        else:
            data.remove(time)
  

^ я попытался использовать немного другой подход к этому коду и попытался модулировать его, но он даже не проанализировал мой ввод json. он просто выплевывает мои данные json, нетронутые (включая запись 12345678 выше)

мне также разрешено использовать только модуль datetime, но я потратил на это слишком много времени и до сих пор не совсем понимаю, что не так.

текущий код (inspo от @MrFuppes), который выдает четыре «ошибки» и ошибку типа: объект ‘datetime.datetime’ не поддается подписке. кажется, что все временные строки json, которые используют стандарт iso datetime, анализируются как ошибка значения, а «пятый заголовок» (который является недопустимым форматом времени) выдает мне ошибку типа.

 def datetime_valid(data, output_format="%Y-%m-%dT%H:%M:%S%Z"):
    final_json = []
    for line in data:
        for format in ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S%Z"):
            try: # see if json string is in iso datetime standard
                check_iso = datetime.strptime(str(line['createdAt']), format)
            except ValueError:
                print("error")
            else: # if string is in iso format, convert to utc and append to final_json array
                line = check_iso.astimezone(timezone.utc).replace(tzinfo=None)
                final_json.append(line.strftime(output_format))
    return final_json
  

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

1. примечание: не изменяйте итерацию во время итерации по ней (например data.remove(time) ) — это может привести к довольно запутанным результатам 😉

Ответ №1:

если у вас есть дата / время в строке изоформата, почему вы не используете методы изоформата? все они являются частью стандартной библиотеки…

 from datetime import datetime, timezone

l = [{"title_text": "Fourth title", "createdAt": "2020-10-17T02:56:51 07:00", "text": "Some post content", "author": "cereal"},
     {"title_text": "Fifth title", "createdAt": "12345678", "text": "Some post content", "author": "ninja"}]

out = []
for d in l:
    try:
        dt = datetime.fromisoformat(d['createdAt'])
    except ValueError:
        pass
    else:
        d['createdAt'] = dt.astimezone(timezone.utc).isoformat()
        out.append(d)
        
# out        
# [{'title_text': 'Fourth title',
#   'createdAt': '2020-10-16T19:56:51 00:00',
#   'text': 'Some post content',
#   'author': 'cereal'}] 
  

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

1. это работает, когда я копирую и вставляю его в ячейку jupyter, но не тогда, когда я меняю l на свой фактический файл json:/ я внес изменения в ваш код (например, все еще придерживаюсь strptime, потому что я не хочу потерять информацию в%H:%M:%S%Z)но в итоге я получаю «ошибку» (x4) и ошибку типа: объект ‘datetime.datetime’ не подлежит подписке. я отредактировал свой пост, чтобы включить этот код более подробную информацию о том, что, по моему мнению, может произойти, не могли бы вы взглянуть?

Ответ №2:

Я не уверен, что точно понимаю вашу цель, но предполагая, что вы просто хотите отфильтровать свой список данных от записей с неправильным форматом даты для createdAt, вы можете использовать функцию для создания нового списка только с допустимыми записями :

 from datetime import datetime
import pytz

raw_data = [
    {"title_text": "Fourth title", "createdAt": "2020-10-17T02:56:51 07:00", "text": "Some post content", "author": "cereal"},
    {"title_text": "Fifth title", "createdAt": "12345678", "text": "Some post content", "author": "ninja"}
]

datetime_formats = ("%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S%Z")
def filter_data(data):
    out = []
    for d in data:
        for date_format in datetime_formats:
            try:
                date = datetime.strptime(d['createdAt'], date_format)
                d['createdAt'] = date.strftime(datetime_formats[0])
                out.append(d)
                break
            except ValueError:
                pass 
    return out
  

выдает

 [{'title_text': 'Fourth title',
  'createdAt': '2020-10-17T02:56:51 0700',
  'text': 'Some post content',
  'author': 'cereal'}]