Borax 1.3 Python常用工具包

最近在修改C++农历离线库,已经改完2020-2099年的数据,全是手动改,所以改的很累,改到不想入了。后来想用Python编个小程序实现自动修改,至少一些累人的事最好让程序来完成。于是又需要研究一下python的borax农历库,据说这个东西很历害,但我只用到了农历部分,以下是转载的关于农历的资料,我觉得写的比较好,留下备忘。

原文地址:https://www.bookstack.cn/read/borax/docs-guides-lunardate.md#%E6%97%A5%E6%9C%9F%E8%8C%83%E5%9B%B4

在此向原作者表示感谢!

lunardate 模块

模块: borax.calendars.lunardate 协议:GPLv3

概述

lunardate 模块是一个处理中国农历日期的工具库。支持1900 - 2100 农历年范围的日期、干支纪年、节气等历法信息。

本模块的数据和算法引用自项目 jjonline/calendar.js ,具体内容包括:

  • 1900-2100年农历月份信息
  • 干支纪年算法

关于本模块的更多资料可参考文章 《Borax-Lunar开发笔记》

常量定义

lunardate 提供了下列的模块级常量。

  • lunardate.MIN_LUNAR_YEAR

农历可表示的最大年份,值为 2100 。

  • lunardate.MAX_LUNAR_YEAR

农历可表示的最小年份,值为 1900 。

  • lunardate.MIN_SOLAR_DATE

农历可表示的日期下限,值为 datetime.date(1900, 1, 31),日期同 LunarDate.min

  • lunardate.MAX_SOLAR_DATE

农历可表示的日期下限,值为 datetime.date(2101, 1, 28),日期同 LunarDate.max

  • lunardate.MAX_OFFSET

农历日期的最大偏移量,值为73411。

日期范围

LunarDate 实例表示一个具体日期,该类可以表示的日期起止范围如下表:

项目起始日2100年2101年截止日
公历1990年1月31日2100年12月31日2101年1月1日2101年1月28日
农历1900年正月初一2100年腊月初一2100年腊月初二2100年腊月廿九
offset0733837338473411
干支庚午年丙子月壬辰日庚申年戊子月丁未日庚申年戊子月戊申日庚申年己丑月乙亥日

创建日期对象

可以通过以下几种方法创建。

▶ 农历日期

依次传入农历年、月、日、闰月标志等4个参数创建一个新对象,其中闰月标志可省略,表示为平月。

>>>from borax.calendars.lunardate import LunarDate
>>>LunarDate(2018, 7, 1)
LunarDate(2018, 7, 1, 0)

▶ 公历日期

将公历日期转化为农历日期。

>>>ld = LunarDate.from_solar_date(2018, 8, 11)
>>>ld
LunarDate(2018, 7, 1, 0)

▶ 特定的日期

获取今日/昨日/明日的农历日期。

>>>LunarDate.today()
LunarDate(2018, 7, 1, 0)
>>>LunarDate.yesterday()
LunarDate(2018, 6, 29, 0)
>>>LunarDate.tomorrow()
LunarDate(2018, 7, 2, 0)

lunardate 模块可用的日期上下限

>>>LunarDate.min
LunarDate(1990, 1, 1, 0)
>>>LunarDate.max
LunarDate(2100, 12, 29, 0)

属性和显示

属性表

和公历日期对象 datetime.date 类似,LunarDate 是不可变对象(Immutable Object),可以作为字典的键值。全部属性如下表(以 LunarDate(2018, 6, 26, False) 为例):

属性类型描述示例值格式描述符备注
yearint农历年2018%y 
monthint农历月6%m 
dayint农历日26%d 
leapbool是否闰月False%l(1)
offsetint距下限的偏移量43287- 
termstrNone节气名称立秋%t 
cn_yearstr中文年二〇一八年%Y(2)
cn_monthstr中文月六月%M(2)
cn_daystr中文日廿六%D(2)
gz_yearstr干支年份戊戌%o 
gz_monthstr干支月份庚申%p 
gz_daystr干支日辛未%q 
animalstr年生肖%a 
-str两位数字的月份06%A 
-str两位数字的日期26%B 
cn_day_calendarstr用于日历显示的中文日26%Fv1.3.0新增 (3)
str(ld)str默认表示法LunarDate(2018, 6, 26, False)- 
ld.cn_str()str汉字表示法2018年六月廿六%C 
ld.gz_str()str干支表示法戊戌年庚申月辛未日%G

备注信息:

  • (1) ‘%l’ 将闰月标志格式化为数字,如“0”、“1”
  • (2) ‘%Y’、’%M’、’%D’ 三个中文名称不包含“年”、“月”、“日”后缀汉字
  • (3) ‘%F’ 将“初一”改为相应的中文月份,如“七月”、“闰六”、“冬月”、“闰冬”。

格式化

  • LunarDate.strftime(fmt)

strftime通过描述符(Directive)格式化给定的日期字符串。在“属性”一节中已经列出所有属性的格式描述符。

例子:

>>>today = LunarDate.today()
>>>today.strftime('%Y-%M-%D')
'二〇一八-六-廿六'
>>>today.strftime('今天的干支表示法为:%G')
'今天的干支表示法为:戊戌年庚申月辛未日'

公历转化

  • LunarDate.to_solar_date()

将当前日期转化为公历日期

>>> ld = LunarDate(2018, 6, 26, False)
>>>ld.to_solar_date()
datetime.date(2018, 8, 7)

日期推算

▶ 加减操作符

LunarDate 支持和 datetime.timedeltadatetime.date 进行加减计算。

左操作数类型操作符右操作数类型结果类型
LunarDate+datetime.timedeltaLunarDate
datetime.timedelta+LunarDateLunarDate
LunarDate-datetime.timedeltaLunarDate
datetime.date-LunarDatedatetime.timedelta
LunarDate-datetime.datedatetime.timedelta
LunarDate-LunarDatedatetime.timedelta

例子:

>>> LunarDate(2018, 6, 3) + timedelta(days=3)
LunarDate(2018, 6, 6, 0)
>>> LunarDate(2018, 6, 18) - LunarDate(2018, 6, 3)
timedelta(days=15)

▶ 日期推算

before/after函数

返回向前/向后推算 n 天的日期。n 允许取负值,即 ld.after(5)ld.before(-5) 返回表示同一个日期的实例。

>>> ld = LunarDate(2018, 6, 3)
>>>ld.after(3)
LunarDate(2018, 6, 6, 0)
>>>ld.before(2)
LunarDate(2018, 6, 1, 0)
>>>ld.after(-2)
LunarDate(2018, 6, 1, 0)

replace函数

replace(self, *, year=None, month=None, day=None, leap=None)

返回一个替换给定值后的日期对象。所有参数必须以关键字形式传入。如果该日期不存在,将抛出 ValyeError 异常。

>>>ld = LunarDate(2018, 5, 3)
>>>ld.replace(year=2019)
LunarDate(2019, 5, 3, 0)
>>>ld.replace(leap=True)
ValueError: month out of range

日期比较

LunarDate 支持和 datetime.date 对象进行比较,对象所代表的日期更新其“数值”更大。

>>>LunarDate(2018, 6, 2) > LunarDate(2018, 6, 14)
False
>>>LunarDate(2018, 6, 2) > date(2018, 6, 2)
True

序列化与存储

pickle协议支持

LunarDate 对象支持 pickle 序列化。

import pickle
from borax.calendars.lunardate import LunarDate


ld = LunarDate.today()
with open('data.pickle', 'wb') as f:
pickle.dump(ld, f)

with open('data.pickle', 'rb') as f:
l2 = pickle.load(f)
print(l2) # LunarDate(2018, 7, 24, 0)

sqlite3自定义字段

LunarDate 继承自 store.EncoderMixin 接口,为 sqlite3 自定义字段提供支持,更多细节参考 sqlite3文档

下面是一个简单的例子:

import sqlite3

from borax.calendars.lunardate import LunarDate


def adapt_lunardate(ld):
return ld.encode()

sqlite3.register_adapter(LunarDate, adapt_lunardate)
sqlite3.register_converter("lunardate", LunarDate.decode)

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute('CREATE TABLE member (pid INT AUTO_INCREMENT PRIMARY KEY,birthday lunardate);')

ld = LunarDate(2018, 5, 3)
cur.execute("INSERT INTO member(birthday) VALUES (?)", (ld,))

cur.execute("SELECT pid, birthday FROM member;")
my_birthday = cur.fetchone()[1]

cur.close()
con.close()

print(my_birthday.year) # 2018
print(my_birthday.month) # 5
print(my_birthday.day) # 3
print(my_birthday.leap) # 0

LCalendars工具接口

LCalendars 提供了一系列的工具方法。

  • LCalendars.leap_month(year: int) -> int

返回 year 年的闰月月份,范围为 [0,12] ,0 表示该年无闰月。

  • LCalendars.is_leap_month(year: int, month: int) -> bool

判断 year 年 month 月是否为闰月。该方法已废弃,可使用 LCalendars.leap_month(year) == month 表达式代替。

  • LCalendars.ndays(year: int, month: Optional[int] = None, leap: Leap = False) -> int

返回X年或者X年X月的天数;如输入的年月不存在,将抛出 ValueError 异常。
例子:

>>>from borax.calendars.lunardate import LCalendars
>>>LCalendars.ndays(2018)
354
>>>LCalendars.ndays(2018, 12)
30
>>>LCalendars.ndays(2017, 6, 1)
30
>>>LCalendars.ndays(2200)
ValueError: year out of range [1900, 2100]
>>>LCalendars.ndays(2017, 7, 1)
ValueError: Invalid month for the year 2017
  • LCalendars.iter_year_month(year: int) -> Iterator[Tuple[int, int, int]]

迭代X年的月份信息,元素返回 (月份, 该月的天数, 闰月标记) 的元祖。

例子:

>>>from borax.calendars.lunardate import LCalendars
>>>list(LCalendars.iter_year_month(2017))
[(1, 29, 0), (2, 30, 0), (3, 29, 0), (4, 30, 0), (5, 29, 0), (6, 29, 0), (6, 30, 1), (7, 29, 0), (8, 30, 0), (9, 29, 0), (10, 30, 0), (11, 30, 0), (12, 30, 0)]
  • LCalendars.create_solar_date(year: int, term_index: Optional[int] = None, term_name: Optional[str] = None) -> datetime.date

根据节气名称或者序号获取对应的公历日期对象(dateitime.date)。term_indexterm_name 只需传入一个参数,

term_index 取值为 0-23 。其中 小寒的序号为0,立春的序号为2,…冬至的序号为23。

>>>LCalendars.create_solar_date(2019, term_name='清明')
2019-04-05
  • LCalendars.delta(date1:MDate, date2:MDate) -> int

计算两个日期相隔的天数,即 (date1 - date2).days

参考资料

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值