将月份转换为数字时如何有效地检查不同的日期格式

How to efficiently check different date formats when converting month to number

我正在尝试将给定月份转换为整数格式的月份数字。我想尝试转换三种有效格式。以字符串形式给出的月份数字(输入函数 returns 字符串)、月份缩写和完整的月份名称。

虽然我的函数按预期工作,但我觉得它写得不太好,尽管我尝试使其尽可能简洁。特别是,我不高兴我有一个刚刚通过的 except 语句。处理字符串到整数的转换并检查字符串是否是要转换为整数的有效月份是一项艰巨的任务。

我尝试更改 try-excepts 的顺序,删除 string-to-int 以使其位于 try-except 块上,而不是直接进入异常中的日期格式,但仅此而已。下面的功能是我做过的最好的尝试。除了可能创建辅助函数,我想不出其他任何东西?

代码

def get_start_month_updated():
    date_formats = ['%b', '%B']
    while True:
        month = input("What is the starting month?")
        try:
            month_num = int(month)
            if 1 <= month_num <= 12:
                return month_num
        except ValueError:
            for date_format in date_formats:
                try:
                    month_num = strptime(month, date_format).tm_mon
                    return month_num
                except ValueError:
                    pass
            else:
                print("You must enter a valid month")
        else:
            print("You must enter a valid month")

我的结果是正确的,函数按预期工作,但我觉得代码很乱,有更好的方法可以做到这一点而不会让人费解。

首先,您应该创建一个 parse_month 函数以便更好地测试。 此 parse_month 函数可以有多个内部解析器,每种格式一个:"int"、带“%b”的日期时间、带“%B”的日期时间。这是实现细节。

一种方法可以是:

import datetime
import functools


def parse_month(value):
    def from_int(v):
        month_num = int(v)
        if 1 <= month_num <= 12:
            return month_num
        raise ValueError(v)

    def from_month_fmt(fmt, v):
        return datetime.datetime.strptime(v, fmt).month

    parsers = (
        from_int,
        functools.partial(from_month_fmt, "%b"),
        functools.partial(from_month_fmt, "%B"),
    )
    for parser in parsers:
        try:
            return parser(value)
        except ValueError:
            pass
    else:
        raise ValueError(value)

然后,你可以使用这个函数来提示用户:

def get_start_month_updated():
    while True:
        month = input("What is the starting month?")
        try:
            month_num = parse_month(month)
        except ValueError:
            print("You must enter a valid month")
        else:
            return month_num

如果你不想重新发明轮子,Arrow是你的朋友:

import arrow

def parse_month(value):
    formats = (
        "MMMM",
        "MMM",
        "MM",
        "M"
    )
    for fmt in formats:
        try:
            return arrow.get(value, fmt).month
        except arrow.parser.ParserError:
            pass
    else:
        raise ValueError(value)