wareki 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ChangeLog +66 -0
- data/README.md +46 -8
- data/lib/wareki/calendar.rb +90 -0
- data/lib/wareki/calendar_def.rb +253 -1431
- data/lib/wareki/common.rb +24 -5
- data/lib/wareki/date.rb +144 -67
- data/lib/wareki/era_def.rb +16 -13
- data/lib/wareki/std_ext.rb +55 -7
- data/lib/wareki/utils.rb +99 -32
- data/lib/wareki/version.rb +1 -1
- metadata +11 -52
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1559659acd73e0b2e1760b9d5d889f59f7ac592ec6ff357ebe17e9631398cd18
|
|
4
|
+
data.tar.gz: 9c2271acf0e4522b2bc69b00abe579e6ae10299d6d560bbd987bd88581ad578a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b6e16627c6d96af8128ecba167c59c077970373f1f37dfac0f156b88478869a29d8fe04e0bcf91c77dacd482c32cc1493b6aaa2cd065915b5a6c1696a293d450
|
|
7
|
+
data.tar.gz: bc6ba557cff73de604dc895f95b60f0baa4ecd82c8796b1b8e3c23cb9f6395c004c213d01ea781a92a7c72145e53772cdaba0d0302ccf2585a3a20e6a2cb9c8f
|
data/ChangeLog
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
+
2026-07-13 Tatsuki Sugiura <sugi@nemui.org>
|
|
2
|
+
|
|
3
|
+
* Version: 2.1.0
|
|
4
|
+
* Shrink in-memory kyuureki calendar table to ~1/48 (bit-packed
|
|
5
|
+
one-integer-per-year representation in new internal module
|
|
6
|
+
Wareki::Calendar); calendar definitions now load ~30x faster
|
|
7
|
+
* Era definitions are now generated from manakai/data-locale
|
|
8
|
+
era-defs.json instead of the Wikipedia era list page
|
|
9
|
+
(build-util/gen-era-def.rb); corrects 正平/建徳/文中 boundaries,
|
|
10
|
+
白雉/朱鳥 now cover until the end of their last kyuureki year,
|
|
11
|
+
and ERA_NORTH_DEFS 元徳 now ends at 正慶 transition
|
|
12
|
+
* Wareki.parse_to_date and patched Date.parse/_parse no longer
|
|
13
|
+
fall back to stdlib parsing on UnsupportedDateRange; the error
|
|
14
|
+
propagates again as in 1.x (reverts a 2.0.0 change)
|
|
15
|
+
* Cache kansuji conversion of small numbers for %J format
|
|
16
|
+
directives; Utils.to_simple_kan delegates non-Integer values
|
|
17
|
+
to YaKansuji
|
|
18
|
+
* Fast-path ASCII-only strings in patched Date.parse/Date._parse
|
|
19
|
+
* Remove internal constants Wareki::YEAR_DEFS, Wareki::YEAR_BY_NUM,
|
|
20
|
+
Wareki::Year and Wareki::Utils.find_year
|
|
21
|
+
* required_ruby_version is now >= 2.3
|
|
22
|
+
|
|
23
|
+
2026-07-13 Tatsuki Sugiura <sugi@nemui.org>
|
|
24
|
+
|
|
25
|
+
* Version: 2.0.0
|
|
26
|
+
* Time.parse now understands Japanese kansuji/zenkaku time notations
|
|
27
|
+
(十二時三十四分五十六秒, 午後三時半, 正午, ...) via the patched
|
|
28
|
+
Date._parse; Date.parse no longer misreads bare 時分秒 strings
|
|
29
|
+
* Add %JT* time format directives (%JTf/%JTF/%JTH(k)/%JTM(k)/%JTS(k));
|
|
30
|
+
Time#strftime now supports all %J directives and DateTime#strftime
|
|
31
|
+
expands %JT too; add Time#to_wareki_date
|
|
32
|
+
* Strict date validation: nonexistent dates now raise
|
|
33
|
+
Wareki::InvalidDate (< ArgumentError) (month/day out of range,
|
|
34
|
+
nonexistent leap month, and the Meiji 5 December calendar-switch
|
|
35
|
+
gap for all era notations); patched Date.parse re-raises it
|
|
36
|
+
instead of falling back to stdlib misinterpretation
|
|
37
|
+
* README: document that conversion from Date/jd prefers northern court
|
|
38
|
+
eras during the Nanboku-cho period (previous statement was wrong;
|
|
39
|
+
behavior unchanged from 1.1.0)
|
|
40
|
+
* Update kyuureki calendar data (regenerated from
|
|
41
|
+
manakai/data-locale); corrects month boundaries of some
|
|
42
|
+
historical years
|
|
43
|
+
* Wareki::Date#- returns day count for date-like operands;
|
|
44
|
+
#+ raises TypeError for non-numeric operands (stdlib parity)
|
|
45
|
+
* Support date calculation with ActiveSupport::Duration
|
|
46
|
+
(was NotImplementedError)
|
|
47
|
+
* Add Wareki::Date#hash, #<=>, Comparable and #succ
|
|
48
|
+
* Invalidate cached jd on attribute writes; writers keep
|
|
49
|
+
year/era_year consistent
|
|
50
|
+
* Freeze era definition structs to prevent accidental mutation
|
|
51
|
+
of shared state
|
|
52
|
+
* Fix imperial_year= setter (sign error)
|
|
53
|
+
* Parse apostrophe leap-month markers so %Jf/%Jm output round-trips
|
|
54
|
+
* Fix misokka (晦日) parsing for 皇紀/西暦/紀元前/era-less dates
|
|
55
|
+
* DateTime#strftime now supports %J directives
|
|
56
|
+
* Escaped %%J or invalid %J sequences no longer trigger conversion;
|
|
57
|
+
Wareki::Date#strftime honors %% escapes too
|
|
58
|
+
* Fast-path non-wareki strings in patched Date.parse/_parse
|
|
59
|
+
* Wareki.parse_to_date falls back on UnsupportedDateRange too
|
|
60
|
+
* Fix deprecated Utils.i_to_kan (was calling undefined method)
|
|
61
|
+
* gemspec: SPDX license identifier (BSD-2-Clause)
|
|
62
|
+
|
|
63
|
+
[ by masa.kunikata <masa.kunikata@gmail.com> ]
|
|
64
|
+
* Add zero padding format feature
|
|
65
|
+
* Use zero padded format on default
|
|
66
|
+
|
|
1
67
|
2019-12-24 Tatsuki Sugiura <sugi@nemui.org>
|
|
2
68
|
|
|
3
69
|
* Version: 1.1.0
|
data/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# wareki - ruby 和暦ライブラリ
|
|
2
2
|
|
|
3
3
|
[<img src="https://badge.fury.io/rb/wareki.svg" alt="Gem Version" />](https://badge.fury.io/rb/wareki)
|
|
4
|
-
[<img src="https://
|
|
5
|
-
[<img src="https://coveralls.io/repos/sugi/wareki/badge.svg?branch=master
|
|
4
|
+
[<img src="https://github.com/sugi/wareki/actions/workflows/ci.yml/badge.svg" alt="Build Status" />](https://github.com/sugi/wareki/actions/workflows/ci.yml)
|
|
5
|
+
[<img src="https://coveralls.io/repos/github/sugi/wareki/badge.svg?branch=master" alt="Coverage Status" />](https://coveralls.io/github/sugi/wareki?branch=master)
|
|
6
6
|
[<img src="https://api.codeclimate.com/v1/badges/c9209422700b526d2b45/maintainability" />](https://codeclimate.com/github/sugi/wareki/maintainability)
|
|
7
|
-
[](https://app.codacy.com/gh/sugi/wareki/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
|
8
8
|
|
|
9
9
|
## 概要
|
|
10
10
|
|
|
11
11
|
日本の和暦をサポートするライブラリです。
|
|
12
12
|
旧暦は445年から、元号は大化から全て処理できます。
|
|
13
|
-
|
|
13
|
+
元号・暦とも [manakai/data-locale](https://github.com/manakai/data-locale) のデータを元にしています (暦は日本暦日原典由来)。
|
|
14
14
|
|
|
15
15
|
## 機能
|
|
16
16
|
|
|
@@ -20,10 +20,15 @@
|
|
|
20
20
|
* 閏月サポート
|
|
21
21
|
* 月の別名のサポート (如月、弥生、師走など)
|
|
22
22
|
* 元年、正月、朔日、晦日、廿一日、卅日 などの特殊な表記の日付サポート
|
|
23
|
+
* 時刻の漢数字・全角数字表記のサポート (十二時三十四分五十六秒、午後三時半、正午 など)
|
|
23
24
|
* Date クラスの拡張
|
|
24
25
|
* 標準の strftime に和暦へのフォーマット文字列を追加
|
|
25
26
|
* to_wareki_date を追加
|
|
26
27
|
* Date::JAPAN (明治改暦日)の追加
|
|
28
|
+
* Time / DateTime クラスの拡張
|
|
29
|
+
* strftime に時刻の全角・漢数字フォーマット文字列 (%JT 系) を追加
|
|
30
|
+
* Time.parse で和暦・漢数字時刻の文字列を解釈 (要 `require 'time'`)
|
|
31
|
+
* Time#to_wareki_date を追加
|
|
27
32
|
|
|
28
33
|
## インストール
|
|
29
34
|
|
|
@@ -71,6 +76,20 @@ Wareki::Date.parse("正嘉元年 うるう3月 12日") # => Wareki::Date イ
|
|
|
71
76
|
Wareki::Date.new("明治", 8, 2, 1).to_date # => 標準 Date インスタンス 1875-02-01
|
|
72
77
|
```
|
|
73
78
|
|
|
79
|
+
### 時刻のパースとフォーマット
|
|
80
|
+
|
|
81
|
+
時刻の漢数字・全角数字表記も透過的に扱えます。時刻には暦のようなマッピングは
|
|
82
|
+
存在しないため、単純な数字変換として処理されます。
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
require 'time'
|
|
86
|
+
t = Time.parse("平成元年五月四日 午後三時三十四分五十六秒")
|
|
87
|
+
# => 1989-05-04 15:34:56
|
|
88
|
+
t.strftime("%JF %JTF") # => "平成元年五月四日 十五時三十四分五十六秒"
|
|
89
|
+
t.strftime("%JTf") # => "15時34分56秒"
|
|
90
|
+
t.strftime("%JTHk時%JTMk分") # => "十五時三十四分"
|
|
91
|
+
```
|
|
92
|
+
|
|
74
93
|
### 和暦・旧暦へのフォーマット
|
|
75
94
|
|
|
76
95
|
日本では明治5年まで、グレゴリオ暦でもユリウス歴でもない旧暦が使われていました。これもフォーマット文字列経由で透過的に扱えます。
|
|
@@ -154,6 +173,18 @@ strftime が拡張されるので、 `config/locale/ja.yml` にそのままフ
|
|
|
154
173
|
* %JDk: 和暦日の漢数字
|
|
155
174
|
* %JDK: 和暦日の漢数字の特殊記法 (朔、晦)
|
|
156
175
|
|
|
176
|
+
以下の時刻フォーマット文字列は Time / DateTime の strftime でのみ使用できます
|
|
177
|
+
(Date は時刻情報を持たないため展開されません)。
|
|
178
|
+
|
|
179
|
+
* %JTf: "%JTH時%JTM分%JTS秒" 相当の半角ゼロ埋め複合表記 (例: 15時04分05秒)
|
|
180
|
+
* %JTF: 漢数字の複合表記 (例: 十五時四分五秒)
|
|
181
|
+
* %JTH: 時の全角数字
|
|
182
|
+
* %JTHk: 時の漢数字
|
|
183
|
+
* %JTM: 分の全角数字
|
|
184
|
+
* %JTMk: 分の漢数字
|
|
185
|
+
* %JTS: 秒の全角数字
|
|
186
|
+
* %JTSk: 秒の漢数字
|
|
187
|
+
|
|
157
188
|
## 仕様、限界、制限など
|
|
158
189
|
|
|
159
190
|
* 作者は暦の専門家ではまったくありません。ツッコミお待ちしています。
|
|
@@ -162,18 +193,25 @@ strftime が拡張されるので、 `config/locale/ja.yml` にそのままフ
|
|
|
162
193
|
* 日本暦日原典の対照表が、どの暦法を元にしているのか分かっていません。単にデータだけを利用しています。
|
|
163
194
|
* 内部的には全てユリウス日を経由して変換しています。
|
|
164
195
|
* パース時には元号の存在しない年(例: 霊亀百年)を受け入れます。しかし現状、Date に変換した場合この情報は捨てられ、パース時の元号を復元することはできません。(Wareki::Date を直接扱えば可能です)
|
|
165
|
-
*
|
|
166
|
-
*
|
|
196
|
+
* 存在しない日付(月・日の範囲超過、存在しない閏月、改暦により存在しない明治5年12月3日〜31日など)は例外(Wareki::InvalidDate, ArgumentError のサブクラス)を上げます。
|
|
197
|
+
* 南朝・北朝どちらの元号も解釈できます。Date やユリウス日からの変換では、南北朝期は通常の慣例に従い北朝の元号を優先します(元弘・延元など、北朝側の改元前で北朝に固有の元号がない期間は南朝の元号になります)。
|
|
198
|
+
* 元号の開始日より前の日付表記(例: 令和元年1月1日)は受理し、その元号の元年として解釈します。逆変換では実際の元号(平成31年1月1日)になります。
|
|
167
199
|
* 10月の別名は「神無月」しかサポートしていません
|
|
168
200
|
* 将来の日付に関しては、現在の元号がずっと継続しているとみなします
|
|
169
201
|
* 日本でユリウス暦は使われていないので、Date::JAPAN は単にグレゴリオ暦への改暦日の目安、と言うだけです。Date.new で使う意味はほぼありません。
|
|
202
|
+
* 時刻の解釈・出力は単純な数字変換のみで、十二時辰などの伝統的時刻制度との対応はありません
|
|
203
|
+
* 時刻パース時、「午前」は無変換、「午後」は12時未満の時にのみ+12します (午後十二時 → 12:00)
|
|
204
|
+
* 「三時間」「13時代」のような「数字+時」を含む複合語も時刻として解釈されることがあります (このため、従来 Date.parse が数字を日として解釈して成功していた文字列がエラーになる場合があります)
|
|
205
|
+
* 範囲外の時刻 (二十五時など) は ASCII 表記 (25:00) と同様に扱われ、Time.parse では通常 ArgumentError になります
|
|
206
|
+
* 和暦・漢数字時刻のパース対応は Date.parse / Date._parse / Time.parse のみです。DateTime.parse は Ruby 内部のパーサを直接呼ぶため対象外です
|
|
170
207
|
|
|
171
208
|
## 参照元データ
|
|
172
209
|
|
|
173
210
|
作成には以下のデータを参照しました。
|
|
174
211
|
|
|
175
|
-
*
|
|
176
|
-
*
|
|
212
|
+
* Wakaba 氏による https://github.com/manakai/data-locale のデータを利用しています
|
|
213
|
+
* 旧暦: [suikawiki - 旧暦](http://wiki.suikawiki.org/n/%E6%97%A7%E6%9A%A6#section-%E5%AF%BE%E7%85%A7%E8%A1%A8%E3%81%A8%E5%A4%89%E6%8F%9B%E3%83%84%E3%83%BC%E3%83%AB) にある「日本暦日原典」第4版準拠の先発グレゴリオ暦対照表 (kyuureki-map.txt)
|
|
214
|
+
* 元号: 同リポジトリの元号定義データ (era-defs.json)
|
|
177
215
|
|
|
178
216
|
## ライセンス
|
|
179
217
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'wareki/calendar_def'
|
|
4
|
+
|
|
5
|
+
module Wareki
|
|
6
|
+
# 旧暦テーブルの参照ロジック。1年分の旧暦情報は整数1個 (40bit) に
|
|
7
|
+
# ビットパックされている。PACKED[西暦年 - YEAR_MIN]:
|
|
8
|
+
# bits 0..21 : その年の最初の月の初日のユリウス通日 (JD)
|
|
9
|
+
# bits 22..34 : 月の大小マスク (bit i = i 番目の月が大の月 = 30日)
|
|
10
|
+
# bit 35 : 閏月を含む13ヶ月の年なら1
|
|
11
|
+
# bits 36..39 : 閏月の月番号 (1..12、閏月がなければ0)
|
|
12
|
+
# 明治5年12月 (テーブル最終月) はグレゴリオ暦切替のため LAST_MONTH_DAYS
|
|
13
|
+
# (= 2) 日で打ち切られており、大小マスクには反映されていない。
|
|
14
|
+
module Calendar
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def covers_year?(year)
|
|
18
|
+
year.between?(YEAR_MIN, YEAR_MAX)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def covers_jd?(jd)
|
|
22
|
+
jd.between?(JD_MIN, JD_MAX)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# 閏月の月番号。閏月のない年・範囲外の年は nil
|
|
26
|
+
def leap_month(year)
|
|
27
|
+
covers_year?(year) or return nil
|
|
28
|
+
lp = PACKED[year - YEAR_MIN] >> 36
|
|
29
|
+
lp == 0 ? nil : lp
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 月番号 (1始まり) を月配列添字 (閏月込み・0始まり) に変換する。
|
|
33
|
+
# year がテーブル範囲内であることは呼び出し側が保証すること。
|
|
34
|
+
def month_index(year, month, is_leap)
|
|
35
|
+
lp = leap_month(year)
|
|
36
|
+
idx = month - 1
|
|
37
|
+
is_leap || (lp && month > lp) and idx += 1
|
|
38
|
+
idx
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def last_day_of_month(year, month, is_leap)
|
|
42
|
+
covers_year?(year) or return nil
|
|
43
|
+
packed = PACKED[year - YEAR_MIN]
|
|
44
|
+
idx = month_index(year, month, is_leap)
|
|
45
|
+
months = 12 + ((packed >> 35) & 1)
|
|
46
|
+
return LAST_MONTH_DAYS if year == YEAR_MAX && idx == months - 1
|
|
47
|
+
|
|
48
|
+
29 + ((packed >> (22 + idx)) & 1)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def to_jd(year, month, day, is_leap)
|
|
52
|
+
covers_year?(year) or return nil
|
|
53
|
+
packed = PACKED[year - YEAR_MIN]
|
|
54
|
+
idx = month_index(year, month, is_leap)
|
|
55
|
+
jd = packed & 0x3fffff
|
|
56
|
+
i = 0
|
|
57
|
+
while i < idx
|
|
58
|
+
jd += 29 + ((packed >> (22 + i)) & 1)
|
|
59
|
+
i += 1
|
|
60
|
+
end
|
|
61
|
+
jd + day - 1
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# jd を [西暦年, 月, 日, 閏月フラグ] に変換する。範囲外は nil
|
|
65
|
+
def find_date_ary(jd)
|
|
66
|
+
covers_jd?(jd) or return nil
|
|
67
|
+
i = PACKED.bsearch_index { |packed| (packed & 0x3fffff) > jd }
|
|
68
|
+
if i.nil?
|
|
69
|
+
i = PACKED.size - 1
|
|
70
|
+
else
|
|
71
|
+
i -= 1
|
|
72
|
+
end
|
|
73
|
+
packed = PACKED[i]
|
|
74
|
+
month_start = packed & 0x3fffff
|
|
75
|
+
months = 12 + ((packed >> 35) & 1)
|
|
76
|
+
lp = packed >> 36
|
|
77
|
+
idx = 0
|
|
78
|
+
while idx < months - 1
|
|
79
|
+
next_start = month_start + 29 + ((packed >> (22 + idx)) & 1)
|
|
80
|
+
break if jd < next_start
|
|
81
|
+
|
|
82
|
+
month_start = next_start
|
|
83
|
+
idx += 1
|
|
84
|
+
end
|
|
85
|
+
month = idx + 1
|
|
86
|
+
month -= 1 if lp != 0 && lp < month
|
|
87
|
+
[YEAR_MIN + i, month, jd - month_start + 1, lp != 0 && lp == idx]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|