wareki 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/LICENSE +24 -0
- data/README.rdoc +103 -0
- data/Rakefile +6 -0
- data/lib/wareki/calendar_def.rb +1433 -0
- data/lib/wareki/common.rb +41 -0
- data/lib/wareki/core_ext.rb +33 -0
- data/lib/wareki/date.rb +206 -0
- data/lib/wareki/era_def.rb +502 -0
- data/lib/wareki/utils.rb +173 -0
- data/lib/wareki/version.rb +3 -0
- data/lib/wareki.rb +2 -0
- data/wareki.gemspec +25 -0
- metadata +101 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'wareki/calendar_def'
|
3
|
+
require 'wareki/era_def'
|
4
|
+
require 'date'
|
5
|
+
module Wareki
|
6
|
+
GREGORIAN_START = 2405160 # Date.new(1873, 1, 1, Date::GREGORIAN).jd
|
7
|
+
GREGORIAN_START_YEAR = 1873
|
8
|
+
IMPERIAL_START = 1480041 # Date.new(-660, 2, 11, Date::GREGORIAN).jd
|
9
|
+
IMPERIAL_START_YEAR = -660
|
10
|
+
DATE_INFINITY = ::Date.new(2**(0.size * 8 -2) -1, 12, 31) # Use max Fixnum as year.
|
11
|
+
YEAR_BY_NUM = Hash[*YEAR_DEFS.map{|y| [y.year, y]}.flatten].freeze
|
12
|
+
ERA_BY_NAME = Hash[*(ERA_NORTH_DEFS + ERA_DEFS).map {|g| [g.name, g]}.flatten]
|
13
|
+
ERA_BY_NAME['皇紀'] = ERA_BY_NAME['神武天皇即位紀元'] = Era.new('皇紀', -660, 1480041, DATE_INFINITY.jd)
|
14
|
+
ERA_BY_NAME.keys.each do |era_name|
|
15
|
+
alt_era_name = era_name.tr("宝霊神応暦祥寿斎観寛徳禄万福禎国亀", "寳靈神應曆祥壽斉觀寬德祿萬福禎國龜")
|
16
|
+
alt_era_name == era_name and next
|
17
|
+
ERA_BY_NAME[alt_era_name] = ERA_BY_NAME[era_name]
|
18
|
+
end
|
19
|
+
ERA_BY_NAME.freeze
|
20
|
+
NUM_CHARS = "零〇一二三四五六七八九十卄廿卅丗卌肆百皕千万億兆01234567890123456789"
|
21
|
+
ALT_MONTH_NAME = %w(睦月 如月 弥生 卯月 皐月 水無月 文月 葉月 長月 神無月 霜月 師走).freeze
|
22
|
+
REGEX = %r{^
|
23
|
+
(?<era_name>西暦|#{ERA_BY_NAME.keys.join('|')})?
|
24
|
+
(?:(?<year>[元#{NUM_CHARS}]+)年)?
|
25
|
+
(?:(?<is_leap>閏|潤|うるう)?
|
26
|
+
(?:(?<month>[正#{NUM_CHARS}]+)月 |
|
27
|
+
(?<alt_month>#{ALT_MONTH_NAME.join('|')})))?
|
28
|
+
(?:(?<day>[元朔晦#{NUM_CHARS}]+)日)?
|
29
|
+
$}x
|
30
|
+
|
31
|
+
class UnsupportedDateRange < StandardError; end
|
32
|
+
|
33
|
+
module_function
|
34
|
+
def parse_to_date(str, start = ::Date::ITALY)
|
35
|
+
begin
|
36
|
+
Date.parse(str).to_date(start)
|
37
|
+
rescue ArgumentError => e
|
38
|
+
::Date.parse(str, true, start)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'wareki/date'
|
3
|
+
module Wareki
|
4
|
+
module CoreExt
|
5
|
+
end
|
6
|
+
end
|
7
|
+
class Date
|
8
|
+
JAPAN = Wareki::GREGORIAN_START
|
9
|
+
|
10
|
+
def to_wareki_date
|
11
|
+
Wareki::Date.jd(self.jd)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :_wareki_strftime_orig, :strftime
|
15
|
+
def strftime(format = "%F")
|
16
|
+
if format.index("%J")
|
17
|
+
to_wareki_date.strftime(format)
|
18
|
+
else
|
19
|
+
_wareki_strftime_orig(format)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
alias_method :_wareki_parse_orig, :parse
|
25
|
+
def parse(str, comp = true, start = ::Date::ITALY)
|
26
|
+
begin
|
27
|
+
Wareki::Date.parse(str).to_date(start)
|
28
|
+
rescue => e
|
29
|
+
::Date._wareki_parse_orig(str, comp, start)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/wareki/date.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'date'
|
3
|
+
require 'wareki/common'
|
4
|
+
require 'wareki/utils'
|
5
|
+
module Wareki
|
6
|
+
|
7
|
+
class Date
|
8
|
+
attr_reader :jd
|
9
|
+
attr_accessor :year, :month, :day, :era_year, :era_name
|
10
|
+
|
11
|
+
def self._parse(str)
|
12
|
+
match = REGEX.match(str.to_s.gsub(/[[:space:]]/, ''))
|
13
|
+
if !match || !match[:year]
|
14
|
+
raise ArgumentError, "Invaild Date: #{str}"
|
15
|
+
end
|
16
|
+
era = match[:era_name]
|
17
|
+
year = Utils.kan_to_i(match[:year])
|
18
|
+
month = 1
|
19
|
+
day = 1
|
20
|
+
|
21
|
+
if era.to_s != "" && !ERA_BY_NAME[era]
|
22
|
+
raise ArgumentError, "Date parse failed: Invalid era name '#{match[:era_name]}'"
|
23
|
+
end
|
24
|
+
|
25
|
+
if match[:month]
|
26
|
+
month = Utils.kan_to_i(match[:month])
|
27
|
+
elsif match[:alt_month]
|
28
|
+
month = Utils.alt_month_name_to_i(match[:alt_month])
|
29
|
+
end
|
30
|
+
|
31
|
+
month > 12 || month < 0 and
|
32
|
+
raise ArgumentError, "Invalid month: #{str}"
|
33
|
+
|
34
|
+
if match[:day]
|
35
|
+
if match[:day] == "晦"
|
36
|
+
day = Utils.last_day_of_month(ERA_BY_NAME[era].year + year -1, month, match[:is_leap])
|
37
|
+
else
|
38
|
+
day = Utils.kan_to_i(match[:day])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
if (era == "明治" && year == 5 ||
|
43
|
+
era.to_s == "" && year == GREGORIAN_START_YEAR - 1 ||
|
44
|
+
(era == "皇紀" || era == "神武天皇即位紀元") &&
|
45
|
+
year == GREGORIAN_START_YEAR - IMPERIAL_START_YEAR - 1) &&
|
46
|
+
month == 12 && day > 2
|
47
|
+
raise ArgumentError, "Invaild Date: #{str}"
|
48
|
+
end
|
49
|
+
|
50
|
+
{era: era, year: year, month: month, day: day, is_leap: !!match[:is_leap]}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.parse(str)
|
54
|
+
di = _parse(str)
|
55
|
+
new(di[:era], di[:year], di[:month], di[:day], di[:is_leap])
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.jd(d)
|
59
|
+
era = Utils.find_era(d)
|
60
|
+
era or raise UnsupportedDateRange, "Cannot find era for date #{d.inspect}"
|
61
|
+
year, month, day, is_leap = Utils.find_date_ary(d)
|
62
|
+
obj = new(era.name, year - era.year + 1, month, day, is_leap)
|
63
|
+
obj.__set_jd(d)
|
64
|
+
obj
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.date(date)
|
68
|
+
jd(date.jd)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.imperial(year, month = 1, day = 1, is_leap_month = false)
|
72
|
+
new("皇紀", year, month, day, is_leap_month)
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(era_name, era_year, month = 1, day = 1, is_leap_month = false)
|
76
|
+
if era_name.to_s != "" && era_name != "西暦" && !ERA_BY_NAME[era_name]
|
77
|
+
raise ArgumentError, "Undefined era '#{era_name}'"
|
78
|
+
end
|
79
|
+
@month = month
|
80
|
+
@day = day
|
81
|
+
@is_leap_month = is_leap_month
|
82
|
+
@era_name = era_name
|
83
|
+
@era_year = era_year
|
84
|
+
if era_name.to_s == ""
|
85
|
+
@year = @era_year
|
86
|
+
elsif era_name == "皇紀" || era_name == "神武天皇即位紀元"
|
87
|
+
@year = era_year + IMPERIAL_START_YEAR
|
88
|
+
else
|
89
|
+
@year = ERA_BY_NAME[era_name].year + era_year - 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def imperial_year
|
94
|
+
@year - IMPERIAL_START_YEAR
|
95
|
+
end
|
96
|
+
|
97
|
+
def imperial_year=(v)
|
98
|
+
@year = v - IMPERIAL_START_YEAR
|
99
|
+
end
|
100
|
+
|
101
|
+
def leap_month?
|
102
|
+
!!@is_leap_month
|
103
|
+
end
|
104
|
+
|
105
|
+
def leap_month=(v)
|
106
|
+
@is_leap_month = v
|
107
|
+
end
|
108
|
+
|
109
|
+
def __set_jd(v)
|
110
|
+
@jd = v
|
111
|
+
end
|
112
|
+
|
113
|
+
def month_index
|
114
|
+
if @era_name == "西暦" || @year >= GREGORIAN_START_YEAR
|
115
|
+
return month -1
|
116
|
+
end
|
117
|
+
|
118
|
+
yobj = YEAR_BY_NUM[@year] or
|
119
|
+
raise UnsupportedDateRange, "Cannot get year info of #{self.inspect}"
|
120
|
+
idx = month - 1
|
121
|
+
if leap_month? || yobj.leap_month && month > yobj.leap_month
|
122
|
+
idx += 1
|
123
|
+
end
|
124
|
+
idx
|
125
|
+
end
|
126
|
+
|
127
|
+
def jd
|
128
|
+
@jd and return @jd
|
129
|
+
|
130
|
+
if @era_name == "西暦"
|
131
|
+
return @jd = ::Date.new(@year, month, day, ::Date::ITALY).jd
|
132
|
+
elsif @year >= GREGORIAN_START_YEAR
|
133
|
+
return @jd = ::Date.new(@year, month, day, ::Date::GREGORIAN).jd
|
134
|
+
end
|
135
|
+
|
136
|
+
yobj = YEAR_BY_NUM[@year] or
|
137
|
+
raise UnsupportedDateRange, "Cannot convert to jd #{self.inspect}"
|
138
|
+
@jd = yobj.month_starts[month_index] + day - 1
|
139
|
+
end
|
140
|
+
|
141
|
+
def to_date(start = ::Date::ITALY)
|
142
|
+
::Date.jd(jd, start)
|
143
|
+
end
|
144
|
+
|
145
|
+
def strftime(format_str = "%JF")
|
146
|
+
ret = format_str.to_str.gsub(/%J([fFyYegGoOiImMsSlLdD][kK]?)/) { format($1) || $& }
|
147
|
+
ret.index("%") or return ret
|
148
|
+
d = to_date
|
149
|
+
d.respond_to?(:_wareki_strftime_orig) ? d._wareki_strftime_orig(ret) : d.strftime(ret)
|
150
|
+
end
|
151
|
+
|
152
|
+
def format(key)
|
153
|
+
case key.to_sym
|
154
|
+
when :e; era_name
|
155
|
+
when :g; era_name.to_s == "" ? '' : era_year
|
156
|
+
when :G; era_name.to_s == "" ? '' : Utils.i_to_zen(era_year)
|
157
|
+
when :Gk; era_name.to_s == "" ? '' : Utils.i_to_kan(era_year)
|
158
|
+
when :GK
|
159
|
+
if era_name.to_s == ""
|
160
|
+
''
|
161
|
+
elsif era_year == 1
|
162
|
+
"元"
|
163
|
+
else
|
164
|
+
Utils.i_to_kan(era_year)
|
165
|
+
end
|
166
|
+
when :o; year
|
167
|
+
when :O; Utils.i_to_zen(year)
|
168
|
+
when :Ok; Utils.i_to_kan(year)
|
169
|
+
when :i; imperial_year
|
170
|
+
when :I; Utils.i_to_zen(imperial_year)
|
171
|
+
when :Ik; Utils.i_to_kan(imperial_year)
|
172
|
+
when :s; month
|
173
|
+
when :S; Utils.i_to_zen(month)
|
174
|
+
when :Sk; Utils.i_to_kan(month)
|
175
|
+
when :SK; ALT_MONTH_NAME[month-1]
|
176
|
+
when :l; leap_month? ? "'" : ""
|
177
|
+
when :L; leap_month? ? "’" : ""
|
178
|
+
when :Lk; leap_month? ? "閏" : ""
|
179
|
+
when :d; day
|
180
|
+
when :D; Utils.i_to_zen(day)
|
181
|
+
when :Dk; Utils.i_to_kan(day)
|
182
|
+
when :DK
|
183
|
+
if month == 1 && !leap_month? && day == 1
|
184
|
+
"元"
|
185
|
+
elsif day == 1
|
186
|
+
"朔"
|
187
|
+
elsif day == Utils.last_day_of_month(year, month, leap_month?)
|
188
|
+
"晦"
|
189
|
+
else
|
190
|
+
Utils.i_to_kan(day)
|
191
|
+
end
|
192
|
+
when :m; "#{format(:s)}#{format(:l)}"
|
193
|
+
when :M; "#{format(:Lk)}#{format(:S)}"
|
194
|
+
when :Mk; "#{format(:Lk)}#{format(:Sk)}"
|
195
|
+
when :y; "#{format(:e)}#{format(:g)}"
|
196
|
+
when :Y; "#{format(:e)}#{format(:G)}"
|
197
|
+
when :Yk; "#{format(:e)}#{format(:Gk)}"
|
198
|
+
when :YK; "#{format(:e)}#{format(:GK)}"
|
199
|
+
when :f; "#{format(:e)}#{format(:g)}年#{format(:s)}#{format(:l)}月#{format(:d)}日"
|
200
|
+
when :F; "#{format(:e)}#{format(:GK)}年#{format(:Lk)}#{format(:Sk)}月#{format(:Dk)}日"
|
201
|
+
else
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|