прочитать xls, преобразовать все даты в правильный формат, -> записать в csv

Я читаю файлы excel и записываю их как csv. Несколько столбцов содержат даты, отформатированные как число с плавающей запятой в Excel. Все эти поля должны быть преобразованы в правильную дату и время (дд/мм/гг), прежде чем я запишу в CSV. Я нашел несколько хороших статей о том, как это работает в целом, но изо всех сил пытался заставить это работать для всех строк на открытом листе одновременно. (новичок в питоне)

На данный момент код выглядит следующим образом:

wb = xlrd.open_workbook(args.inname)
    xl_sheet = wb.sheet_by_index(0)
    print args.inname
    print ('Retrieved worksheet: %s' % xl_sheet.name)
    print outname

    # TODO: Convert xldate.datetime from the date fileds to propper datetime

    output = open(outname, 'wb')
    wr = csv.writer(output, quoting=csv.QUOTE_ALL)

    for rownum in xrange(wb.sheet_by_index(0).nrows):
        wr.writerow(wb.sheet_by_index(0).row_values(rownum))

    output.close()

Я уверен, что мне нужно изменить строку «для rownum ....», но я изо всех сил пытаюсь это сделать. Перепробовал несколько вариантов, все неудачно.

Спасибо


person f0rd42    schedule 19.02.2015    source источник
comment
См. stackoverflow.com/a/311655/2327328.   -  person philshem    schedule 24.02.2015


Ответы (2)


Вам нужно просмотреть строку, прежде чем записать ее в файл, преобразовав значения. Вы правильно определили, что он находится рядом с линией for rownum:

# You need to know which columns are dates before hand
# you can't get this from the "type" of the cell as they 
# are just like any other number

date_cols = [5,16,23]

... # Your existing setup code here #

# write the header row (in response to OP comment)
headerrow = wb.sheet_by_index(0).row_values(0)
wr.writerow(headerrow)

# convert and write the data rows (note range now starts from 1, not 0)
for rownum in xrange(1,wb.sheet_by_index(0).nrows):
    # Get the cell values and then convert the relevant ones before writing
    cell_values = wb.sheet_by_index(0).row_values(rownum)
    for col in date_cols:
        cell_values[col] = excel_time_to_string(cell_values[col])

    wr.writerow(cell_values)

Что именно вы добавляете в свою функцию excel_time_to_string(), зависит от вас - ответ @MarkRansom имеет разумный подход - или вы можете использовать xlrd собственные версии пакета, описанные в этом ответе.

Например:

def excel_time_to_string(xltimeinput):
    return str(xlrd.xldate.xldate_as_datetime(xltimeinput, wb.datemode))

* ИЗМЕНИТЬ *

В ответ на просьбу о помощи в комментариях после попытки. Вот более защищенная от ошибок версия excel_time_to_string()

def excel_time_to_string(xltimeinput):
    try:
        retVal = xlrd.xldate.xldate_as_datetime(xltimeinput, wb.datemode)
    except ValueError:
        print('You passed in an argument in that can not be translated to a datetime.')
        print('Will return original value and carry on')
        retVal = xltimeinput

    return retVal
person J Richard Snape    schedule 24.02.2015
comment
Я не могу подтвердить, что это работает, так как я сталкиваюсь с проблемой, что мне, очевидно, нужно пропустить столбец 1, который содержит заголовок. Я получаю ValueError: недопустимый литерал для int() с базой 10: ошибка Vertragsbeginn - person f0rd42; 25.02.2015
comment
да, извините, нужно было что-то добавить, чтобы пропустить строку 1. Об этом говорит ваша ошибка (попытка преобразовать строковый литерал 'Vertragsbeginn' не сработает!). С другой стороны, похоже, что вы правильно указали номера столбцов, поскольку Vertragsbeginn, вероятно, является датой, если только мой немецкий не очень плохой. :) Смотрите мое обновление. Примечание. Вы можете указать условия для пропуска более одной строки, просто изменив диапазон, который перебирает rownum. - person J Richard Snape; 25.02.2015
comment
Великолепно, я нашел точно такой же код в то же время самостоятельно, рад, что не хочу слишком выкручиваться, потому что теперь я получаю: ValueError: недопустимый литерал для int() с основанием 10: ''. Я считаю, что это связано с тем, что не все ячейки на самом деле содержат значение, т. е. если дата окончания контракта еще не определена, ячейка пуста. - person f0rd42; 25.02.2015
comment
Вам нужно включить тест if для пустых ячеек — либо в цикле for, либо в любой другой функции excel_time_to_string(), с которой вы работали. Вы можете сделать это простым способом (например, if value != '':) или сделать что-то более комплексное, например поместить код перевода в блоке try-catch с except ValueError: и заставьте ваш код просто использовать необработанное значение, если он не может выполнить перевод. Я могу поместить код в ответ, если хотите, но это может помочь вам разобраться, как это сделать самостоятельно - дайте мне знать. - person J Richard Snape; 25.02.2015
comment
Я пробовал несколько возможных комбинаций безуспешно. Как упоминалось один или два раза: я полный новичок в программировании (не только в python) и поэтому лучший редактор, чем автор :-) Я был бы признателен за некоторые дополнительные подсказки. Мне нравится идея выяснить это самостоятельно, что я и предпочитаю все время, пока с этим сценарием это просто какой-то кошмар. Я думаю, вы понимаете, что я имею в виду .-) спасибо - person f0rd42; 25.02.2015
comment
Нет проблем - мы здесь, чтобы учиться. Я добавлю более красивый пример для excel_time_to_string(), чтобы вы могли увидеть, как может выглядеть проверка ошибок. - person J Richard Snape; 25.02.2015

Преобразование из Excel в Python довольно просто:

>>> excel_time = 42054.441953
>>> datetime.datetime(1899,12,30) + datetime.timedelta(days=excel_time)
datetime.datetime(2015, 2, 19, 10, 36, 24, 739200)

Или сделать полное преобразование в строку:

def excel_time_to_string(excel_time, fmt='%Y-%m-%d %H:%M:%S'):
    dt = datetime.datetime(1899,12,30) + datetime.timedelta(days=excel_time)
    return dt.strftime(fmt)

>>> excel_time_to_string(42054.441953)
'2015-02-19 10:36:24'
>>> excel_time_to_string(42054.441953, '%d/%m/%y')
'19/02/15'
person Mark Ransom    schedule 19.02.2015
comment
@Марк, я знаю, это то, что я нашел и среди других, но я изо всех сил пытаюсь включить это в код, упомянутый выше (т. Е. Делая магию в каждом поле даты, найденном в каждой строке). Как уже упоминалось, я новичок в Python. Спасибо - person f0rd42; 19.02.2015
comment
@AndreDieball, как упоминалось в документации xlrd, для дат Excel нет отдельного типа, это просто числа. В примере, который я вам привел, показано, как преобразовать число с плавающей запятой в Python datetime. Я добавил код для преобразования его в строку. - person Mark Ransom; 20.02.2015