使用parsedatetime库,能否将日期限制为当前年份?

0 投票
6 回答
741 浏览
提问于 2025-04-18 15:42

我想用 parsedatetime 这个工具,把像 Jan 1 这样的值传给日历解析器,希望它能返回当前年份的1月1日(比如现在发这个帖子时,就是 2014-01-01)。

不过,默认情况下,parsedatetime 返回的是这个日期的下一个出现时间(也就是 2015-01-01):

>>> import parsedatetime as pdt
>>> from datetime import datetime
>>> from time import mktime
>>> cal = pdt.Calendar()
>>> datetime.now()
datetime.datetime(2014, 8, 1, 15, 41, 7, 486294)
>>> str(datetime.fromtimestamp(mktime(cal.parse('Jan 1')[0])))
'2015-01-01 14:41:13'
>>> str(datetime.fromtimestamp(mktime(cal.parse('Dec 31')[0])))
'2014-12-31 14:41:17'

我试过输入像 last Jan 1Jan 1 this year,但是都没有成功。

有没有办法让解析器返回当前年份的值呢?


我补充一下原问题中没有提到的几个要求:

  • 支持自然语言处理(这就是我使用 parsedatetime 的原因)
  • 不影响 parsedatetime 的其他解析功能(比如处理当前年份以外的年份,以及像 yesterday6 months before 3/1 这样的值)

6 个回答

0

如果你不一定要使用那个库(也许你是吗?),你可以这样做:

>>> import datetime
>>> datetime.datetime.now().replace(month=1, day=1).strftime("%Y-%m-%d %H:%M:%S")
'2014-01-01 22:55:56'
>>>
0

这是一个基于Bear的回答改进的实现。

需要注意的是,由于这个实现是在另一个DSL解析器中进行的,natural_date只能接受一个字符串:

import parsedatetime as pdt
from datetime import datetime, date, timedelta
from time import mktime


def natural_date(human_readable):
    human_readable = human_readable.lower()

    # Flag to cause parsedatetime to never go forward
    # https://stackoverflow.com/a/25098991/1093087
    ptc = pdt.Constants()
    ptc.YearParseStyle = 0
    cal = pdt.Calendar(ptc)

    result, parsed_as = cal.parse(human_readable)

    if not parsed_as:
        raise ValueError("Unable to parse %s" % (human_readable))

    return date.fromtimestamp(mktime(result))


def test_natural_date():
    cases = [
        # input, expect
        ('jan 1', date(date.today().year, 1, 1)),
        ('dec 31', date(date.today().year, 12, 31)),
        ('yesterday', date.today() - timedelta(days=1)),
        ('3 months before 12/31', date(date.today().year, 9, 30))
    ]

    for human_readable, expect in cases:
        result = natural_date(human_readable)
        print("%s -> %s" % (human_readable, result))
        assert result == expect, human_readable


test_natural_date()

同时也要感谢Mark Ransom,他发现了sourceTime参数,这为解决这个问题提供了另一种方法,尽管这个解决方案受到这个问题的影响,变得有些复杂。

1

我建议你把你的日期时间对象中的年份替换掉。例如:

str(datetime.fromtimestamp(mktime(cal.parse('Dec 31')[0])))

就会变成:

str(datetime.fromtimestamp(mktime(cal.parse('Dec 31')[0])).replace(year=datetime.today().year))
3

这里是Bear - 我不知道怎么才能找回我原来的Stack Overflow个人资料,因为我以前用的是ClaimID...

不过,你可以设置一个标志,让parsedatetime在只解析月份和日期的时候,永远不会往前推一年...

import parsedatetime as pdt
ptc = pdt.Constants()
ptc.YearParseStyle = 0

cal = pdt.Calendar(ptc)
print cal.parse('Jan 1')
# ((2014, 1, 1, 15, 57, 32, 5, 214, 1), 1)
2

parse 函数似乎需要一个叫 sourceTime 的参数,你可以把它设置为当前年的第一天。

可以查看这个链接了解更多信息:https://bear.im/code/parsedatetime/docs/index.html

撰写回答