dateutils 默认为识别部分的最后一次出现,而不是下一次
dateutils default to the last occurence of recognized part, not next
我正在使用 dateutils.parser.parse
来解析可能包含部分信息的日期字符串。如果某些信息不存在,parse
可以采用 default
关键字参数,它将从中填充任何缺失的字段。此默认值默认为 datetime.datetime.today()
.
对于 dateutil.parser.parse("Thursday")
这样的案例,这意味着它将 return 日期为 下一个 星期四。但是,我需要 return 最后一个 星期四的日期(包括今天,如果今天恰好是星期四的话)。
所以,假设 today == datetime.datetime(2018, 2, 20)
(星期二),我想让所有这些 assert
都为真:
from dateutil import parser
from datetime import datetime
def parse(date_str, default=None):
# this needs to be modified
return parser.parse(date_str, default=default)
today = datetime(2018, 2, 20)
assert parse("Tuesday", default=today) == today # True
assert parse("Thursday", default=today) == datetime(2018, 2, 15) # False
assert parse("Jan 31", default=today) == datetime(2018, 1, 31) # True
assert parse("December 10", default=today) == datetime(2017, 12, 10) # False
有没有简单的方法可以做到这一点?使用当前的 parse
函数,只有第一个和第三个 assert
会通过。
这是您修改后的代码 (code.py):
#!/usr/bin/env python3
import sys
from dateutil import parser
from datetime import datetime, timedelta
today = datetime(2018, 2, 20)
data = [
("Tuesday", today, today),
("Thursday", datetime(2018, 2, 15), today),
("Jan 31", datetime(2018, 1, 31), today),
("December 10", datetime(2017, 12, 10), today),
]
def parse(date_str, default=None):
# this needs to be modified
return parser.parse(date_str, default=default)
def _days_in_year(year):
try:
datetime(year, 2, 29)
except ValueError:
return 365
return 366
def parse2(date_str, default=None):
dt = parser.parse(date_str, default=default)
if default is not None:
weekday_strs = [day_str.lower() for day_tuple in parser.parserinfo.WEEKDAYS for day_str in day_tuple]
if date_str.lower() in weekday_strs:
if dt.weekday() > default.weekday():
dt -= timedelta(days=7)
else:
if (dt.month > today.month) or ((dt.month == today.month) and (dt.day > today.day)):
dt -= timedelta(days=_days_in_year(dt.year))
return dt
def print_stats(parse_func):
print("\nPrinting stats for \"{:s}\"".format(parse_func.__name__))
for triple in data:
d = parse_func(triple[0], default=triple[2])
print(" [{:s}] [{:s}] [{:s}] [{:s}]".format(triple[0], str(d), str(triple[1]), "True" if d == triple[1] else "False"))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
print_stats(parse)
print_stats(parse2)
备注:
- 我更改了代码的结构 "a bit",对其进行参数化,因此如果需要更改(例如要添加的新示例),更改应该是最小的
- 我添加了一个函数 (print_stats,而不是 asserts,而是打印结果(而不是提高 AssertError 如果不匹配则退出程序)
- 接受一个参数 (parse_func),这是一个进行解析的函数(例如 parse)
- 使用一些全局声明的数据(数据)和(以上)函数
- data - 是一个三元组列表,其中每个三元组包含:
- 要转换的文本
- 预期 日期时间 ([Python 3.Docs]: datetime Objects) 由转换
产生
- 默认参数传递给解析函数(parse_func)
parse2函数(parse的改进版):
- 接受 2 种类型的日期字符串:
- 工作日名称
- 月/日(未排序)
- 进行常规解析,如果转换后的对象在 之后作为 default 参数传递(通过比较确定2 个对象的适当属性),它减去一个句点(看看 [Python 3.Docs]: timedelta Objects):
- "Thursday"在"Tuesday"之后,所以它减去一周的天数(7)
- "December 10"在"February 20"之后,所以减去一年中的天数*
weekday_strs:我最好举例说明一下:
>>> parser.parserinfo.WEEKDAYS
[('Mon', 'Monday'), ('Tue', 'Tuesday'), ('Wed', 'Wednesday'), ('Thu', 'Thursday'), ('Fri', 'Friday'), ('Sat', 'Saturday'), ('Sun', 'Sunday')]
>>> [day_str.lower() for day_tuple in parser.parserinfo.WEEKDAYS for day_str in day_tuple]
['mon', 'monday', 'tue', 'tuesday', 'wed', 'wednesday', 'thu', 'thursday', 'fri', 'friday', 'sat', 'saturday', 'sun', 'sunday']
- 变平
parser.parserinfo.WEEKDAYS
- 将字符串转换为小写(为了简化比较)
- _days_in_year* - 你可能已经猜到了,returns 一年中的天数(不能简单地减去 365,因为 leap 年可能会把事情搞砸):
>>> dt = datetime(2018, 3, 1)
>>> dt
datetime.datetime(2018, 3, 1, 0, 0)
>>> dt - timedelta(365)
datetime.datetime(2017, 3, 1, 0, 0)
>>> dt = datetime(2016, 3, 1)
>>> dt
datetime.datetime(2016, 3, 1, 0, 0)
>>> dt - timedelta(365)
datetime.datetime(2015, 3, 2, 0, 0)
输出:
(py35x64_test) E:\Work\Dev\Whosebug\q048884480>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
Printing stats for "parse"
[Tuesday] [2018-02-20 00:00:00] [2018-02-20 00:00:00] [True]
[Thursday] [2018-02-22 00:00:00] [2018-02-15 00:00:00] [False]
[Jan 31] [2018-01-31 00:00:00] [2018-01-31 00:00:00] [True]
[December 10] [2018-12-10 00:00:00] [2017-12-10 00:00:00] [False]
Printing stats for "parse2"
[Tuesday] [2018-02-20 00:00:00] [2018-02-20 00:00:00] [True]
[Thursday] [2018-02-15 00:00:00] [2018-02-15 00:00:00] [True]
[Jan 31] [2018-01-31 00:00:00] [2018-01-31 00:00:00] [True]
[December 10] [2017-12-10 00:00:00] [2017-12-10 00:00:00] [True]
我正在使用 dateutils.parser.parse
来解析可能包含部分信息的日期字符串。如果某些信息不存在,parse
可以采用 default
关键字参数,它将从中填充任何缺失的字段。此默认值默认为 datetime.datetime.today()
.
对于 dateutil.parser.parse("Thursday")
这样的案例,这意味着它将 return 日期为 下一个 星期四。但是,我需要 return 最后一个 星期四的日期(包括今天,如果今天恰好是星期四的话)。
所以,假设 today == datetime.datetime(2018, 2, 20)
(星期二),我想让所有这些 assert
都为真:
from dateutil import parser
from datetime import datetime
def parse(date_str, default=None):
# this needs to be modified
return parser.parse(date_str, default=default)
today = datetime(2018, 2, 20)
assert parse("Tuesday", default=today) == today # True
assert parse("Thursday", default=today) == datetime(2018, 2, 15) # False
assert parse("Jan 31", default=today) == datetime(2018, 1, 31) # True
assert parse("December 10", default=today) == datetime(2017, 12, 10) # False
有没有简单的方法可以做到这一点?使用当前的 parse
函数,只有第一个和第三个 assert
会通过。
这是您修改后的代码 (code.py):
#!/usr/bin/env python3
import sys
from dateutil import parser
from datetime import datetime, timedelta
today = datetime(2018, 2, 20)
data = [
("Tuesday", today, today),
("Thursday", datetime(2018, 2, 15), today),
("Jan 31", datetime(2018, 1, 31), today),
("December 10", datetime(2017, 12, 10), today),
]
def parse(date_str, default=None):
# this needs to be modified
return parser.parse(date_str, default=default)
def _days_in_year(year):
try:
datetime(year, 2, 29)
except ValueError:
return 365
return 366
def parse2(date_str, default=None):
dt = parser.parse(date_str, default=default)
if default is not None:
weekday_strs = [day_str.lower() for day_tuple in parser.parserinfo.WEEKDAYS for day_str in day_tuple]
if date_str.lower() in weekday_strs:
if dt.weekday() > default.weekday():
dt -= timedelta(days=7)
else:
if (dt.month > today.month) or ((dt.month == today.month) and (dt.day > today.day)):
dt -= timedelta(days=_days_in_year(dt.year))
return dt
def print_stats(parse_func):
print("\nPrinting stats for \"{:s}\"".format(parse_func.__name__))
for triple in data:
d = parse_func(triple[0], default=triple[2])
print(" [{:s}] [{:s}] [{:s}] [{:s}]".format(triple[0], str(d), str(triple[1]), "True" if d == triple[1] else "False"))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
print_stats(parse)
print_stats(parse2)
备注:
- 我更改了代码的结构 "a bit",对其进行参数化,因此如果需要更改(例如要添加的新示例),更改应该是最小的
- 我添加了一个函数 (print_stats,而不是 asserts,而是打印结果(而不是提高 AssertError 如果不匹配则退出程序)
- 接受一个参数 (parse_func),这是一个进行解析的函数(例如 parse)
- 使用一些全局声明的数据(数据)和(以上)函数
- data - 是一个三元组列表,其中每个三元组包含:
- 要转换的文本
- 预期 日期时间 ([Python 3.Docs]: datetime Objects) 由转换 产生
- 默认参数传递给解析函数(parse_func)
- 我添加了一个函数 (print_stats,而不是 asserts,而是打印结果(而不是提高 AssertError 如果不匹配则退出程序)
parse2函数(parse的改进版):
- 接受 2 种类型的日期字符串:
- 工作日名称
- 月/日(未排序)
- 进行常规解析,如果转换后的对象在 之后作为 default 参数传递(通过比较确定2 个对象的适当属性),它减去一个句点(看看 [Python 3.Docs]: timedelta Objects):
- "Thursday"在"Tuesday"之后,所以它减去一周的天数(7)
- "December 10"在"February 20"之后,所以减去一年中的天数*
weekday_strs:我最好举例说明一下:
>>> parser.parserinfo.WEEKDAYS [('Mon', 'Monday'), ('Tue', 'Tuesday'), ('Wed', 'Wednesday'), ('Thu', 'Thursday'), ('Fri', 'Friday'), ('Sat', 'Saturday'), ('Sun', 'Sunday')] >>> [day_str.lower() for day_tuple in parser.parserinfo.WEEKDAYS for day_str in day_tuple] ['mon', 'monday', 'tue', 'tuesday', 'wed', 'wednesday', 'thu', 'thursday', 'fri', 'friday', 'sat', 'saturday', 'sun', 'sunday']
- 变平
parser.parserinfo.WEEKDAYS
- 将字符串转换为小写(为了简化比较)
- 变平
- 接受 2 种类型的日期字符串:
- _days_in_year* - 你可能已经猜到了,returns 一年中的天数(不能简单地减去 365,因为 leap 年可能会把事情搞砸):
>>> dt = datetime(2018, 3, 1) >>> dt datetime.datetime(2018, 3, 1, 0, 0) >>> dt - timedelta(365) datetime.datetime(2017, 3, 1, 0, 0) >>> dt = datetime(2016, 3, 1) >>> dt datetime.datetime(2016, 3, 1, 0, 0) >>> dt - timedelta(365) datetime.datetime(2015, 3, 2, 0, 0)
输出:
(py35x64_test) E:\Work\Dev\Whosebug\q048884480>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 Printing stats for "parse" [Tuesday] [2018-02-20 00:00:00] [2018-02-20 00:00:00] [True] [Thursday] [2018-02-22 00:00:00] [2018-02-15 00:00:00] [False] [Jan 31] [2018-01-31 00:00:00] [2018-01-31 00:00:00] [True] [December 10] [2018-12-10 00:00:00] [2017-12-10 00:00:00] [False] Printing stats for "parse2" [Tuesday] [2018-02-20 00:00:00] [2018-02-20 00:00:00] [True] [Thursday] [2018-02-15 00:00:00] [2018-02-15 00:00:00] [True] [Jan 31] [2018-01-31 00:00:00] [2018-01-31 00:00:00] [True] [December 10] [2017-12-10 00:00:00] [2017-12-10 00:00:00] [True]