日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Borax.Lunardate:中国农历日期

發(fā)布時(shí)間:2023/12/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Borax.Lunardate:中国农历日期 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:https://kinegratii.github.io/2019/01/05/lunardate-module/

感謝原作者!本人只是搬運(yùn)工。看完這個(gè)和上一篇基本對(duì)農(nóng)歷就有了一個(gè)較全面的認(rèn)識(shí)。

本文簡(jiǎn)要介紹了我國(guó)傳統(tǒng)的農(nóng)歷歷法知識(shí),并敘述了 Borax-Lunar 工具庫(kù)開(kāi)發(fā)背后的一些算法原理和技術(shù)資料。

目錄

1 農(nóng)歷概述

1.1 編排規(guī)則

1.2 表示方法

1.3 二十四節(jié)氣

2 數(shù)據(jù)結(jié)構(gòu)

2.1 大小月和閏月

2.2 節(jié)氣的數(shù)據(jù)結(jié)構(gòu)

3 Borax-Lunardate概述

4 模塊設(shè)計(jì)

4.1 LunarDate日期類

4.1.1 初始化日期對(duì)象

4.1.2 基準(zhǔn)日期

4.2 格式化顯示

4.2.1 使用方法

4.2.2 源碼解析

4.3 類型標(biāo)注

4.3.1 概述

4.3.2 常用的使用示例

5 參考資料


1 農(nóng)歷概述

農(nóng)歷是我國(guó)的傳統(tǒng)歷法,依據(jù)太陽(yáng)和月球位置的精確預(yù)報(bào)以及約定的日期編排規(guī)則編排日期,并以傳統(tǒng)命名方法表述日期。

2017年,我國(guó)已經(jīng)頒布了國(guó)家推薦性標(biāo)準(zhǔn)《GB/T 33661-2017 農(nóng)歷的編算和頒行》。

1.1 編排規(guī)則

農(nóng)歷屬于一種陰陽(yáng)合歷,基本規(guī)則如下:其年份分為平年和閏年。平年為十二個(gè)月;閏年為十三個(gè)月。月份分為大月和小月,大月三十天,小月二十九天。一年中哪個(gè)月大,哪個(gè)月小,可由“置閏規(guī)則”計(jì)算決定。

若從某個(gè)農(nóng)歷十一月開(kāi)始到下一個(gè)農(nóng)歷十一月(不含)之間有13個(gè)農(nóng)歷月,則需要置閏。置閏規(guī)則為:去其中最先出現(xiàn)的一個(gè)不包含中氣的農(nóng)歷月為農(nóng)歷閏月。

除此之外,還有生肖紀(jì)年、干支紀(jì)年、二十四節(jié)氣等。

1.2 表示方法

農(nóng)歷日期通常有以下幾種表示方法:

  • 農(nóng)歷乙未年正月初一
  • 農(nóng)歷牛年閏五月十一
  • 農(nóng)歷甲午年七月庚戌日
  • 公元2016年農(nóng)歷丙申年十一月廿九

1.3 二十四節(jié)氣

一個(gè)回歸年內(nèi)24個(gè)太陽(yáng)地心視黃經(jīng)等于15度的整數(shù)倍的時(shí)刻的總稱,每個(gè)時(shí)刻成為一個(gè)節(jié)氣。太陽(yáng)每年運(yùn)行360度,共經(jīng)歷二十四個(gè)節(jié)氣,分別為立春(315度)、雨水(330度)、驚蟄(345度)、春分(0度、360度)、清明(15度)、谷雨(30度)、立夏(45度)、小滿(60度)、芒種(75度)、夏至(90度)、小暑(105度)、大暑(120度)、立秋(135度)、處暑(150度)、白露(165度)、秋分(180度)、寒露(195度)、霜降(210度)、立冬(225度)、小雪(240度)、大雪(255度)、冬至(270度)、小寒(285度)、大寒(300度)??梢酝ㄟ^(guò)下面的兒歌記憶這些節(jié)氣。

?

春雨驚春清谷天, 夏滿芒夏暑相連, 秋處露秋寒霜降, 冬雪雪冬小大寒, 每月兩節(jié)不變更, 最多相差一兩天

2016年11月30日,中國(guó)“二十四節(jié)氣”被正式列入聯(lián)合國(guó)教科文組織人類非物質(zhì)文化遺產(chǎn)代表作名錄。

2 數(shù)據(jù)結(jié)構(gòu)

農(nóng)歷月份大小、農(nóng)歷閏/平年、二十四節(jié)氣的日期沒(méi)有什么特定的規(guī)律,只能使用原始的“查表法”存儲(chǔ)和查詢這些信息。

2.1 大小月和閏月

從香港天文臺(tái)網(wǎng)站可以獲取1900 - 2100年的農(nóng)歷信息,每一天包含公歷日期、農(nóng)歷日期、星期、節(jié)氣四項(xiàng)基本信息。日期范圍的基本信息如下表:

項(xiàng)目起始日…2100年2101年…截止日
公歷1990年1月31日2100年12月31日2101年1月1日2101年1月28日
農(nóng)歷1900年正月初一2100年十二月初一2100年十二月初二2100年十二月二十九
offset0733837338473411
干支庚午年丙子月壬辰日庚申年戊子月丁未日--

具體到一個(gè)農(nóng)歷年中,從中可以看出以下幾點(diǎn)信息:

  • 每個(gè)月有多少天;哪些是大月(30天),哪些是小月(29天)
  • 本年是否有閏月;如果有,是哪個(gè)月份

如何使用精煉的數(shù)據(jù)結(jié)構(gòu)表述這些信息,是一個(gè)重要的前提,主要要求算法簡(jiǎn)單、內(nèi)存占用少。網(wǎng)上有許多種方式,一種比較通行的做法是使用5字節(jié)的數(shù)據(jù),高3位總是“000”,實(shí)際使用的低17位二進(jìn)制。

字段閏月大小標(biāo)志月份大小標(biāo)志閏月月份
大小4b12b4b
2017年示例00010101 0001 01110110
描述本年有閏月2,4,8,10,11,12為大月六月是閏月
2019年示例00001010 1001 00110000
描述無(wú)閏月1,3,5,8,11,12為大月無(wú)閏月

綜上所述,2017年信息可以使用 0x15176 表示;2019年信息可使用 0x0a930 表示。

2.2 節(jié)氣的數(shù)據(jù)結(jié)構(gòu)

36位字符串

二十四節(jié)氣開(kāi)始的日期,與通用的公歷幾乎一致,最多相差一兩天,因?yàn)槭前凑盏厍蛞荒昀@太陽(yáng)公轉(zhuǎn)一周作為依據(jù)。比如小寒通常落在在1月5-7日,立春落在2月3-5日,冬至落在12月21-23日。即每個(gè)月都會(huì)有2個(gè)節(jié)氣,1月只能有小寒、大寒這兩個(gè)節(jié)氣。

構(gòu)建兩個(gè)含有24元素的數(shù)組,

第一個(gè)數(shù)組以小寒為第1個(gè)節(jié)氣重新排列這24個(gè)節(jié)氣。

?

小寒, 大寒, 立春, 雨水, 驚蟄, 春分, 清明, 谷雨, 立夏, 小滿, 芒種, 夏至, 小暑, 大暑, 立秋, 處暑, 白露, 秋分, 寒露, 霜降, 立冬, 小雪, 大雪, 冬至

第二個(gè)數(shù)組表示對(duì)應(yīng)節(jié)氣對(duì)應(yīng)的日期數(shù)字。

?

6 20 4 19 6 21 5 20 6 21 6 22 7 23 8 23 8 23 9 24 8 23 7 22

結(jié)合這兩個(gè)數(shù)組,可記錄在一個(gè)公歷年中,二十四個(gè)節(jié)氣分別是在哪一天。比如上述的24個(gè)數(shù)字可解釋為:1月6日是小寒、1月20日是大寒…12月7日是大雪、12月22日是冬至。

在 Python 語(yǔ)言層面,可以使用字符串(基本數(shù)據(jù)類型)代替上述數(shù)組(復(fù)合數(shù)據(jù)類型),即"620419621520621622723823823924823722" ,需要36位字符存儲(chǔ)。

解析表中數(shù)據(jù)的 Python 代碼實(shí)現(xiàn)如下:

?

def parse_term(year_info):result = []for i in range(0, 36, 3):s = year_info[i:i + 3]result.extend([int(s[0]), int(s[1:3])])return result

30位字符串

jjonline/calendar.js 提供了一種用更為簡(jiǎn)單的表示方法:利用十六進(jìn)制壓縮數(shù)字的位數(shù),進(jìn)一步簡(jiǎn)化為30位的字符串。具體計(jì)算過(guò)程如下:

?

9778397bd097c36b0b6fc9274c91aa # 按長(zhǎng)度5分割,共6組97783 97bd0 97c36 b0b6f c9274 c91aa # 轉(zhuǎn)化為十進(jìn)制620419 621520 621622 723823 823924 823722 # 按長(zhǎng)度1,2,1,2細(xì)分6 20 4 19 6 21 5 20 6 21 6 22 7 23 8 23 8 23 9 24 8 23 7 22

使用 Python代碼實(shí)現(xiàn)上述算法如下:

?

def parse_term(term_info):values = [str(int(term_info[i:i + 5], 16)) for i in range(0, 30, 5)]term_day_list = []for v in values:term_day_list.extend([int(v[0]), int(v[1:3]), int(v[3]), int(v[4:6])])return term_day_list

24位字符串

從 Borax v1.2.0 開(kāi)始使用算法。

統(tǒng)計(jì)1900-2100年之前節(jié)氣日期統(tǒng)計(jì)可知,中氣的日期都是在18-24日之間,這些均為兩位數(shù),可以通過(guò)線性變化轉(zhuǎn)為一位數(shù)的數(shù)字,結(jié)合月份特點(diǎn),可以通過(guò)減去一個(gè)固定偏移量15就是比較好的選擇。

同樣的按照上述處理,具體過(guò)程如下:

?

654466556667788888998877 # 按長(zhǎng)度1分割6 5 4 4 6 6 5 5 6 6 6 7 7 8 8 8 8 8 9 9 8 8 7 7 # 增加偏移量,奇位置為0,偶位置為156 20 4 19 6 21 5 20 6 21 6 22 7 23 8 23 8 23 9 24 8 23 7 22

同樣的使用Python 代碼如下,和30位表示法相比,更為簡(jiǎn)單直接。

?

def parse_term_days(term_info):return [int(c) + [0, 15][i % 2] for i, c in enumerate(term_info)]

3 Borax-Lunardate概述

到2019年1月為止,關(guān)于農(nóng)歷的主題,github/PyPI 上已經(jīng)有非常多的代碼項(xiàng)目,語(yǔ)言有C、Java、Python等,具體的思路也不一樣。綜合來(lái)看,這些庫(kù)有的功能單一,只覆蓋某幾個(gè)方面;有的已經(jīng)很久沒(méi)有更新了,主要是農(nóng)歷信息已在多年之前就采集完成,但是對(duì)于一些最新的數(shù)據(jù)修正未能及時(shí)涵蓋;也有的在代碼層面沒(méi)有很好的適用最新的 Python 語(yǔ)言特性。

基于此,本人利用收集整理的一些技術(shù)資料開(kāi)發(fā)出了 Borax-Lunar 這個(gè)庫(kù),主要的目標(biāo)和特點(diǎn)有:

  • 完整的農(nóng)歷信息

在開(kāi)發(fā)過(guò)程中我收集網(wǎng)絡(luò)上的幾個(gè)重要農(nóng)歷數(shù)據(jù),包含了干支、生肖、節(jié)氣等事項(xiàng),并同時(shí)將它們作為數(shù)據(jù)驗(yàn)證的參考標(biāo)準(zhǔn)。

另外,一些術(shù)語(yǔ)命名(比如天干、地支等)采用 《GB/T 33661-2017 農(nóng)歷的編算和頒行》 所規(guī)定的文字。

  • 功能完備

Borax-Lunardate 庫(kù)分為三個(gè)部分:1) 基于 LunarDate 的農(nóng)歷日期表示;2)類似于 datetime.strftime 的字符串格式系統(tǒng);3) 一些常用的農(nóng)歷工具接口。

其中第2,3部分是網(wǎng)絡(luò)上的農(nóng)歷庫(kù)比較少涉及的,Borax-Lunardate 在這一方面非常有優(yōu)勢(shì)的。

  • 對(duì)標(biāo)datetime

在模塊/類層面的組織和分類上,Borax-Lunardate 對(duì)標(biāo)標(biāo)準(zhǔn)庫(kù)的 datetime 和 calendar 模塊,實(shí)現(xiàn)了這兩個(gè)模塊中與農(nóng)歷日期相聯(lián)系的方法,LunarDate 和 date 類有許多相同的特性,包括不可變類、可比較性、時(shí)間加減等。 甚至有些命名也是一樣的,比如 strftime 方法。

?

lunardate.LunarDate <------> datetime.datelunardate.LCalendars <------> calendar.Calendar

4 模塊設(shè)計(jì)

4.1 LunarDate日期類

4.1.1 初始化日期對(duì)象

LunarDate 是一個(gè)重要的類,每一個(gè)對(duì)象表示一個(gè)農(nóng)歷日期,一個(gè)特定的農(nóng)歷日期可以由農(nóng)歷年、月、日、閏月標(biāo)志4個(gè)字段唯一確定,可以使用這些字段初始化對(duì)象。

?

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

對(duì)于一些特定的日期,也可以通過(guò)類方法創(chuàng)建這些日期對(duì)象。

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

4.1.2 基準(zhǔn)日期

LunarDate 類使用可表示范圍的下限作為基準(zhǔn)日期(即LunarDate(1990, 1, 1, False))。對(duì)象的 offset 屬性表示與基準(zhǔn)日期相差的天數(shù),這也是一種可以唯一確定日期的方法。

4.2 格式化顯示

該功能由 Borax-Lunardate 特有的功能,提供了與 datetime.date.strftime 相似的功能。

4.2.1 使用方法

LunarDate 提供了 strftime 方法,可以將一個(gè)農(nóng)歷日期按照給定的格式轉(zhuǎn)化為字符串。

?

class LunarDate:def strftime(fmt:str) -> str: pass

格式字符串使用 ‘%’ 加一個(gè)字母的描述符(Directive)表示日期對(duì)象的一個(gè)字段,常用的描述符見(jiàn)下表:

屬性類型描述示例值格式描述符備注
yearint農(nóng)歷年2018%y?
monthint農(nóng)歷月6%m?
dayint農(nóng)歷日26%d?
leapbool是否閏月False%l(1)
offsetint距下限的偏移量43287-?
termstr 或 None節(jié)氣名稱立秋%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兩位數(shù)字的月份06%A?
-str兩位數(shù)字的日期26%B?

備注:

  • (1) ‘%l’ 將閏月標(biāo)志格式化為數(shù)字,如“0”、“1”
  • (2) ‘%Y’、’%M’、’%D’ 三個(gè)中文名稱不包含“年”、“月”、“日”后綴漢字

下面是幾個(gè)使用 strftime 的例子:

?

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

4.2.2 源碼解析

strftime 的具體實(shí)現(xiàn)定義在 lunardate.Formatter 類。該類接受一個(gè) %形式的格式字符串,轉(zhuǎn)化為命名字段形式的格式字符串,并格式化給定的日期對(duì)象,如下圖:

?

'%Y-%M-%D' ==> '{cn_year}-{cn_month}-{cn_day}' ==> '二〇一八-六-廿六'

某個(gè)字段 field 的具體值,根據(jù)下列先后順序確定具體的值。

  • Formatter.get_<field>
  • obj.<field>()
  • obj.<field>

核心代碼如下:

?

class Formatter:def resolve(self, obj, field):try:func = getattr(self, 'get_' + field)return func(obj)except AttributeError:attr = getattr(obj, field)if callable(attr):return attr()else:return attr

4.3 類型標(biāo)注

4.3.1 概述

PEP 484 和 PEP526 提供了一種針對(duì) Python 語(yǔ)言的類型標(biāo)注方法。在 Python3.5+ 以上,可以使用 typing 標(biāo)準(zhǔn)模塊實(shí)現(xiàn)這一目的,需要說(shuō)明的是:

  • 方便使用者了解所調(diào)用函數(shù)的參數(shù)類型和返回值類型

  • 類型標(biāo)注不會(huì)影響運(yùn)行,不會(huì)拋出異常,只是警告

  • 配合IDE的語(yǔ)法語(yǔ)義檢查功能,增強(qiáng)智能提示功能

    下面是一個(gè)參數(shù)和返回值都是字符串的函數(shù)標(biāo)注:

    def greeting(name: str) -> str:return 'Hello ' + name

    ?

?

除了一些基本類型,常用的符合數(shù)據(jù)類型還有 Any、Union、Tuple、List、Callable、TyVar、Generic 等。

需要注意的是,Python 的語(yǔ)言特性也可能給類型標(biāo)準(zhǔn)的使用帶來(lái)了一些麻煩,比如變量在使用過(guò)程中其類型有所變化?;谀繕?biāo)用戶是API使用者,大概可以整理出幾條實(shí)用的原則:

  • 只應(yīng)用在公共接口(類、函數(shù)、方法、變量)加上類型標(biāo)注。
  • 全局常量不使用類型標(biāo)注
  • 魔術(shù)方法不使用類型標(biāo)注
  • 私有方法可以不使用類型標(biāo)注

4.3.2 常用的使用示例

類型標(biāo)注學(xué)習(xí)起來(lái)也不困難,掌握幾種常見(jiàn)的情形即可。

使用 :表示參數(shù)類型,使用 -> 表示返回值類型,如上述的 greeting 函數(shù) 。

默認(rèn)參數(shù)

?

def foo(arg: int = 0) -> None: pass

可選參數(shù),需要使用 Optional,通常和上面的默認(rèn)參數(shù)相互配合。

?

def ndays(year: int, month: Optional[int] = None, leap: bool = False) -> int:pass

自定義類型、混合類型,閏月標(biāo)記可以使用布爾值或者整數(shù)。

?

Leap = Union[bool, int]

后向引用,如果使用的類還沒(méi)有定義,可以使用包含類名的字符串,以便后續(xù)實(shí)例化。一般用于創(chuàng)建對(duì)象的方法或者樹(shù)形結(jié)構(gòu)的定義。

class LunarDate:def from_solar_date(cls, year: int, month: int, day: int) -> 'LunarDate':pass

類型綁定。在后向引用的例子中,通常需要在多個(gè)地方使用字符串方式,為避免拼寫錯(cuò)誤,可以使用 TypeVar 的 bound 參數(shù)提前預(yù)定義。

T = TypeVar('T', bound=BaseClass) 使用父類創(chuàng)建類型變量以便所有子類均可匹配,這和 Java/C++ 語(yǔ)言中的 多態(tài) 相類似。

?

from typing import TypeVarT = TypeVar('T', bound='LunarDate')class LunarDate:def from_solar_date(cls, year: int, month: int, day: int) -> T:pass

迭代器,使用 Iterator。

def hello(n:int) -> Iterator[int]:for i in range(n):yield i

5 參考資料

  • 香港天文臺(tái)農(nóng)歷信息
  • “農(nóng)歷”維基詞條
  • jjonline/calendar.js
  • lidaobing/python-lunardate
  • Forward references - Stackflow

?

總結(jié)

以上是生活随笔為你收集整理的Borax.Lunardate:中国农历日期的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。