K纪年日期<=>公元纪年日期(相互转换)

以输入日期折合总天数(以公元2018-1-1始)为媒,实现“k纪年日期”与“公元日期”的相互转换。


(笔记模板由python脚本于2024年11月07日 09:25:03创建,本篇笔记适合熟悉python基础编程的coder翻阅)


【学习的细节是欢悦的历程】


  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


等风来,不如追风去……


以输入日期折合总天数为媒
K纪年<=>公元纪年
(实现“k”日期与“公元”日期相互转换)


本文质量分:

97 97 97

本文地址: https://blog.csdn.net/m0_57158496/article/details/143585909

CSDN质量分查询入口:http://www.csdn.net/qc


目 录

  • ◆ K纪年日期<=>公元纪年日期
    • 1、题目描述
    • 2、解题逻辑
    • 3、代码实炼
      • 3.1 数据准备
        • a. “每月天数”常量
      • 3.2 闰年功能模块
        • a. 闰年判定
        • b. 统计给定年限闰年总数
      • 3.3 功能模块
        • a. 计算日期总天
        • b. 总天数转日期
        • c. 输入校验
        • d. 主程序
        • e. 功能测试
        • f. 程序入口
    • 4、优化代码


◆ K纪年日期<=>公元纪年日期


1、题目描述


  • 题目描述截屏图片
    在这里插入图片描述

编写程序对公历纪年法和K纪年法进行相互转换

K纪年法规则: 公元2018年是K纪年元年,公元2018年1月2日用K纪年法记为1年1月1日。一年由30个月组成,其中奇数月份有31天偶数月份有30天。

输入: 输入为符号a(“C” 公历日期标识or “K”K纪年日期标识)和整数y, m, d组成。
注:保证输入的日期是合法的,且转为公历日期后在2018-1-1到2999-12-31之间。

输出: a对应的“C”或者“F”日期。

示例一:
输入“K 1 2 29”,输出“C 2018 3 1”

示例一:
输入“C 2018 3 29”,输出“K 1 3 27”


题目来源于 CSDN 问答社区提问“问题标题



回页目录


2、解题逻辑


以下是针对K纪年法转换问题的“解题逻辑”:


A A A、问题理解

K纪年法是一种特殊的日期表示方法,其规则如下:

  • 公元2018年是K纪年元年,即2018年1月1日是K纪年的1年1月1日。
  • K纪年的一年由30个月组成,奇数月份有31天,偶数月份有30天。

任务要求编写一个程序,实现K纪年法与公历纪年法之间的相互转换。


B B B、解题思路

  • a a a. 公历转K纪年:
    • 确定输入的公历日期是否在2018年1月2日之后,因为这是K纪年的起始点。
    • 计算输入日期与2018年1月2日之间的总天数。
    • 将总天数转换为K纪年的年份、月份和日期。
  • b b b. K纪年转公历:
    • 确定输入的K纪年日期是否合法。
    • 计算K纪年的年份、月份和日期对应的总天数。
    • 将总天数加到2018年1月2日上,得到对应的公历日期。

C C C、关键步骤

  • a a a. 计算总天数:
    • 对于公历日期,需要考虑平年和闰年的不同天数,以及每个月的天数。
    • 对于K纪年日期,由于每个月的天数固定,可以使用算术公式直接计算总天数。
  • b b b. 日期转换:
    • 从总天数中提取出年份、月份和日期。
    • 考虑到K纪年月份的特殊性,需要特别处理月份和日期的计算。

D D D、代码实现

以下是实现转换逻辑的伪代码:


def is_leap_year(year):
    # 判断是否为闰年

def days_in_year_to_date(year, days):
    # 从年初计算到给定天数的日期

def days_to_k_year(days):
    # 将总天数转换为K纪年日期

def convert_to_k_year(y, m, d):
    # 将公历日期转换为K纪年日期

def convert_to_calendar_year(y, m, d):
    # 将K纪年日期转换为公历日期


E E E、测试与验证

  编写测试用例,确保程序能够正确处理以下情况:

  • 边界条件,如K纪年的起始和结束日期。
  • 闰年的转换。
  • 普通日期的转换。

F F F、结论

  通过以上步骤,我们可以实现K纪年法与公历纪年法之间的相互转换。代码实现需要精确考虑日期计算的细节,并确保所有可能的日期都是正确转换的。


  这份“解题逻辑”概述了解题的主要逻辑和步骤,可以根据实际代码的具体实现来进一步细化每个部分。



回页目录


3、代码实炼


3.1 数据准备


a. “每月天数”常量
  • 常量:C_MONTHS_DAY,公历每月天数;K_MONTHS_DAY,k纪年每月天数
    公历纪年每年月份少且规则相对“复杂”,我用元组结构数据;k纪年月份多达30,但天数规则齐整,生成器推导式自动生成。
    
    # 公元纪年每月最大天数列表
    C_MONTHES_DAY = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 
    # K纪年每月最大天数列表(为后面的切片方案保留)
    K_MONTHES_DAY = tuple(31 if (m+1)%2 else 30 for m in range(30)) 
    
    

3.2 闰年功能模块


a. 闰年判定
  • 闰年判定
      1582年后都是“新式”规则:年份整除4不可以整除100,或者整除400。这里不考虑“只整除4”的老规则情形。
    
    def is_leap_year(year: int) -> bool:
      ''' 新规则闰年判定
      1582年后都是“新式”规则:
      年份整除4不可以整除100,
      或者整除400。
      本题目没有“只整除4”的老规则情形 '''
      return year%400==0 or (year%4==0 and year%100!=0)
    
    

b. 统计给定年限闰年总数
  • 计算指定年限内所有闰年总数
    闰的置1平年忽略,用sum统计1的个数。
    
    def sum_leap_days(year: int) -> int:
      ''' 计算闰年总数(不含year)
      闰的置1平年忽略,用sum统计1的个数 '''
      return sum(1 for i in range(2018, year) if is_leap_year(i)) 
    
    

3.3 功能模块


a. 计算日期总天
  • 计算给定日期的总天数
    计算日期总天数:
    K K K,整年天数+整月天数(每天按30计,补加奇数月多的“31”天数)+当前月天数;或者整月天数从每天月天数元组中切片求和。
    我更喜欢“算术计算”😋,所以用前者,后者被我注释呈现)

    C C C,整年天数+整月天数+当前月天数(忽略闰年)(月份最大天数变量在脚本开始处定义);补加闰年总天数(当年月份大于2,检查闰年含当年)

    
    def sum_days(flag: str, y: int, m: int, d:int) -> int:
      ''' 计算K纪年日期总天数 '''
    
      if flag == 'K':
          days = 915*(y-1) + 30*(m-1) + m//2 + d # 整年天数+整月天数(每天按30计,补加奇数月多的“31”天数)+当前月天数
          #days = 915*(y-1) + sum(K_MONTHES_DAY[:m-1]) + d # 整月天数从每天月天数元组中切片求和(我更喜欢“算术计算”😋)
          return days
      elif flag == 'C':
          days = 365*(y-2018) + sum(C_MONTHES_DAY[:m-1]) + d # 整年天数+整月天数+当前月天数(忽略闰年)。(月份最大天数变量在脚本开始处定义)
          days += sum_leap_days(y+1) if (is_leap_year(y) and m>2) else sum_leap_days(y) # 补加闰年总天数(当年月份大于2,检查闰年含当年)
          return days
    
    

b. 总天数转日期
  • 总天数转日期
    sum_days计算出来的总天数,根据相应规则转换对应日期(这里是用循环,以功能实现为目的,代码还有很大的优化空间)
    
    def days_to_date(a: str, y: int, m: int, d: int) -> str:
      ''' 总天数转日期 '''
      days = sum_days(a, y, m, d)
    
      #sum_days('C', 2999, 12, 31) = 358668
      if not 0 < days < 358668+1:
          raise ValueError(f"\n\n{' 输入超出范围!':-^35}\n")
    
      #print('\n', a, y, m, d) # 程序调试语句
    
      if a=='K':
          #print(f"K:{days = }") # 程序调试语句
          year = days//365 # 取整年数
          days -= 365*year
          year += 2018 # 调整年份
          days -= sum_leap_days(year) # 去除闰年2月29总天数(不含当前年份)。(+2018转换公历)
    
          for i in range(12):
              # 2月整月天数去除 #
              #input(days) # 程序调试语句
              if i+1 == 2:
                  # 闰年 #
                  '''
                  if is_leap_year(year):
                      if days > 29:
                          days -= 29
                      elif days <= 29:
                          day = days if days<29 else 29                
                  # 平年 #
                  else:
                      if days > 28:
                          days -= 28
                      elif days <= 28:
                          day = days if days<28 else 28
                          break '''
                  # 上面的逻辑可以用“5行语句”优化成后面的代码
                  max_day = 29 if is_leap_year(y) else 28
                  if days <= max_day:
                      break
                  else:
                      days -= max_day
              # 大月整月天数去除 #
              elif i+1 in (1, 3, 5, 7, 8, 10, 12):
                  if days <= 31:
                      day = days if days<31 else 31
                      break 
                  else:
                      days -= 31
              # 小月整月天数去除 #
              else:
                  if days <= 30:
                      day = days if days<30 else 30
                      break 
                  else:
                      days -= 30
                      break 
    
          month = i + 1 # 月份调整到当前月份
          print(f"{sum_days('C', year, month, day) = }")
          return f"公元{year}-{month}-{day}"
      elif a == 'C':
          print(f"C:{days = }")
          year = days//915 # 取年份
          days -= 915*year
          year = 1 if year==0 else year+1 # 修正年份
          
          for i in range(30):
              max_day = 31 if (i+1)%2 else 30
    
              if days <= max_day:
                  month = i + 1 # 调整月份
                  day = days if days < max_day else max_day # 取日数值
                  break
              else:
                 days -= max_day
    
          print(f"{sum_days('K', year, month, day) = }")
          return f"K纪年{year}-{month}-{day}"
    
    

c. 输入校验
  • 输入校验
    虽然题目说明保证输入合法,但本着练手原则,我还是写了“校验”模块。😋
    
    def verify_input(a: str, y: int, m: int, d: int):
      ''' 输入校验 '''
      # 公元日期校验 #
      if a == 'C':
          verification = (
          	0 < m < 13 
          and (
          	0 < d < 32 and m in (1, 3, 5, 7, 8, 10, 12)
          	or 0 < d < 31 and m in (4, 6, 9, 11)
          		or 0 < d < 30 and is_leap_year(y) and m == 2
          		or 0 < d < 29 and not is_leap_year(y) and m == 2
          		)
          		) # 组合月、日边界校验(不用考量年份,另有范围校验)
          if not verification:
              raise ValueError(f"\n\n{' 公元格式错误!':-^35}\n")
    
      # K纪年日期校验 #
      elif a == 'K':
          verification = (
          	0 < m < 31
          	and (
          		0 < d < 32 and m%2
          		or 0 < d < 32 and m%2==0
          		)
          		) # 月、大小月天数边界组合校验(年份另有范围校验)
          if not verification:
              raise ValueError(f"\n\n{' K纪年格式错误!':-^35}\n")
    
      else:
          raise ValueError(f"\n\n{' 年份标识错误!':-^35}\n")
          
      return True
    
    

d. 主程序
  • 主程序
    实现对各模块的调度统筹。
    
    def main() -> None:
      ''' 主程序 '''
      a, y, m, d = input(f"\n\n{' 输入 ':-^40}\n{'(如K 3 27 31,或者C 2019 2 15)':^36}\n\n{'$ ':>9}").strip().split()
      a = a.upper()
      y, m, d = map(int, (y, m, d))
      verify_input(a, y, m, d)
      days = sum_days(a, y, m, d)
      print(f"\n\n{' 输出 ':-^40}{days_to_date(a, y, m, d):^40}\n\n")
    
    

e. 功能测试
  • test,多余的功能
    我这次突发“奇想”,编撰了一个“测试”模块,方便在完成模块代码修改调试后,“自动”测试。😋经试验,确实方便。😎😎
    
    def test() -> None:
      ''' 测试用例 '''
      print(f"\n\n{' 模块测试用例 ':-^36}\n\n") 
      print(f"{is_leap_year(2024) = }")
      print(f"{sum_days('K', 1, 5, 31) = }")
      print(f"{sum_days('K', 12, 4, 3) = }")
      print(f"{sum_days('C', 2018, 2, 27) = }")
      print(f"{sum_days('C', 2018, 3, 29) = }")
      print(f"{sum_days('C', 2024, 4, 3) = }")
      print(sum_days('C', 2024, 2, 30))
      print(days_to_date('K', 1, 2, 29))
      print(days_to_date('C', 2024, 11, 6))
      print(f"\n\n{'':-^42}\n\n") 
    
    

f. 程序入口
  • 程序入口
    __name__查验来决定是否执行主程序,可以方便地把功能模块以import的方式引入其它脚本使用。确保只有直接run本脚本时才会执行main()
    
    if __name__ == '__main__':
      test()
    
      try:
          main()
      except ValueError as e:
          print(f"\n\n{' 异常提示 ':=^38}\n\nErrorType:\n{e}")
    
    



回页目录


4、优化代码


  充分利用所学的python基础,适时启用掌握的python特性技巧:如解析式、三元操作语句、以及内库的调用来让代码变得 P y t h o n Python Python。😎


  • 与ai聊本题目代码学到的技巧
    在这里插入图片描述
    在这里插入图片描述

(源码较长,点此跳过源码)


代码正在优化……



回页首


上一篇:  字符串统计(Python)(接收键盘任意录入,分别统计大小写字母、数字及其它字符数量,打印输出)
下一篇: 



我的HOT博:

  本次共计收集 311 篇博文笔记信息,总阅读量43.82w。数据于2024年03月22日 00:50:22完成采集,用时6分2.71秒。阅读量不小于6.00k的有 7 7 7篇。


推荐条件 阅读量突破6.00k
(更多热博,请点击蓝色文字跳转翻阅)

  • 截屏图片
    在这里插入图片描述
      (此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)



回页首


老齐漫画头像

精品文章:

来源:老齐教室


Python 入门指南【Python 3.6.3】


好文力荐:


CSDN实用技巧博文:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幻精灵_cq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值