wareki 0.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.
@@ -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
@@ -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