dateutils默认为已识别零件的最后一次出现,而不是下一次出现

问题描述 投票:0回答:1

我使用dateutils.parser.parse来解析可能包含部分信息的日期字符串。如果某些信息不存在,parse可以使用default关键字参数来填充任何缺失的字段。此默认值默认为datetime.datetime.today()

对于像dateutil.parser.parse("Thursday")这样的情况,这意味着它将返回下周四的日期。但是,我需要它来返回上周四的日期(包括今天,如果今天恰好是星期四)。

所以,假设today == datetime.datetime(2018, 2, 20)(星期二),我想让所有这些asserts成为现实:

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会通过。

python datetime date-parsing python-dateutil
1个回答
2
投票

这是您修改后的代码(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)

笔记:

  • 我对代码的结构进行了“改动”,以便对其进行参数化,因此如果需要进行更改(例如,要添加的新示例),则更改应该是最小的 而不是断言,我添加了一个打印结果的函数(print_stats)(如果事情不匹配,则会引发AssertError并退出程序) 采用参数(parse_func),它是一个执行解析的函数(例如解析) 使用一些全局声明的数据(数据)和(上面)函数 data - 是三元组列表,其中每个三元组包含: 要转换的文本 转换产生的预期日期时间([Python 3.Docs]: datetime Objects) 要传递给解析函数的默认参数(parse_func)
  • parse2函数(解析的改进版本): 接受2种类型的日期字符串: 平日名称 月/日(无序) 常规解析,如果转换后的对象在作为默认参数传递的对象之后(通过比较2个对象的适当属性确定),它会减去一个句点(看看[Python 3.Docs]: timedelta Objects): “星期四”在“星期二”之后,所以它减去一周内的天数(7) “12月10日”在“2月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 * - 正如您可能猜到的那样,返回一年中的天数(不能简单地减去365,因为闰年​​可能会搞砸了): >>> 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\StackOverflow\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]
© www.soinside.com 2019 - 2024. All rights reserved.