wareki 1.1.0 → 2.0.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 +44 -0
- data/README.md +44 -6
- data/lib/wareki/calendar_def.rb +8 -9
- data/lib/wareki/common.rb +24 -4
- data/lib/wareki/date.rb +134 -55
- data/lib/wareki/era_def.rb +2 -2
- data/lib/wareki/std_ext.rb +49 -5
- data/lib/wareki/utils.rb +91 -12
- data/lib/wareki/version.rb +1 -1
- metadata +9 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 23992b6b4cd96544832ea1db1e843279eddabc6d205d2a7af87c30e29079fc7b
|
|
4
|
+
data.tar.gz: 706f0a880da6c9a05a3fa013450aa04dbd15993d5144df7aeef92d9f49b19f4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d03b898c5bd3efc4087d9a9b6cfdb54526b30c7088e2a051b3bc31ae9c3994acca5607a8920ddd44f6acc1b9331ac4e62a6a82943689e3e41beb5633f165a5bc
|
|
7
|
+
data.tar.gz: 77d82b574ff6fee3fee4c19f27faf532ac040b2fb933b9c33d86ffd1fd6deb32a6aa9c5a2c08eb4ee039594e60032c97a2a0e95d26a9489b2790d7290480073c
|
data/ChangeLog
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
2026-07-13 Tatsuki Sugiura <sugi@nemui.org>
|
|
2
|
+
|
|
3
|
+
* Version: 2.0.0
|
|
4
|
+
* Time.parse now understands Japanese kansuji/zenkaku time notations
|
|
5
|
+
(十二時三十四分五十六秒, 午後三時半, 正午, ...) via the patched
|
|
6
|
+
Date._parse; Date.parse no longer misreads bare 時分秒 strings
|
|
7
|
+
* Add %JT* time format directives (%JTf/%JTF/%JTH(k)/%JTM(k)/%JTS(k));
|
|
8
|
+
Time#strftime now supports all %J directives and DateTime#strftime
|
|
9
|
+
expands %JT too; add Time#to_wareki_date
|
|
10
|
+
* Strict date validation: nonexistent dates now raise
|
|
11
|
+
Wareki::InvalidDate (< ArgumentError) (month/day out of range,
|
|
12
|
+
nonexistent leap month, and the Meiji 5 December calendar-switch
|
|
13
|
+
gap for all era notations); patched Date.parse re-raises it
|
|
14
|
+
instead of falling back to stdlib misinterpretation
|
|
15
|
+
* README: document that conversion from Date/jd prefers northern court
|
|
16
|
+
eras during the Nanboku-cho period (previous statement was wrong;
|
|
17
|
+
behavior unchanged from 1.1.0)
|
|
18
|
+
* Update kyuureki calendar data (regenerated from
|
|
19
|
+
manakai/data-locale); corrects month boundaries of some
|
|
20
|
+
historical years
|
|
21
|
+
* Wareki::Date#- returns day count for date-like operands;
|
|
22
|
+
#+ raises TypeError for non-numeric operands (stdlib parity)
|
|
23
|
+
* Support date calculation with ActiveSupport::Duration
|
|
24
|
+
(was NotImplementedError)
|
|
25
|
+
* Add Wareki::Date#hash, #<=>, Comparable and #succ
|
|
26
|
+
* Invalidate cached jd on attribute writes; writers keep
|
|
27
|
+
year/era_year consistent
|
|
28
|
+
* Freeze era definition structs to prevent accidental mutation
|
|
29
|
+
of shared state
|
|
30
|
+
* Fix imperial_year= setter (sign error)
|
|
31
|
+
* Parse apostrophe leap-month markers so %Jf/%Jm output round-trips
|
|
32
|
+
* Fix misokka (晦日) parsing for 皇紀/西暦/紀元前/era-less dates
|
|
33
|
+
* DateTime#strftime now supports %J directives
|
|
34
|
+
* Escaped %%J or invalid %J sequences no longer trigger conversion;
|
|
35
|
+
Wareki::Date#strftime honors %% escapes too
|
|
36
|
+
* Fast-path non-wareki strings in patched Date.parse/_parse
|
|
37
|
+
* Wareki.parse_to_date falls back on UnsupportedDateRange too
|
|
38
|
+
* Fix deprecated Utils.i_to_kan (was calling undefined method)
|
|
39
|
+
* gemspec: SPDX license identifier (BSD-2-Clause)
|
|
40
|
+
|
|
41
|
+
[ by masa.kunikata <masa.kunikata@gmail.com> ]
|
|
42
|
+
* Add zero padding format feature
|
|
43
|
+
* Use zero padded format on default
|
|
44
|
+
|
|
1
45
|
2019-12-24 Tatsuki Sugiura <sugi@nemui.org>
|
|
2
46
|
|
|
3
47
|
* Version: 1.1.0
|
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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
|
|
|
@@ -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,17 +193,24 @@ 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
|
-
*
|
|
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版準拠の先発グレゴリオ暦対照表
|
|
176
214
|
* 元号: [Wikipedia - 元号一覧_(日本)](https://ja.wikipedia.org/wiki/%E5%85%83%E5%8F%B7%E4%B8%80%E8%A6%A7_%28%E6%97%A5%E6%9C%AC%29) のユリウス歴とグレゴリオ暦表記の物に基づいています
|
|
177
215
|
|
|
178
216
|
## ライセンス
|
data/lib/wareki/calendar_def.rb
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
1
|
module Wareki
|
|
3
2
|
Year = Struct.new(:year, :start, :end, :leap_month, :month_starts, :month_days)
|
|
4
3
|
YEAR_DEFS = [
|
|
5
4
|
Year.new(445, 1883618, 1884001, 5, [1883618, 1883648, 1883677, 1883707, 1883736, 1883766, 1883795, 1883825, 1883854, 1883884, 1883913, 1883943, 1883972], [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30]),
|
|
6
5
|
Year.new(446, 1884002, 1884355, nil, [1884002, 1884032, 1884061, 1884091, 1884120, 1884150, 1884179, 1884209, 1884238, 1884268, 1884297, 1884327], [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29]),
|
|
7
|
-
Year.new(447, 1884356, 1884710, nil, [1884356, 1884386, 1884415, 1884445,
|
|
8
|
-
Year.new(448, 1884711, 1885094, 2, [1884711, 1884740, 1884770, 1884799, 1884829, 1884858, 1884888, 1884917, 1884947,
|
|
6
|
+
Year.new(447, 1884356, 1884710, nil, [1884356, 1884386, 1884415, 1884445, 1884474, 1884504, 1884534, 1884563, 1884593, 1884622, 1884652, 1884681], [30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30]),
|
|
7
|
+
Year.new(448, 1884711, 1885094, 2, [1884711, 1884740, 1884770, 1884799, 1884829, 1884858, 1884888, 1884917, 1884947, 1884976, 1885006, 1885036, 1885065], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30, 29, 30]),
|
|
9
8
|
Year.new(449, 1885095, 1885448, nil, [1885095, 1885124, 1885154, 1885183, 1885213, 1885242, 1885272, 1885301, 1885331, 1885360, 1885390, 1885419], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30]),
|
|
10
9
|
Year.new(450, 1885449, 1885832, 10, [1885449, 1885479, 1885508, 1885538, 1885567, 1885597, 1885626, 1885656, 1885685, 1885715, 1885744, 1885774, 1885803], [30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30]),
|
|
11
|
-
Year.new(451, 1885833, 1886186, nil, [1885833, 1885862, 1885892,
|
|
12
|
-
Year.new(452, 1886187, 1886541, nil, [1886187, 1886217, 1886246, 1886276, 1886305, 1886335, 1886364, 1886394,
|
|
10
|
+
Year.new(451, 1885833, 1886186, nil, [1885833, 1885862, 1885892, 1885921, 1885951, 1885981, 1886010, 1886040, 1886069, 1886099, 1886128, 1886158], [29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29]),
|
|
11
|
+
Year.new(452, 1886187, 1886541, nil, [1886187, 1886217, 1886246, 1886276, 1886305, 1886335, 1886364, 1886394, 1886423, 1886453, 1886483, 1886512], [30, 29, 30, 29, 30, 29, 30, 29, 30, 30, 29, 30]),
|
|
13
12
|
Year.new(453, 1886542, 1886925, 6, [1886542, 1886571, 1886601, 1886630, 1886660, 1886689, 1886719, 1886748, 1886778, 1886807, 1886837, 1886866, 1886896], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30]),
|
|
14
13
|
Year.new(454, 1886926, 1887279, nil, [1886926, 1886955, 1886985, 1887014, 1887044, 1887073, 1887103, 1887132, 1887162, 1887191, 1887221, 1887250], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30]),
|
|
15
14
|
Year.new(455, 1887280, 1887633, nil, [1887280, 1887309, 1887339, 1887369, 1887398, 1887428, 1887457, 1887487, 1887516, 1887546, 1887575, 1887605], [29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29]),
|
|
@@ -255,7 +254,7 @@ module Wareki
|
|
|
255
254
|
Year.new(695, 1974927, 1975310, 2, [1974927, 1974956, 1974986, 1975015, 1975045, 1975074, 1975104, 1975133, 1975163, 1975192, 1975222, 1975252, 1975281], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30, 29, 30]),
|
|
256
255
|
Year.new(696, 1975311, 1975664, nil, [1975311, 1975340, 1975370, 1975399, 1975429, 1975458, 1975488, 1975517, 1975547, 1975576, 1975606, 1975636], [29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 30, 29]),
|
|
257
256
|
Year.new(697, 1975665, 1976048, 12, [1975665, 1975694, 1975724, 1975753, 1975783, 1975813, 1975842, 1975871, 1975901, 1975931, 1975960, 1975990, 1976020], [29, 30, 29, 30, 30, 29, 29, 30, 30, 29, 30, 30, 29]),
|
|
258
|
-
Year.new(698, 1976049, 1976403, nil, [1976049, 1976079, 1976108, 1976137, 1976167, 1976196, 1976226, 1976255, 1976285,
|
|
257
|
+
Year.new(698, 1976049, 1976403, nil, [1976049, 1976079, 1976108, 1976137, 1976167, 1976196, 1976226, 1976255, 1976285, 1976315, 1976344, 1976374], [30, 29, 29, 30, 29, 30, 29, 30, 30, 29, 30, 30]),
|
|
259
258
|
Year.new(699, 1976404, 1976757, nil, [1976404, 1976433, 1976463, 1976492, 1976521, 1976551, 1976580, 1976609, 1976639, 1976669, 1976698, 1976728], [29, 30, 29, 29, 30, 29, 29, 30, 30, 29, 30, 30]),
|
|
260
259
|
Year.new(700, 1976758, 1977141, 7, [1976758, 1976788, 1976817, 1976847, 1976876, 1976905, 1976935, 1976964, 1976993, 1977023, 1977052, 1977082, 1977112], [30, 29, 30, 29, 29, 30, 29, 29, 30, 29, 30, 30, 30]),
|
|
261
260
|
Year.new(701, 1977142, 1977495, nil, [1977142, 1977171, 1977201, 1977231, 1977260, 1977289, 1977319, 1977348, 1977377, 1977407, 1977436, 1977466], [29, 30, 30, 29, 29, 30, 29, 29, 30, 29, 30, 30]),
|
|
@@ -300,7 +299,7 @@ module Wareki
|
|
|
300
299
|
Year.new(740, 1991375, 1991729, nil, [1991375, 1991405, 1991434, 1991464, 1991493, 1991523, 1991552, 1991582, 1991612, 1991641, 1991671, 1991700], [30, 29, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30]),
|
|
301
300
|
Year.new(741, 1991730, 1992113, 3, [1991730, 1991759, 1991789, 1991818, 1991847, 1991877, 1991906, 1991936, 1991966, 1991995, 1992025, 1992055, 1992084], [29, 30, 29, 29, 30, 29, 30, 30, 29, 30, 30, 29, 30]),
|
|
302
301
|
Year.new(742, 1992114, 1992467, nil, [1992114, 1992143, 1992173, 1992202, 1992231, 1992261, 1992290, 1992320, 1992349, 1992379, 1992409, 1992439], [29, 30, 29, 29, 30, 29, 30, 29, 30, 30, 30, 29]),
|
|
303
|
-
Year.new(743, 1992468, 1992822, nil, [1992468, 1992498, 1992527, 1992557, 1992586, 1992615, 1992645, 1992674, 1992704,
|
|
302
|
+
Year.new(743, 1992468, 1992822, nil, [1992468, 1992498, 1992527, 1992557, 1992586, 1992615, 1992645, 1992674, 1992704, 1992733, 1992763, 1992793], [30, 29, 30, 29, 29, 30, 29, 30, 29, 30, 30, 30]),
|
|
304
303
|
Year.new(744, 1992852, 1993205, 1, [1992823, 1992852, 1992882, 1992911, 1992941, 1992970, 1992999, 1993029, 1993058, 1993087, 1993117, 1993147, 1993176], [29, 30, 29, 30, 29, 29, 30, 29, 29, 30, 30, 29, 30]),
|
|
305
304
|
Year.new(745, 1993206, 1993559, nil, [1993206, 1993236, 1993266, 1993295, 1993325, 1993354, 1993383, 1993413, 1993442, 1993471, 1993501, 1993531], [30, 30, 29, 30, 29, 29, 30, 29, 29, 30, 30, 29]),
|
|
306
305
|
Year.new(746, 1993560, 1993943, 9, [1993560, 1993590, 1993620, 1993649, 1993679, 1993709, 1993738, 1993767, 1993797, 1993826, 1993856, 1993885, 1993915], [30, 30, 29, 30, 30, 29, 29, 30, 29, 30, 29, 30, 29]),
|
|
@@ -351,7 +350,7 @@ module Wareki
|
|
|
351
350
|
Year.new(791, 2010009, 2010362, nil, [2010009, 2010038, 2010068, 2010098, 2010128, 2010157, 2010187, 2010216, 2010245, 2010275, 2010304, 2010334], [29, 30, 30, 30, 29, 30, 29, 29, 30, 29, 30, 29]),
|
|
352
351
|
Year.new(792, 2010363, 2010746, 11, [2010363, 2010393, 2010423, 2010452, 2010481, 2010511, 2010541, 2010570, 2010600, 2010630, 2010659, 2010689, 2010718], [30, 30, 29, 29, 30, 30, 29, 30, 30, 29, 30, 29, 29]),
|
|
353
352
|
Year.new(793, 2010747, 2011101, nil, [2010747, 2010777, 2010806, 2010836, 2010865, 2010895, 2010924, 2010954, 2010984, 2011013, 2011043, 2011072], [30, 29, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30]),
|
|
354
|
-
Year.new(794, 2011102, 2011456, nil, [2011102, 2011131, 2011161, 2011190,
|
|
353
|
+
Year.new(794, 2011102, 2011456, nil, [2011102, 2011131, 2011161, 2011190, 2011220, 2011249, 2011278, 2011308, 2011338, 2011367, 2011397, 2011427], [29, 30, 29, 30, 29, 29, 30, 30, 29, 30, 30, 30]),
|
|
355
354
|
Year.new(795, 2011457, 2011840, 7, [2011457, 2011486, 2011515, 2011545, 2011574, 2011603, 2011633, 2011662, 2011692, 2011722, 2011751, 2011781, 2011811], [29, 29, 30, 29, 29, 30, 29, 30, 30, 29, 30, 30, 30]),
|
|
356
355
|
Year.new(796, 2011841, 2012194, nil, [2011841, 2011870, 2011899, 2011929, 2011958, 2011987, 2012017, 2012046, 2012076, 2012105, 2012135, 2012165], [29, 29, 30, 29, 29, 30, 29, 30, 29, 30, 30, 30]),
|
|
357
356
|
Year.new(797, 2012195, 2012548, nil, [2012195, 2012224, 2012254, 2012283, 2012313, 2012342, 2012371, 2012401, 2012430, 2012460, 2012489, 2012519], [29, 30, 29, 30, 29, 29, 30, 29, 30, 29, 30, 30]),
|
|
@@ -377,7 +376,7 @@ module Wareki
|
|
|
377
376
|
Year.new(817, 2019488, 2019871, 4, [2019488, 2019518, 2019547, 2019577, 2019607, 2019636, 2019666, 2019695, 2019725, 2019754, 2019784, 2019813, 2019842], [30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 29, 30]),
|
|
378
377
|
Year.new(818, 2019872, 2020226, nil, [2019872, 2019902, 2019931, 2019961, 2019991, 2020020, 2020050, 2020079, 2020109, 2020138, 2020168, 2020197], [30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, 30]),
|
|
379
378
|
Year.new(819, 2020227, 2020580, nil, [2020227, 2020256, 2020286, 2020315, 2020345, 2020374, 2020404, 2020433, 2020463, 2020493, 2020522, 2020552], [29, 30, 29, 30, 29, 30, 29, 30, 30, 29, 30, 29]),
|
|
380
|
-
Year.new(820, 2020611, 2020964, 1, [2020581, 2020611,
|
|
379
|
+
Year.new(820, 2020611, 2020964, 1, [2020581, 2020611, 2020640, 2020670, 2020699, 2020728, 2020758, 2020788, 2020817, 2020847, 2020877, 2020906, 2020936], [30, 29, 30, 29, 29, 30, 30, 29, 30, 30, 29, 30, 29]),
|
|
381
380
|
Year.new(821, 2020965, 2021319, nil, [2020965, 2020995, 2021024, 2021053, 2021083, 2021112, 2021142, 2021171, 2021201, 2021231, 2021260, 2021290], [30, 29, 29, 30, 29, 30, 29, 30, 30, 29, 30, 30]),
|
|
382
381
|
Year.new(822, 2021320, 2021703, 9, [2021320, 2021350, 2021379, 2021408, 2021437, 2021467, 2021496, 2021525, 2021555, 2021585, 2021614, 2021644, 2021674], [30, 29, 29, 29, 30, 29, 29, 30, 30, 29, 30, 30, 30]),
|
|
383
382
|
Year.new(823, 2021704, 2022057, nil, [2021704, 2021733, 2021763, 2021792, 2021821, 2021851, 2021880, 2021909, 2021939, 2021969, 2021998, 2022028], [29, 30, 29, 29, 30, 29, 29, 30, 30, 29, 30, 30]),
|
data/lib/wareki/common.rb
CHANGED
|
@@ -9,6 +9,8 @@ module Wareki
|
|
|
9
9
|
GREGORIAN_START_YEAR = 1873
|
|
10
10
|
IMPERIAL_START = 1_480_041 # Date.new(-660, 2, 11, Date::GREGORIAN).jd
|
|
11
11
|
IMPERIAL_START_YEAR = -660
|
|
12
|
+
WESTERN_ERA_NAMES = ['', '西暦', '紀元前'].freeze
|
|
13
|
+
IMPERIAL_ERA_NAMES = %w(皇紀 神武天皇即位紀元).freeze
|
|
12
14
|
DATE_INFINITY = ::Date.new(280_000_000, 12, 31) # Use 280000000 for jruby limitation...
|
|
13
15
|
YEAR_BY_NUM = Hash[*YEAR_DEFS.map { |y| [y.year, y] }.flatten].freeze
|
|
14
16
|
KANJI_VARIANTS = {
|
|
@@ -42,8 +44,8 @@ module Wareki
|
|
|
42
44
|
NORMALIZE_KANJI_VARIANTS_HASH = KANJI_VARIANTS.each_with_object({}) { |(n, s), h| s.each_char { |c| h[c] = n } }
|
|
43
45
|
NORMALIZE_KANJI_VARIANTS = ->(str) { str.gsub(NORMALIZE_KANJI_VARIANTS_REGEX, NORMALIZE_KANJI_VARIANTS_HASH) }
|
|
44
46
|
ERA_BY_NAME = Hash[*(ERA_NORTH_DEFS + ERA_DEFS).flat_map { |g| [g.name, g] }]
|
|
45
|
-
ERA_BY_NAME['皇紀'] = ERA_BY_NAME['神武天皇即位紀元'] = Era.new('皇紀', -660, 1_480_041, DATE_INFINITY.jd)
|
|
46
|
-
ERA_BY_NAME['西暦'] = ERA_BY_NAME[''] = Era.new('西暦', 1, 1_721_424, DATE_INFINITY.jd)
|
|
47
|
+
ERA_BY_NAME['皇紀'] = ERA_BY_NAME['神武天皇即位紀元'] = Era.new('皇紀', -660, 1_480_041, DATE_INFINITY.jd).freeze
|
|
48
|
+
ERA_BY_NAME['西暦'] = ERA_BY_NAME[''] = Era.new('西暦', 1, 1_721_424, DATE_INFINITY.jd).freeze
|
|
47
49
|
ERA_BY_NAME.default_proc = ->(hash, key) { hash.fetch(SQUARE_ERAS[key] || NORMALIZE_KANJI_VARIANTS[key], nil) }
|
|
48
50
|
ERA_BY_NAME.freeze
|
|
49
51
|
ERA_REGEX = Regexp.new(
|
|
@@ -58,18 +60,36 @@ module Wareki
|
|
|
58
60
|
(?:(?<era_name>紀元前|#{ERA_REGEX})?
|
|
59
61
|
(?:(?<year>[元#{NUM_CHARS}]+)年))?
|
|
60
62
|
(?:(?<is_leap>閏|潤|うるう)?
|
|
61
|
-
(?:(?<month>[正#{NUM_CHARS}]+)
|
|
63
|
+
(?:(?<month>[正#{NUM_CHARS}]+)(?<is_leap_post>['’])?月 |
|
|
62
64
|
(?<alt_month>#{ALT_MONTH_NAME.join('|')})))?
|
|
63
65
|
(?:(?<day>[元朔晦#{NUM_CHARS}]+)日|元旦)?
|
|
64
66
|
}x.freeze
|
|
67
|
+
# REGEX が空でないマッチを返すには 年/月/日/元旦 か、「月」を含まない
|
|
68
|
+
# 月の別名 (弥生・師走) のいずれかが必要。それ以外は素の Date.parse に
|
|
69
|
+
# 直行させて monkey patch のオーバーヘッドを避ける。
|
|
70
|
+
PARSE_QUICK_FILTER = /[年月日]|元旦|弥生|師走/.freeze
|
|
71
|
+
TIME_REGEX = %r{
|
|
72
|
+
(?<noon>正午) |
|
|
73
|
+
(?:(?<ampm>午前|午後)[[:space:]]*)?
|
|
74
|
+
(?<hour>[#{NUM_CHARS}]+)[[:space:]]*時
|
|
75
|
+
(?:[[:space:]]*
|
|
76
|
+
(?:(?<half>半) |
|
|
77
|
+
(?<min>[#{NUM_CHARS}]+)[[:space:]]*分
|
|
78
|
+
(?:[[:space:]]*(?<sec>[#{NUM_CHARS}]+)[[:space:]]*秒)?))?
|
|
79
|
+
}x.freeze
|
|
80
|
+
# TIME_REGEX が非空マッチしうるのは「時」か「正午」を含む文字列のみ
|
|
81
|
+
TIME_PARSE_QUICK_FILTER = /時|正午/.freeze
|
|
65
82
|
|
|
66
83
|
class UnsupportedDateRange < StandardError; end
|
|
84
|
+
class InvalidDate < ArgumentError; end
|
|
67
85
|
|
|
68
86
|
module_function
|
|
69
87
|
|
|
70
88
|
def parse_to_date(str, start = ::Date::ITALY)
|
|
71
89
|
Date.parse(str).to_date(start)
|
|
72
|
-
rescue
|
|
90
|
+
rescue InvalidDate
|
|
91
|
+
raise
|
|
92
|
+
rescue ArgumentError, UnsupportedDateRange
|
|
73
93
|
::Date.parse(str, true, start)
|
|
74
94
|
end
|
|
75
95
|
end
|
data/lib/wareki/date.rb
CHANGED
|
@@ -8,33 +8,25 @@ require 'wareki/kansuji'
|
|
|
8
8
|
module Wareki
|
|
9
9
|
# Wareki date handling class, main implementation.
|
|
10
10
|
class Date
|
|
11
|
-
|
|
11
|
+
include Comparable
|
|
12
|
+
|
|
13
|
+
attr_reader :year, :month, :day, :era_year, :era_name
|
|
12
14
|
|
|
13
15
|
def self.today
|
|
14
16
|
jd(::Date.today.jd)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def self._check_invalid_date(era, year, month, day)
|
|
18
|
-
month == 12 or return true
|
|
19
|
-
day > 2 or return true
|
|
20
|
-
(era == '明治' && year == 5 ||
|
|
21
|
-
%w(皇紀 神武天皇即位紀元).member?(era) &&
|
|
22
|
-
year == GREGORIAN_START_YEAR - IMPERIAL_START_YEAR - 1) and
|
|
23
|
-
return false
|
|
24
|
-
true
|
|
25
|
-
end
|
|
26
|
-
|
|
27
19
|
def self._parse(str)
|
|
28
20
|
str = str.to_s.gsub(/[[:space:]]/, '')
|
|
29
21
|
match = REGEX.match(str)
|
|
30
|
-
match && !match[0].empty? or
|
|
22
|
+
(match && !match[0].empty?) or
|
|
31
23
|
raise ArgumentError, "Invaild Date: #{str}"
|
|
32
24
|
era = match[:era_name]
|
|
33
25
|
if (era.nil? || era == '') && match[:year].nil?
|
|
34
26
|
year = Date.today.year
|
|
35
27
|
else
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
year = Utils.k2i(match[:year])
|
|
29
|
+
year > 0 or raise ArgumentError, "Invalid year: #{str}"
|
|
38
30
|
end
|
|
39
31
|
month = day = 1
|
|
40
32
|
|
|
@@ -48,20 +40,20 @@ module Wareki
|
|
|
48
40
|
end
|
|
49
41
|
|
|
50
42
|
month > 12 || month < 1 and
|
|
51
|
-
raise
|
|
43
|
+
raise InvalidDate, "invalid date (month out of range): #{str}"
|
|
44
|
+
|
|
45
|
+
is_leap = !!(match[:is_leap] || match[:is_leap_post])
|
|
52
46
|
|
|
53
47
|
if match[:day]
|
|
54
48
|
if match[:day] == '晦'
|
|
55
|
-
|
|
49
|
+
civil_year = Utils.era_year_to_civil(era, year)
|
|
50
|
+
day = Utils.last_day_of_era_month(era, civil_year, month, is_leap)
|
|
56
51
|
else
|
|
57
52
|
day = Utils.k2i(match[:day])
|
|
58
53
|
end
|
|
59
54
|
end
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
raise ArgumentError, "Invaild Date: #{str}"
|
|
63
|
-
|
|
64
|
-
{era: era, year: year, month: month, day: day, is_leap: !!match[:is_leap]}
|
|
56
|
+
{era: era, year: year, month: month, day: day, is_leap: is_leap}
|
|
65
57
|
end
|
|
66
58
|
|
|
67
59
|
def self.parse(str)
|
|
@@ -87,23 +79,13 @@ module Wareki
|
|
|
87
79
|
end
|
|
88
80
|
|
|
89
81
|
def initialize(era_name, era_year, month = 1, day = 1, is_leap_month = false)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
82
|
+
@era_name = era_name.to_s
|
|
83
|
+
@era_year = era_year
|
|
93
84
|
@month = month
|
|
94
85
|
@day = day
|
|
95
86
|
@is_leap_month = is_leap_month
|
|
96
|
-
@
|
|
97
|
-
|
|
98
|
-
if era_name.to_s == '' || era_name == '西暦'
|
|
99
|
-
@year = @era_year
|
|
100
|
-
elsif era_name.to_s == '紀元前'
|
|
101
|
-
@year = -@era_year
|
|
102
|
-
elsif %w(皇紀 神武天皇即位紀元).include? era_name
|
|
103
|
-
@year = era_year + IMPERIAL_START_YEAR
|
|
104
|
-
else
|
|
105
|
-
@year = ERA_BY_NAME[era_name].year + era_year - 1
|
|
106
|
-
end
|
|
87
|
+
@year = Utils.era_year_to_civil(@era_name, @era_year)
|
|
88
|
+
_validate_date!
|
|
107
89
|
end
|
|
108
90
|
|
|
109
91
|
def imperial_year
|
|
@@ -111,7 +93,7 @@ module Wareki
|
|
|
111
93
|
end
|
|
112
94
|
|
|
113
95
|
def imperial_year=(v)
|
|
114
|
-
|
|
96
|
+
self.year = v + IMPERIAL_START_YEAR
|
|
115
97
|
end
|
|
116
98
|
|
|
117
99
|
def leap_month?
|
|
@@ -119,28 +101,86 @@ module Wareki
|
|
|
119
101
|
end
|
|
120
102
|
|
|
121
103
|
def leap_month=(v)
|
|
104
|
+
@jd = nil
|
|
122
105
|
@is_leap_month = v
|
|
123
106
|
end
|
|
124
107
|
|
|
108
|
+
def year=(v)
|
|
109
|
+
era_year = Utils.civil_to_era_year(@era_name, v)
|
|
110
|
+
@jd = nil
|
|
111
|
+
@year = v
|
|
112
|
+
@era_year = era_year
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def month=(v)
|
|
116
|
+
@jd = nil
|
|
117
|
+
@month = v
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def day=(v)
|
|
121
|
+
@jd = nil
|
|
122
|
+
@day = v
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def era_year=(v)
|
|
126
|
+
year = Utils.era_year_to_civil(@era_name, v)
|
|
127
|
+
@jd = nil
|
|
128
|
+
@era_year = v
|
|
129
|
+
@year = year
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def era_name=(v)
|
|
133
|
+
era_name = v.to_s
|
|
134
|
+
year = Utils.era_year_to_civil(era_name, @era_year)
|
|
135
|
+
@jd = nil
|
|
136
|
+
@era_name = era_name
|
|
137
|
+
@year = year
|
|
138
|
+
end
|
|
139
|
+
|
|
125
140
|
def __set_jd(v)
|
|
126
141
|
@jd = v
|
|
127
142
|
end
|
|
128
143
|
|
|
129
144
|
def month_index
|
|
130
145
|
return month - 1 if
|
|
131
|
-
|
|
146
|
+
WESTERN_ERA_NAMES.include?(@era_name) || @year >= GREGORIAN_START_YEAR
|
|
132
147
|
|
|
133
148
|
yobj = YEAR_BY_NUM[@year] or
|
|
134
149
|
raise UnsupportedDateRange, "Cannot get year info of #{inspect}"
|
|
135
150
|
idx = month - 1
|
|
136
|
-
idx += 1 if leap_month? || yobj.leap_month && month > yobj.leap_month
|
|
151
|
+
idx += 1 if leap_month? || (yobj.leap_month && month > yobj.leap_month)
|
|
137
152
|
idx
|
|
138
153
|
end
|
|
139
154
|
|
|
155
|
+
def last_day_of_month
|
|
156
|
+
Utils.last_day_of_era_month(@era_name, @year, month, leap_month?)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def _validate_date!
|
|
160
|
+
(month.is_a?(Integer) && month >= 1 && month <= 12) or
|
|
161
|
+
raise InvalidDate, "invalid date (month out of range): #{inspect}"
|
|
162
|
+
(day.is_a?(Integer) && day >= 1) or
|
|
163
|
+
raise InvalidDate, "invalid date (day out of range): #{inspect}"
|
|
164
|
+
if !WESTERN_ERA_NAMES.include?(@era_name) && @year < GREGORIAN_START_YEAR
|
|
165
|
+
# 暦テーブル外の年は従来どおり jd 変換時の UnsupportedDateRange に委ねる
|
|
166
|
+
yobj = YEAR_BY_NUM[@year] or return
|
|
167
|
+
!leap_month? || yobj.leap_month == month or
|
|
168
|
+
raise InvalidDate, "invalid date (no leap month): #{inspect}"
|
|
169
|
+
day <= yobj.month_days[month_index] or
|
|
170
|
+
raise InvalidDate, "invalid date (day out of range): #{inspect}"
|
|
171
|
+
else
|
|
172
|
+
leap_month? and
|
|
173
|
+
raise InvalidDate, "invalid date (no leap month): #{inspect}"
|
|
174
|
+
day <= last_day_of_month or
|
|
175
|
+
raise InvalidDate, "invalid date (day out of range): #{inspect}"
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
140
179
|
def jd
|
|
141
180
|
@jd and return @jd
|
|
142
181
|
|
|
143
|
-
|
|
182
|
+
_validate_date!
|
|
183
|
+
WESTERN_ERA_NAMES.include?(@era_name) and
|
|
144
184
|
return @jd = ::Date.new(@year, month, day, ::Date::ITALY).jd
|
|
145
185
|
|
|
146
186
|
@year >= GREGORIAN_START_YEAR and
|
|
@@ -159,17 +199,28 @@ module Wareki
|
|
|
159
199
|
to_date.to_time
|
|
160
200
|
end
|
|
161
201
|
|
|
202
|
+
FORMAT_DIRECTIVE_REGEX = /%J(-|[_0]{0,2}[0-9]*|)([fFyYegGoOiImMsSlLdD][kK]?)/.freeze
|
|
203
|
+
FORMAT_EXPANSION_REGEX = /(?<!%)(?:%%)*\K#{FORMAT_DIRECTIVE_REGEX}/.freeze
|
|
204
|
+
|
|
205
|
+
def expand_wareki_format(format_str)
|
|
206
|
+
format_str.to_str.gsub(FORMAT_EXPANSION_REGEX) { format($2, $1) || $& }
|
|
207
|
+
end
|
|
208
|
+
|
|
162
209
|
def strftime(format_str = '%JF')
|
|
163
|
-
ret = format_str
|
|
210
|
+
ret = expand_wareki_format(format_str)
|
|
164
211
|
ret.index('%') or return ret
|
|
165
212
|
d = to_date
|
|
166
213
|
d.respond_to?(:_wareki_strftime_orig) ? d._wareki_strftime_orig(ret) : d.strftime(ret)
|
|
167
214
|
end
|
|
168
215
|
|
|
169
|
-
def
|
|
216
|
+
def _number_format(opt)
|
|
217
|
+
Utils.number_format(opt)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def format(key, opt = '')
|
|
170
221
|
case key.to_sym
|
|
171
222
|
when :e then era_name
|
|
172
|
-
when :g then era_name.to_s == '' ? '' : era_year
|
|
223
|
+
when :g then era_name.to_s == '' ? '' : Kernel.format(_number_format(opt), era_year)
|
|
173
224
|
when :G then era_name.to_s == '' ? '' : Utils.i2z(era_year)
|
|
174
225
|
when :Gk then era_name.to_s == '' ? '' : YaKansuji.to_kan(era_year, :simple)
|
|
175
226
|
when :GK
|
|
@@ -186,14 +237,14 @@ module Wareki
|
|
|
186
237
|
when :i then imperial_year
|
|
187
238
|
when :I then Utils.i2z(imperial_year)
|
|
188
239
|
when :Ik then YaKansuji.to_kan(imperial_year, :simple)
|
|
189
|
-
when :s then month
|
|
240
|
+
when :s then Kernel.format(_number_format(opt), month)
|
|
190
241
|
when :S then Utils.i2z(month)
|
|
191
242
|
when :Sk then YaKansuji.to_kan(month, :simple)
|
|
192
243
|
when :SK then Utils.alt_month_name(month)
|
|
193
244
|
when :l then leap_month? ? "'" : ''
|
|
194
245
|
when :L then leap_month? ? '’' : ''
|
|
195
246
|
when :Lk then leap_month? ? '閏' : ''
|
|
196
|
-
when :d then day
|
|
247
|
+
when :d then Kernel.format(_number_format(opt), day)
|
|
197
248
|
when :D then Utils.i2z(day)
|
|
198
249
|
when :Dk then YaKansuji.to_kan(day, :simple)
|
|
199
250
|
when :DK
|
|
@@ -201,19 +252,19 @@ module Wareki
|
|
|
201
252
|
'元'
|
|
202
253
|
elsif day == 1
|
|
203
254
|
'朔'
|
|
204
|
-
elsif day ==
|
|
255
|
+
elsif day == last_day_of_month
|
|
205
256
|
'晦'
|
|
206
257
|
else
|
|
207
258
|
YaKansuji.to_kan(day, :simple)
|
|
208
259
|
end
|
|
209
|
-
when :m then "#{format(:s)}#{format(:l)}"
|
|
260
|
+
when :m then "#{format(:s, opt)}#{format(:l)}"
|
|
210
261
|
when :M then "#{format(:Lk)}#{format(:S)}"
|
|
211
262
|
when :Mk then "#{format(:Lk)}#{format(:Sk)}"
|
|
212
|
-
when :y then "#{format(:e)}#{format(:g)}"
|
|
263
|
+
when :y then "#{format(:e)}#{format(:g, opt)}"
|
|
213
264
|
when :Y then "#{format(:e)}#{format(:G)}"
|
|
214
265
|
when :Yk then "#{format(:e)}#{format(:Gk)}"
|
|
215
266
|
when :YK then "#{format(:e)}#{format(:GK)}"
|
|
216
|
-
when :f then "#{format(:e)}#{format(:g)}年#{format(:s)}#{format(:l)}月#{format(:d)}日"
|
|
267
|
+
when :f then "#{format(:e)}#{format(:g, opt)}年#{format(:s, opt)}#{format(:l)}月#{format(:d, opt)}日"
|
|
217
268
|
when :F then "#{format(:e)}#{format(:GK)}年#{format(:Lk)}#{format(:Sk)}月#{format(:Dk)}日"
|
|
218
269
|
end
|
|
219
270
|
end
|
|
@@ -239,20 +290,48 @@ module Wareki
|
|
|
239
290
|
true
|
|
240
291
|
end
|
|
241
292
|
|
|
293
|
+
def hash
|
|
294
|
+
[self.class, @era_name, @era_year, @year, @month, @day, leap_month?].hash
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def <=>(other)
|
|
298
|
+
ojd = _jd_if_date_like(other)
|
|
299
|
+
ojd = other if ojd.nil? && other.is_a?(Numeric)
|
|
300
|
+
ojd.nil? and return nil
|
|
301
|
+
jd <=> ojd
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def succ
|
|
305
|
+
self + 1
|
|
306
|
+
end
|
|
307
|
+
|
|
242
308
|
def -(other)
|
|
243
|
-
|
|
309
|
+
n = _to_days(other)
|
|
310
|
+
n.nil? or return self.class.jd(jd - n)
|
|
311
|
+
ojd = _jd_if_date_like(other)
|
|
312
|
+
ojd and return jd - ojd
|
|
313
|
+
raise TypeError, "Cannot subtract #{other.inspect} from Wareki::Date"
|
|
244
314
|
end
|
|
245
315
|
|
|
246
316
|
def +(other)
|
|
247
|
-
|
|
317
|
+
n = _to_days(other)
|
|
318
|
+
n.nil? and raise TypeError, "Cannot add #{other.inspect} to Wareki::Date"
|
|
319
|
+
self.class.jd(jd + n)
|
|
248
320
|
end
|
|
249
321
|
|
|
250
|
-
def
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
other
|
|
322
|
+
def _to_days(other)
|
|
323
|
+
# rubocop:disable Style/ClassEqualityComparison
|
|
324
|
+
return other.in_days if other.class.name == 'ActiveSupport::Duration'
|
|
325
|
+
# rubocop:enable Style/ClassEqualityComparison
|
|
326
|
+
|
|
327
|
+
other.is_a?(Numeric) ? other : nil
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def _jd_if_date_like(other)
|
|
331
|
+
return other.jd if other.respond_to?(:jd)
|
|
332
|
+
|
|
333
|
+
other.respond_to?(:to_date) && !other.is_a?(Numeric) and other = other.to_date
|
|
334
|
+
other.respond_to?(:jd) ? other.jd : nil
|
|
256
335
|
end
|
|
257
336
|
end
|
|
258
337
|
end
|
data/lib/wareki/era_def.rb
CHANGED
|
@@ -252,7 +252,7 @@ module Wareki
|
|
|
252
252
|
Era.new("昭和", 1926, 2424875, 2447534),
|
|
253
253
|
Era.new("平成", 1989, 2447535, 2458604),
|
|
254
254
|
Era.new("令和", 2019, 2458605, DAY_MAX),
|
|
255
|
-
].freeze
|
|
255
|
+
].each(&:freeze).freeze
|
|
256
256
|
ERA_NORTH_DEFS = [
|
|
257
257
|
Era.new("大化", 645, 1956842, 1958551),
|
|
258
258
|
Era.new("白雉", 650, 1958551, 1960259),
|
|
@@ -502,5 +502,5 @@ module Wareki
|
|
|
502
502
|
Era.new("昭和", 1926, 2424875, 2447534),
|
|
503
503
|
Era.new("平成", 1989, 2447535, 2458604),
|
|
504
504
|
Era.new("令和", 2019, 2458605, DAY_MAX),
|
|
505
|
-
].freeze
|
|
505
|
+
].each(&:freeze).freeze
|
|
506
506
|
end
|
data/lib/wareki/std_ext.rb
CHANGED
|
@@ -5,8 +5,26 @@ require 'wareki/date'
|
|
|
5
5
|
module Wareki
|
|
6
6
|
# :nodoc:
|
|
7
7
|
module StdExt
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
def wareki_directive?(format)
|
|
11
|
+
!!(format.to_str =~ Wareki::Date::FORMAT_EXPANSION_REGEX)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def wareki_time_directive?(format)
|
|
15
|
+
!!(format.to_str =~ Wareki::Utils::TIME_FORMAT_EXPANSION_REGEX)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# %JT 時刻トークンと %J 日付トークンの両方を展開した文字列を返す
|
|
19
|
+
def expand_all_wareki_formats(format, datetime)
|
|
20
|
+
ret = format
|
|
21
|
+
ret = Wareki::Utils.expand_time_format(ret, datetime) if wareki_time_directive?(ret)
|
|
22
|
+
ret = datetime.to_wareki_date.expand_wareki_format(ret) if wareki_directive?(ret)
|
|
23
|
+
ret
|
|
24
|
+
end
|
|
8
25
|
end
|
|
9
26
|
end
|
|
27
|
+
|
|
10
28
|
# :nodoc:
|
|
11
29
|
class Date
|
|
12
30
|
JAPAN = Wareki::GREGORIAN_START
|
|
@@ -17,23 +35,29 @@ class Date
|
|
|
17
35
|
|
|
18
36
|
alias _wareki_strftime_orig strftime
|
|
19
37
|
def strftime(format = '%F')
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
_wareki_strftime_orig(format)
|
|
24
|
-
end
|
|
38
|
+
return _wareki_strftime_orig(format) unless Wareki::StdExt.wareki_directive?(format)
|
|
39
|
+
|
|
40
|
+
_wareki_strftime_orig(to_wareki_date.expand_wareki_format(format))
|
|
25
41
|
end
|
|
26
42
|
|
|
27
43
|
class << self
|
|
28
44
|
alias _wareki_parse_orig parse
|
|
29
45
|
def parse(str = '-4712-01-01', comp = true, start = ::Date::ITALY)
|
|
46
|
+
str = Wareki::Utils.normalize_time(str)
|
|
47
|
+
str.to_s =~ Wareki::PARSE_QUICK_FILTER or
|
|
48
|
+
return ::Date._wareki_parse_orig(str, comp, start)
|
|
30
49
|
Wareki::Date.parse(str).to_date(start)
|
|
50
|
+
rescue Wareki::InvalidDate
|
|
51
|
+
raise
|
|
31
52
|
rescue ArgumentError, Wareki::UnsupportedDateRange
|
|
32
53
|
::Date._wareki_parse_orig(str, comp, start)
|
|
33
54
|
end
|
|
34
55
|
|
|
35
56
|
alias _wareki__parse_orig _parse
|
|
36
57
|
def _parse(str, comp = true)
|
|
58
|
+
str = Wareki::Utils.normalize_time(str)
|
|
59
|
+
str.to_s =~ Wareki::PARSE_QUICK_FILTER or
|
|
60
|
+
return ::Date._wareki__parse_orig(str, comp)
|
|
37
61
|
di = Wareki::Date._parse(str)
|
|
38
62
|
wdate = Wareki::Date.new(di[:era], di[:year], di[:month], di[:day], di[:is_leap])
|
|
39
63
|
rescue ArgumentError, Wareki::UnsupportedDateRange
|
|
@@ -43,3 +67,23 @@ class Date
|
|
|
43
67
|
end
|
|
44
68
|
end
|
|
45
69
|
end
|
|
70
|
+
|
|
71
|
+
# :nodoc:
|
|
72
|
+
class DateTime
|
|
73
|
+
alias _wareki_strftime_orig strftime
|
|
74
|
+
def strftime(format = '%FT%T%:z')
|
|
75
|
+
_wareki_strftime_orig(Wareki::StdExt.expand_all_wareki_formats(format, self))
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# :nodoc:
|
|
80
|
+
class Time
|
|
81
|
+
def to_wareki_date
|
|
82
|
+
Wareki::Date.jd(to_date.jd)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
alias _wareki_strftime_orig strftime
|
|
86
|
+
def strftime(format)
|
|
87
|
+
_wareki_strftime_orig(Wareki::StdExt.expand_all_wareki_formats(format, self))
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/wareki/utils.rb
CHANGED
|
@@ -5,6 +5,9 @@ require 'ya_kansuji'
|
|
|
5
5
|
module Wareki
|
|
6
6
|
# Static utility methods.
|
|
7
7
|
module Utils
|
|
8
|
+
TIME_FORMAT_DIRECTIVE_REGEX = /%J(-|[_0]{0,2}[0-9]*|)(T(?:[fF]|[HMS]k?))/.freeze
|
|
9
|
+
TIME_FORMAT_EXPANSION_REGEX = /(?<!%)(?:%%)*\K#{TIME_FORMAT_DIRECTIVE_REGEX}/.freeze
|
|
10
|
+
|
|
8
11
|
module_function
|
|
9
12
|
|
|
10
13
|
def last_day_of_month(year, month, is_leap)
|
|
@@ -16,25 +19,47 @@ module Wareki
|
|
|
16
19
|
end
|
|
17
20
|
|
|
18
21
|
def _last_day_of_month_gregorian(year, month)
|
|
19
|
-
|
|
20
|
-
tmp_m = month
|
|
21
|
-
if month == 12
|
|
22
|
-
tmp_y += 1
|
|
23
|
-
tmp_m = 1
|
|
24
|
-
else
|
|
25
|
-
tmp_m += 1
|
|
26
|
-
end
|
|
27
|
-
(::Date.new(tmp_y, tmp_m, 1, ::Date::GREGORIAN) - 1).day
|
|
22
|
+
::Date.new(year, month, -1, ::Date::GREGORIAN).day
|
|
28
23
|
end
|
|
29
24
|
|
|
30
25
|
def _last_day_of_month_from_defs(year, month, is_leap)
|
|
31
26
|
yobj = YEAR_BY_NUM[year] or
|
|
32
|
-
raise UnsupportedDateRange, "Cannot find year #{
|
|
27
|
+
raise UnsupportedDateRange, "Cannot find year #{year}"
|
|
33
28
|
month_idx = month - 1
|
|
34
|
-
month_idx += 1 if is_leap || yobj.leap_month && yobj.leap_month < month
|
|
29
|
+
month_idx += 1 if is_leap || (yobj.leap_month && yobj.leap_month < month)
|
|
35
30
|
yobj.month_days[month_idx]
|
|
36
31
|
end
|
|
37
32
|
|
|
33
|
+
def era_year_to_civil(era_name, era_year)
|
|
34
|
+
era_name = era_name.to_s
|
|
35
|
+
return era_year if ['', '西暦'].include?(era_name)
|
|
36
|
+
return -era_year if era_name == '紀元前'
|
|
37
|
+
return era_year + IMPERIAL_START_YEAR if IMPERIAL_ERA_NAMES.include?(era_name)
|
|
38
|
+
|
|
39
|
+
era = ERA_BY_NAME[era_name] or
|
|
40
|
+
raise ArgumentError, "Undefined era '#{era_name}'"
|
|
41
|
+
era.year + era_year - 1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def civil_to_era_year(era_name, year)
|
|
45
|
+
era_name = era_name.to_s
|
|
46
|
+
return year if ['', '西暦'].include?(era_name)
|
|
47
|
+
return -year if era_name == '紀元前'
|
|
48
|
+
return year - IMPERIAL_START_YEAR if IMPERIAL_ERA_NAMES.include?(era_name)
|
|
49
|
+
|
|
50
|
+
era = ERA_BY_NAME[era_name] or
|
|
51
|
+
raise ArgumentError, "Undefined era '#{era_name}'"
|
|
52
|
+
year - era.year + 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def last_day_of_era_month(era_name, civil_year, month, is_leap)
|
|
56
|
+
if WESTERN_ERA_NAMES.include?(era_name.to_s)
|
|
57
|
+
::Date.new(civil_year, month, -1, ::Date::ITALY).day
|
|
58
|
+
else
|
|
59
|
+
last_day_of_month(civil_year, month, is_leap)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
38
63
|
def alt_month_name_to_i(name)
|
|
39
64
|
i = ALT_MONTH_NAME.index(name) or return false
|
|
40
65
|
i + 1
|
|
@@ -85,6 +110,7 @@ module Wareki
|
|
|
85
110
|
|
|
86
111
|
def find_year(d)
|
|
87
112
|
jd = _to_jd(d)
|
|
113
|
+
jd < YEAR_DEFS.first.start and return nil
|
|
88
114
|
YEAR_DEFS.bsearch { |y| y.end >= jd }
|
|
89
115
|
end
|
|
90
116
|
|
|
@@ -111,6 +137,59 @@ module Wareki
|
|
|
111
137
|
end
|
|
112
138
|
end
|
|
113
139
|
|
|
140
|
+
# 日本語の時刻表記 (漢数字・全角数字の時分秒、午前/午後、半、正午) を
|
|
141
|
+
# 等価な "HH:MM(:SS)" 表記へ置換する。値の範囲チェックは行わず、
|
|
142
|
+
# 妥当性判断は Ruby 標準パーサに委ねる (二十五時 -> "25:00")。
|
|
143
|
+
def normalize_time(str)
|
|
144
|
+
str.to_s =~ TIME_PARSE_QUICK_FILTER or return str
|
|
145
|
+
str.to_s.sub(TIME_REGEX) { _time_match_to_s(Regexp.last_match) }
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def _time_match_to_s(match)
|
|
149
|
+
return '12:00' if match[:noon]
|
|
150
|
+
|
|
151
|
+
hour = k2i(match[:hour])
|
|
152
|
+
hour += 12 if match[:ampm] == '午後' && hour < 12
|
|
153
|
+
min = 0
|
|
154
|
+
min = 30 if match[:half]
|
|
155
|
+
min = k2i(match[:min]) if match[:min]
|
|
156
|
+
return Kernel.format('%<hour>02d:%<min>02d', hour: hour, min: min) unless match[:sec]
|
|
157
|
+
|
|
158
|
+
Kernel.format('%<hour>02d:%<min>02d:%<sec>02d', hour: hour, min: min, sec: k2i(match[:sec]))
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def number_format(opt)
|
|
162
|
+
case opt
|
|
163
|
+
when '', '0', '_0' then '%02d'
|
|
164
|
+
when '-' then '%d'
|
|
165
|
+
when /_\Z/ then '%2d'
|
|
166
|
+
when /0?_/ then "%#{opt.sub(/0?_/, '')}d"
|
|
167
|
+
when /_?0/ then "%#{opt.sub(/_?0/, '0')}d"
|
|
168
|
+
else "%0#{opt}d"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def expand_time_format(format_str, time)
|
|
173
|
+
format_str.to_str.gsub(TIME_FORMAT_EXPANSION_REGEX) { _format_time_directive($2, $1, time) || $& }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def _format_time_directive(key, opt, time)
|
|
177
|
+
case key.to_sym
|
|
178
|
+
when :Tf
|
|
179
|
+
nf = number_format(opt)
|
|
180
|
+
Kernel.format("#{nf}時#{nf}分#{nf}秒", time.hour, time.min, time.sec)
|
|
181
|
+
when :TF
|
|
182
|
+
"#{YaKansuji.to_kan(time.hour, :simple)}時#{YaKansuji.to_kan(time.min, :simple)}分" \
|
|
183
|
+
"#{YaKansuji.to_kan(time.sec, :simple)}秒"
|
|
184
|
+
when :TH then i2z(time.hour)
|
|
185
|
+
when :THk then YaKansuji.to_kan(time.hour, :simple)
|
|
186
|
+
when :TM then i2z(time.min)
|
|
187
|
+
when :TMk then YaKansuji.to_kan(time.min, :simple)
|
|
188
|
+
when :TS then i2z(time.sec)
|
|
189
|
+
when :TSk then YaKansuji.to_kan(time.sec, :simple)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
114
193
|
# DEPRECATED
|
|
115
194
|
def kan_to_i(*args)
|
|
116
195
|
warn '[DEPRECATED] Wareki::Utils.kan_to_i: Please use ya_kansuji gem to handle kansuji'
|
|
@@ -120,7 +199,7 @@ module Wareki
|
|
|
120
199
|
# DEPRECATED
|
|
121
200
|
def i_to_kan(*args)
|
|
122
201
|
warn '[DEPRECATED] Wareki::Utils.i_to_kan: Please use ya_kansuji gem to handle kansuji'
|
|
123
|
-
|
|
202
|
+
YaKansuji.to_kan(*args)
|
|
124
203
|
end
|
|
125
204
|
end
|
|
126
205
|
end
|
data/lib/wareki/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wareki
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tatsuki Sugiura
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-07-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ya_kansuji
|
|
@@ -30,48 +30,6 @@ dependencies:
|
|
|
30
30
|
- - "<"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: 2.0.0
|
|
33
|
-
- !ruby/object:Gem::Dependency
|
|
34
|
-
name: bundler
|
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '1.9'
|
|
40
|
-
type: :development
|
|
41
|
-
prerelease: false
|
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '1.9'
|
|
47
|
-
- !ruby/object:Gem::Dependency
|
|
48
|
-
name: rake
|
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - ">="
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '10.0'
|
|
54
|
-
type: :development
|
|
55
|
-
prerelease: false
|
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '10.0'
|
|
61
|
-
- !ruby/object:Gem::Dependency
|
|
62
|
-
name: rspec
|
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0'
|
|
68
|
-
type: :development
|
|
69
|
-
prerelease: false
|
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - ">="
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '0'
|
|
75
33
|
description: |
|
|
76
34
|
Pure ruby library of Wareki (Japanese calendar date) that supports string parsing,
|
|
77
35
|
formatting, and bi-directional convertion with standard Date class.
|
|
@@ -95,9 +53,10 @@ files:
|
|
|
95
53
|
- lib/wareki/version.rb
|
|
96
54
|
homepage: https://github.com/sugi/wareki
|
|
97
55
|
licenses:
|
|
98
|
-
- BSD
|
|
99
|
-
metadata:
|
|
100
|
-
|
|
56
|
+
- BSD-2-Clause
|
|
57
|
+
metadata:
|
|
58
|
+
rubygems_mfa_required: 'true'
|
|
59
|
+
post_install_message:
|
|
101
60
|
rdoc_options: []
|
|
102
61
|
require_paths:
|
|
103
62
|
- lib
|
|
@@ -112,9 +71,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
112
71
|
- !ruby/object:Gem::Version
|
|
113
72
|
version: '0'
|
|
114
73
|
requirements: []
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
signing_key:
|
|
74
|
+
rubygems_version: 3.1.6
|
|
75
|
+
signing_key:
|
|
118
76
|
specification_version: 4
|
|
119
77
|
summary: Pure ruby library of Wareki (Japanese calendar date)
|
|
120
78
|
test_files: []
|