使用Python按日期对CSV进行排序

4
我正在尝试对CSV文件进行排序,并希望按日期的倒序排序:最新的排在前面。
def SortCsvByField( filename, fieldNo, sep = ',' ):
   records = [line.split(sep) for line in file(filename)]

如果只是比较日期,那就很简单了。但如何比较日期和时间呢?


你展示的内容相当简单,但也相当脆弱。最好使用Python的CSV库:http://docs.python.org/library/csv.html。关于比较日期(我假设某些日期在每行的特定列中),您可以使用datetime模块:http://docs.python.org/library/datetime.html。您可以在日期对象上使用标准比较运算符。 - Vinko Vrsalovic
这取决于日期的格式。 - SilentGhost
3个回答

5
我建议安装优秀的dateutil模块。(在Ubuntu/Debian中,它由python-dateutil软件包提供)。
dateutil可以将日期字符串解析为datetime对象:它可以处理许多不同的日期格式,而您无需动手(*):
import dateutil.parser as dparser
date=dparser.parse("Mon May 7 1883 10:36:28")
print(date)
# 1883-05-07 10:36:28

date=dparser.parse("1685-3-21")
print(date)
# 1685-03-21 00:00:00

date=dparser.parse("12/17/1770")
print(date)
# 1770-12-17 00:00:00

请注意,解析器将"12/17/1770"解释为"MM/DD/YYYY"的形式。您可以使用解析器的dayfirstyearfirst选项更改此行为。(参见http://labix.org/python-dateutil)
print(type(date))
# <type 'datetime.datetime'>

datetime对象可以轻松排序:

dates=[dparser.parse("Mon May 7 1883 10:36:28"),dparser.parse("1685-3-21"),dparser.parse("12/17/1770"),]
dates.sort()
print(dates)
# [datetime.date(1685, 3, 21), datetime.date(1770, 12, 17), datetime.date(1833, 5, 7)]

如果您不想安装dateutil包,那么您需要自己编写将日期字符串转换为datetime对象的方法。这需要更多的工作,因为您需要定义格式。下面的“%Y-%m-%d”定义了YYYY-MM-DD格式。有关可用格式代码的更多信息,请参见http://au2.php.net/strftime(或strftime的man页面)。
例如,
dates=[datetime.datetime.strptime(date_str,'%Y-%m-%d') for date_str in
       ('1883-5-7','1685-3-21','1770-12-17',)]
print([str(date) for date in dates])
# ['1883-05-07 00:00:00', '1685-03-21 00:00:00', '1770-12-17 00:00:00']
dates.sort()
print([str(date) for date in dates])
# ['1685-03-21 00:00:00', '1770-12-17 00:00:00', '1883-05-07 00:00:00']

使用 datetime.datetime.strftime() 方法,可以控制将 datetime 对象转换回可打印字符串时的格式。

(1) 如果你正在使用Linux?dateutil有什么平台依赖性吗?它似乎在Windows上运行良好(但请参见下面的第3点)。(2) 日期前缀为“#”,例如“#2009-09-25 10:36:28”?print()输出的结果?如果是这样,那么它们是错误的。应该是如“1883-05-07 10:36:28”所示。(3) 它会将“01/02/2009”解释为按照DD/MM/YYYY约定的2月份的第一天,而不需要他们抬手吗?它不会做像默默地将“31/12/2008”作为12月31日,同时又将“01/02/2009”作为1月2日那样的恶劣事情,对吧? - John Machin
这是一个不错的开始,但您尚未解决默认情况下欣然接受混合dd/mm和mm/dd日期的问题,并且(据我所知)没有选择“严格”行为的选项。 - John Machin
1
我不明白为什么默认情况下它会自动在没有指定月份和日期的日期后面添加10-19。例如,1946年变成了1946-10-19,而46变成了2046-10-19。我们能改变这个默认行为吗? - ThinkCode
@ThinkCode:它附加了10-19,因为今天是10月19日。您希望dparser.parse('1946')返回什么? - unutbu
哎呀,我怎么会错过那个!好吧,我把它应用到了出生日期列上,只有1946年的显示为1946-10-19。感谢您澄清了这一点。我们指定默认日期/月份将使其更加出色。我想这只是if else块。感谢您拼错Ubuntu! - ThinkCode
很高兴你解决了那个问题,拼错了TechnoKid! - unutbu

2
假设您已经知道日期的格式,并且它们在CSV文件的第一列中:
>>> import csv
>>> from datetime import datetime
>>> def date_key(row):
        return datetime.strptime(row[1].strip(), "%m/%d/%Y")

>>> with open('c:\\temp\\test\\date_test.csv', 'rb') as f:
        data = list(csv.reader(f))

>>> data
[['foo', ' 3/11/2004'], ['bar', ' 2/15/2001'], ['baz', '11/15/2007'], ['bat', '10/13/2002']]
>>> data.sort(key=date_key)
>>> data
[['bar', ' 2/15/2001'], ['bat', '10/13/2002'], ['foo', ' 3/11/2004'], ['baz', '11/15/2007']]

2
如果您的日期是ISO-8601格式(YYYY-MM-DD),则可以将其作为字符串进行排序,否则您需要首先解析它们(datetime.strptime)。然后,您可以使用例如sorted(records, key=lambda a:a[1])进行排序,如果日期是第二个字段。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接