Как сравнить 2 даты в 2 разных столбцах csv, чтобы определить, предшествует ли дата в столбце 1 столбцу 2

#python #csv #date #command-line #compare

Вопрос:

Я пытаюсь сравнить 2 столбца временных меток в файле CSV, и я хочу сохранить только строки, в которых дата / время в столбце 1 предшествует дате / времени в столбце 2. Я не совсем уверен, с чего начать, поскольку мы рассматриваем сравнение многих разных чисел (например, месяц, год, час, минута и т. Д.) Отдельно Друг от друга, Включая сравнение AM / PM.

Пример: (дата в формате [мм / дд / гггг])

20.11.2018 3:00:13 вечера 23.11.2017 6:45:00
22.12.2019 16:00:12 1/10/2020 4:50:11 утра
10/10/2018 2:02:19 вечера 07.10.2018 1:04:15 вечера

Здесь я хотел бы сохранить строку 2, потому что дата в столбце 2 идет после даты в столбце 1, и я бы не хотел сохранять строки 1 и 3. Есть ли аккуратный способ сделать это в командной строке? (Если нет, любые указатели на написание скрипта Python были бы очень полезны)

Заранее спасибо!

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

1. Есть ли какой-либо конкретный язык, который вы хотите использовать для этого? Подходит ли вам Ruby?

2. Я не знаком с Ruby, если это невозможно сделать в командной строке, то мне больше всего нравится Python!

3. Если ваш CSV-файл не содержит данных в кавычках (например, для экранирования запятых), вы можете проанализировать его напрямую с помощью оболочки, но проще использовать язык, который имеет анализатор CSV, такой как Perl, Python или Ruby; дальнейшая обработка также будет проще.

Ответ №1:

В Python вам просто нужно преобразовать каждое из значений даты в datetime объекты. Затем их можно легко сравнить с помощью простого < оператора. Например:

 from datetime import datetime
import csv

with open('input.csv') as f_input, open('output.csv', 'w', newline='') as f_output:
    csv_input = csv.reader(f_input)
    #header = next(csv_input)   
    csv_output = csv.writer(f_output)
    #csv_output.writerow(header)
    
    for row in csv_input:
        date_col1 = datetime.strptime(row[0], '%m/%d/%Y %I:%M:%S %p')
        date_col2 = datetime.strptime(row[1], '%m/%d/%Y %I:%M:%S %p')
        
        if date_col1 < date_col2:
            csv_output.writerow(row)
 

Если ваш CSV-файл содержит заголовок, раскомментируйте две строки. Вы можете найти дополнительную информацию о том, как работает строка формата .strptime() , в документации функции.

Этот подход использует встроенную функциональность Python и поэтому не требует установки дополнительных модулей.

Ответ №2:

Я постараюсь сделать это как можно более понятным и подробным, чтобы все могли понять :

1) Сначала я импортировал библиотеку datetime в python

 import datetime as dt
 

2) Теперь я импортирую файл csv, с которым мне нужно работать, в этом случае я использовал dates.csv, который содержит те же данные, что и в вопросе, заданном выше :

 from csv import reader
dataset = list(reader(open("dates.csv", encoding = "utf-8")))
 

2.1) Печать набора данных, чтобы проверить, работает ли он :

 dataset
 

введите описание изображения здесь

печать одной даты из нашего набора данных для проверки шаблона :

Имейте в виду, что индексация в python начинается с нуля

 dataset[1][0] # dataset[row][column]
 

введите описание изображения здесь

2.2) Шаблон — месяц / день / год час: мин: сек утра / вечера

 pattern = "%m/%d/%Y %I:%M:%S %p" 
 

вы можете проверить коды юридического формата, чтобы в будущем создать другой шаблон.

3) Теперь преобразуем даты нашего набора данных в объект date time, используя библиотеку, которую мы импортировали

     for i in dataset[1:]: 
# [1:] because 1st row has heading and we don't need it

        i[0] = dt.datetime.strptime(i[0],pattern)
        i[1] = dt.datetime.strptime(i[1],pattern)

    print(dataset[1][0])
 

введите описание изображения здесь

успешно преобразовано ^

4) Теперь мы вручную сравним даты, чтобы понять концепции.

просто используя операторы сравнения, мы можем сравнивать даты в python, используя библиотеку datetime

 print(dataset[2][0] , "and" , dataset[2][1])
print(dataset[2][0] > dataset[2][1]) 
 

введите описание изображения здесь

5) Теперь создаем отдельный список, в который будут добавлены только те строки, где дата столбца 2 больше даты столбца 1 :

 col2_greatorthan_col1 = []
 

добавление заголовка в наш новый список :

 col2_greatorthan_col1.append(["column 1" , "column 2"])
 

сравнивая каждую дату и добавляя нужную строку в наш новый список :

 for i in dataset[1:]:
    if i[1] > i[0]: # means if column 2's date is greater than column 1's date
        col2_greatorthan_col1.append(i) # appending the filtered rows in our new list

col2_greatorthan_col1
 

введите описание изображения здесь

6) Теперь просто создайте csv-файл реального мира, который будет содержать те же данные, что и col2_greatorthan_col1

 import csv

with open("new_dates.csv" , "w" , newline = "") as file :
    writer = csv.writer(file)
    writer.writerows(lst)
 

Результат :

Новый csv-файл с именем new_dates.csv будет создан в том же каталоге, что и ваш файл кода python. Этот файл будет содержать только те строки, в которых дата столбца 2 больше даты столбца 1.

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

1. Если я не ошибаюсь, вы загружаете весь CSV в память, что имеет некоторые оговорки. Кстати, отличные объяснения 😉

Ответ №3:

Использование Pandas

 import pandas as pd

# Read tab delimited CSV file without header
# Names columns date1, date2
df = pd.read_csv("dates.csv", 
                  header = None,
                  sep='t', 
                  parse_dates = [0, 1],        # use default date parser i.e. parser.parser
                  names=["date1", "date2"])

# Filter (keep) row when date2 > date1
df = df[df.date2 > df.date1]

# Output to filtered CSV file using the original date format
df.to_csv('filtered_dates.csv', index = False, header = False, sep = 't', date_format  = "%Y/%m/%d %I:%M:%S %p")
 

Ответ №4:

С помощью инструментов командной строки вы можете использовать awk : для преобразования 1-й даты в формат эпохи:

 echo "11/20/2018 3:00:13 PM" |gawk -F'[/:]' '{print mktime($3" "$1" "$2" "$4" "$5" "$6" "$7)}'
 

то же самое для второго поля. А затем вычтите столбец 2 из столбца 1. Если результат положительный, это означает, что столбец 1 находится после столбца 2
Здесь используется функция mktime , из awk которой выполняется «волшебство». Имейте в виду, что эта функция недоступна в некоторых версиях UNIX awk

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

1. Я не знаю, как это произошло, но я отклонил ваш ответ; пожалуйста, отредактируйте свой пост, чтобы я мог его отменить

2. @Fravadona, не стесняйтесь отменить это 🙂

Ответ №5:

Я сохранил предоставленный вами образец в файле, разделенном табуляцией, без заголовков. Я импортировал его как DataFrame using (обратите внимание, что я указал ваш формат даты в date_parser ):

 import pandas as pd
import datetime as dt

df = pd.read_csv(PATH_TO_YOUR_FILE, sep="t", names=["col1", "col2"], parse_dates=[0,1], date_parser=lambda x:dt.datetime.strptime(x, "%m/%d/%Y %I:%M:%S %p")
 

Чтобы выбрать нужные вам строки:

 df.loc[df.loc[:,"col2"]>df.loc[:,"col1"],:]
 

Ответ №6:

Вы можете использовать pd.to_datetime для анализа строк даты и времени, а затем использовать их сравнение в качестве условия для фильтрации требуемых строк.

ДЕМОНСТРАЦИЯ:

 import pandas as pd

df = pd.DataFrame({
    'start': ['11/20/2018 3:00:13 PM', '12/22/2019 4:00:12 PM', '10/10/2018 2:02:19 PM'],
    'end': ['11/23/2017 6:45:00 AM', '1/10/2020 4:50:11 AM', '10/07/2018 1:04:15 PM']
})

result = pd.DataFrame(df[
                pd.to_datetime(df['start'], format='%m/%d/%Y %I:%M:%S %p') <
                pd.to_datetime(df['end'], format='%m/%d/%Y %I:%M:%S %p')
            ])

print(result)
 

Вывод:

                    start                   end
1  12/22/2019 4:00:12 PM  1/10/2020 4:50:11 AM
 

ONLINE DEMO