wareki 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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