日期范围的通配符表示-附python代码

Posted BJUT赵亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日期范围的通配符表示-附python代码相关的知识,希望对你有一定的参考价值。

本文记录了将给定的日期范围用通配符表示的相关内容,欢迎与我沟通联系(zhaoliang19960421@outlook.com)
如果在使用中发现程序输入与结果不符,欢迎与我沟通

在hdfs中数据以date为分区进行分别保存,采用MapReduce框架进行大数据开发时在路径输入中,没有在hive\\sql中的 date between . and . 的写法,与之对应的是将日期采用通配符的形式进行输入
case1 日期范围是:20220101 20221231

解释:需要输入的是2022年一整年的数据,所以采用通配符的表达方式为2022*

case2 日期范围是 : 20210101 20210331

解释:需要输入的2021年,1月、2月、3月的全部日期,采用通配符的表示方式是 '202101*', '202102*', '202103*'

case3 日起范围是:20200104 20210302

解释:需要输入的是,从1月4号到1月底,2月整月、3月1号,3月2号的日期,采用通配符的表示方式是 ['20200104', '20200105', '20200106', '20200107', '20200108', '20200109', '2020011*', '2020012*', '2020013*', '202002*', '202003*', '202004*', '202005*', '202006*', '202007*', '202008*', '202009*', '202010*', '202011*', '202012*', '202101*', '202102*', '20210301', '20210302']
因为1月4号到1月9号,无法继续采用通配符,所以全部枚举;1月10号到1月19号、1月11号到19号、1月21号到1月29号、1月30号到1月31号,均可以用通配符。

将以上问题抽象为数学问题是,给定一个函数,输入的是2个字符串[start,end]的日期范围,输出一个字符串数组,这个字符串数组是给定日期范围的通配符表示式的最简结果

具体的解法为递归,在给定日期范围种,先判断年,如果年不相同,则将中间的年份抽出来,前后两端分别判单,则成为了递归

20200101       20200101-20201231
	    =》     2021
20221231       20220101-20221231     

中间的日期通过通配符表示,前后两端继续递归,直到最后的日期

def function(start: str, end: str):
    def _yyyyMM2dd(yyyy, MM):
        if MM in 1, 3, 5, 7, 8, 10, 12:
            return 31
        if MM != 2:
            return 30
        if (yyyy % 4 == 0) and (yyyy % 100 != 0) or (yyyy % 400) == 0:
            return 29
        else:
            return 28

    if start == end: return [start]
    if start > end: return []
    res = []
    if start[:4] != end[:4]:  # 年不相同,中间的年份全部用通配符
        for i in range(int(start[:4]) + 1, int(end[:4])):
            res.append(":0>4*".format(i))
        res.extend(function(start, f"start[:4]1231"))
        res.extend(function(f"end[:4]0101", end))
        return res
    if start[4:6] != end[4:6]:  # 月份不一样
        for i in range(int(start[4:6]) + 1, int(end[4:6])):
            res.append(":0>2*".format(start[:4], i))
        res.extend(function(start, f"start[:6]_yyyyMM2dd(int(start[:4]), int(start[4:6]))"))
        res.extend(function(f"end[:6]01", end))
        if len(res)==12 and len(list(set([i[4:6] for i in res]))) == 12:
            res = ["*".format(start[:4])]
        return res
    if start[6:8] != end[6:8]:  # 日期不同
        if start[6] != end[6]:
            for i in range(int(start[6]) + 1, int(end[6])):
                res.append("*".format(start[:6], i))

            if start[6] in ["0", "1"]:
                start_day_last_num = 9
            elif start[6] == "2":
                if _yyyyMM2dd(int(start[:4]), int(start[4:6])) == 28:
                    start_day_last_num = 8
                else:
                    start_day_last_num = 9
            elif start[6] == "3":
                start_day_last_num = 1
            res.extend(function(start, f"start[:7]start_day_last_num"))
            if end[6] == "0":
                end_day_first_num = 1
            else:
                end_day_first_num = 0
            res.extend(function(f"end[:7]end_day_first_num", end))

            # print(res)
            if int(start[4:6]) == 2:
                if len(res)==3 and len(list(set([i[6] for i in res]))) == 3:
                    res = ["*".format(start[:6])]
            else:
                if len(res)==4 and len(list(set([i[6] for i in res]))) == 4:
                    res = ["*".format(start[:6])]
            # print(res)
            # print()
            return res
        if start[7] != end[7]:
            for i in range(int(start[7]), int(end[7]) + 1):
                res.append("".format(start[:7], i))
            # 剪枝合并
            # print(res)
            if int(start[4:6]) in [1, 3, 5, 7, 8, 10, 12]:
                if (start[6] == "0" and len(res) == 9) or (start[6] in ["1", "2"] and len(res) == 10) or (
                        start[6] == "3" and len(res) == 2):
                    res = ["*".format(start[:7])]
            elif int(start[4:6]) == 2:
                if _yyyyMM2dd(int(start[:4]), int(start[4:6])) == 29:
                    if (start[6] == "0" and len(res) == 9) or (start[6] in ["1", "2"] and len(res) == 10):
                        res = ["*".format(start[:7])]
                else:
                    if (start[6] == "0" and len(res) == 9) or (start[6] == "1" and len(res) == 10) or (
                            start[6] == "2" and len(res) == 9):
                        res = ["*".format(start[:7])]

            else:
                if (start[6] == "0" and len(res) == 9) or (start[6] in ["1", "2"] and len(res) == 10) or (
                        start[6] == "3" and len(res) == 1):
                    res = ["*".format(start[:7])]
            # print(res)
            # print()
            return res


res = function("20201227", "20210302")
res.sort()
print(res)


function("20210101", "20210331") => ['202101*', '202102*', '202103*']
function("20210101", "20211231") => ['2021*']
function("20200101", "20211231") => ['2020*', '2021*']
function("20200104", "20210302") => ['20200104', '20200105', '20200106', '20200107', '20200108', '20200109', '2020011*', '2020012*', '2020013*', '202002*', '202003*', '202004*', '202005*', '202006*', '202007*', '202008*', '202009*', '202010*', '202011*', '202012*', '202101*', '202102*', '20210301', '20210302']
function("20210104", "20210302") => ['20210104', '20210105', '20210106', '20210107', '20210108', '20210109', '2021011*', '2021012*', '2021013*', '202102*', '20210301', '20210302']

以上是关于日期范围的通配符表示-附python代码的主要内容,如果未能解决你的问题,请参考以下文章

日期范围的通配符表示-附pythonScala代码

Python数据分析分组聚合重采样典型例题及其解法

使用具有相对日期范围和标准 SQL 的 Bigquery Table 通配符 [重复]

Python日期时间差的计算(天/小时/分钟)及timedelta函数的使用(附python代码)

quartz表达式介绍

Linux 正则表达式和通配符 以及Python断言