python实现以立春为起点n为周期任意日期所在的日期区间
python实现以立春为起点n为周期任意日期所在的日期区间
需求
话不多说,直接上具体需求。
''' 以每年的立春作为起始点,每N天为一个单元,任给一个日期,返回该日期所在单元的起始和结束日期。例如:N=3, 输入日期20180208,返回20180207,20180209(2018年的立春是20180204,所以第一个单元是20180204-20180206,第二个单元是 20180207-20180209,依次类推) '''
分析
上边的需求乍一看还挺简单,但是具体实现起来还是需要对time模块、datatime模块、sxtwl模块的熟练应用。
首先呢,要求以立春为起始点,那么说我们可以找出立春在一年中的第num_day_0天,同时我们也找出我们输入的日期在一年中的第num_day_x天。这样一来,我们就可以计算出这两天相差的天数day_diff,使用day_diff除以周期N,就可以确定我们输入的日期是在周期日期区间的边线还是在日期区间的中间。然后我们就可以根据输入日期在一年中的第num_day_x以及相差的天数day_diff来计算出需要的日期区间,最麻烦的就在于根据num_day求日期了。
其中的难点我认为有两点,一是根据输入的年份来确定立春的阳历日期,二就是计算日期区间了。当然了,这些对大神来说都是so easy!下来我们看代码。
实现
立春日期
立春日期的确定,我费了不少劲,网上各种查找,偶然间看到了sxtwl模块,于是找到了它的官方文档,参考官方文档中的演示代码,写下了下边的代码,其实这个模块我也没看得很明白,也没怎么看,就发现我使用jqmc方法可以确定立春日期。
这里解释下,我多次实验发现,当day.jqmc的值为3时,这天就为立春,其他日期返回值为0。附上官方文档的部分资料:
''' jqmc = ["冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑","白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪"] '''
看完这个列表你就能发现,立春的索引为3,于是就这样含糊的写出了计算立春的代码。
import sxtwl def getTerms(year, month, day): lunar = sxtwl.Lunar() # 实例化日历库 day = lunar.getDayBySolar(year, month, day) return day.jqmc # 0为非春分;3为春分
num_day转日期
接下来就是这个计算在一年中第多少天的问题,其实这个问题并不难,因为我之前就是知道使用time模块就可以查得到。但是问题是在于知道一年中的第多少天了,怎么得出这一天在一年中的阳历日期呢。下面的代码我也是在网上找了别人的代码参考的。
import datetime def out_date(year, day): fir_day = datetime.datetime(year, 1, 1) # 每年的第一天 zone = datetime.timedelta(days=day - 1) # 日期差值day_diff return datetime.datetime.strftime(fir_day + zone, "%Y-%m-%d") # 得到日期
主代码
import time
from spring_begins import getTerms
from num_day import out_date def input_time(n, inp_time):
# 构造两个年份字典,用来判断输入时间的合法性 common_year = {'01': 31, '02': 28, '03': 31, '04': 30, '05': 31, '06': 30, '07': 31, '08': 31, '09': 30, '10': 31, '11': 30, '12': 31} leap_year = {'01': 31, '02': 29, '03': 31, '04': 30, '05': 31, '06': 30, '07': 31, '08': 31, '09': 30, '10': 31, '11': 30, '12': 31}
# 判断输入的日期是不是纯数字组成的 if not inp_time.isdigit(): return print('输入的内容有误(不是纯数字)!!!')
# 判断输入日期的长度 if len(inp_time) != 8: return print('输入的内容有误(长度有误)!!!')
# 判断输入的月份是否在正确范围内 if month_judge(inp_time[4:6]): pass else: return print('月份输入有误!!!')
# 判断平年闰年 if common_or_leap(int(inp_time[:4])): day_judge(inp_time[-2:], inp_time[4:6], leap_year)
# 判断n输入的合法性,n最大等于一年的总天数 if int(n) > 366: return print('N输入超范围!!!') else: day_judge(inp_time[-2:], inp_time[4:6], common_year) if int(n) > 365: return print('N输入超范围!!!')
# 通过查资料得出立春在每年的二月的三号到八号之间,所以遍历这六天来确定最终的日期 for i in [3, 4, 5, 6, 7, 8]: if getTerms(int(inp_time[:4]), 2, i) == 3: spring_b = f'{inp_time[:4]}020{i}' # 得到立春日期
# 立春的格式化时间,后续取一年中的第num_day用 struct_time_S = time.strptime(f'{spring_b[:4]}-{spring_b[4:6]}-{spring_b[-2:]}', '%Y-%m-%d')
# 输入日期的格式化时间 struct_time = time.strptime(f'{inp_time[:4]}-{inp_time[4:6]}-{inp_time[-2:]}', '%Y-%m-%d')
# 输入日期与立春的天数差day_diff yushu = (struct_time.tm_yday - struct_time_S.tm_yday) % int(n)
# 输出结果 print((out_date(int(inp_time[:4]), struct_time.tm_yday - yushu), out_date(int(inp_time[:4]), struct_time.tm_yday - 1 - yushu + int(n)))) def common_or_leap(years):
'''
判断日期的平闰年
'''
if years % 4 == 0 & years % 100 != 0 or years % 400 == 0: return True def month_judge(months):
'''
判断日期中月份的合法性
''' if int(months) <= 12: return True def day_judge(days, months, year_kind):
'''
判断日期中日的合法性
''' if int(days) <= year_kind[months]: return True if __name__ == '__main__': n = input('请输入周期N>>>').strip() inp_time = input('请输入日期(格式20160920)>>>').strip() input_time(n, inp_time)
以上就是我写这个需求是遇到的问题以及最终的结果,其中可能存在小的问题,本代码仅供参考。