when_exe 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +171 -0
  3. data/lib/when_exe.rb +78 -47
  4. data/lib/when_exe/basictypes.rb +752 -747
  5. data/lib/when_exe/calendarnote.rb +805 -801
  6. data/lib/when_exe/calendartypes.rb +1583 -1531
  7. data/lib/when_exe/coordinates.rb +16 -15
  8. data/lib/when_exe/core/duration.rb +114 -110
  9. data/lib/when_exe/core/extension.rb +504 -504
  10. data/lib/when_exe/ephemeris.rb +1917 -1913
  11. data/lib/when_exe/ephemeris/moon.rb +333 -333
  12. data/lib/when_exe/ephemeris/notes.rb +389 -387
  13. data/lib/when_exe/ephemeris/planets.rb +585 -585
  14. data/lib/when_exe/ephemeris/sun.rb +214 -214
  15. data/lib/when_exe/googlecalendar.rb +144 -140
  16. data/lib/when_exe/icalendar.rb +1636 -1636
  17. data/lib/when_exe/inspect.rb +46 -22
  18. data/lib/when_exe/locales/akt.rb +176 -176
  19. data/lib/when_exe/locales/encoding_conversion.rb +134 -126
  20. data/lib/when_exe/locales/iast.rb +90 -90
  21. data/lib/when_exe/locales/locale.rb +750 -746
  22. data/lib/when_exe/locales/transliteration_table.rb +62 -62
  23. data/lib/when_exe/mini_application.rb +307 -305
  24. data/lib/when_exe/parts/enumerator.rb +2 -2
  25. data/lib/when_exe/parts/geometric_complex.rb +397 -397
  26. data/lib/when_exe/parts/method_cash.rb +224 -224
  27. data/lib/when_exe/parts/resource.rb +1069 -1071
  28. data/lib/when_exe/parts/timezone.rb +240 -230
  29. data/lib/when_exe/region/armenian.rb +56 -56
  30. data/lib/when_exe/region/babylonian.rb +405 -0
  31. data/lib/when_exe/region/bahai.rb +146 -146
  32. data/lib/when_exe/region/balinese.rb +622 -622
  33. data/lib/when_exe/region/chinese.rb +95 -25
  34. data/lib/when_exe/region/chinese/calendars.rb +1016 -1016
  35. data/lib/when_exe/region/chinese/epochs.rb +1 -1
  36. data/lib/when_exe/region/chinese/twins.rb +803 -795
  37. data/lib/when_exe/region/christian.rb +824 -824
  38. data/lib/when_exe/region/coptic.rb +106 -87
  39. data/lib/when_exe/region/discordian.rb +225 -225
  40. data/lib/when_exe/region/far_east.rb +188 -188
  41. data/lib/when_exe/region/french.rb +56 -56
  42. data/lib/when_exe/region/geologicalage.rb +639 -639
  43. data/lib/when_exe/region/goddess.rb +58 -58
  44. data/lib/when_exe/region/indian.rb +1254 -1251
  45. data/lib/when_exe/region/iranian.rb +8 -8
  46. data/lib/when_exe/region/islamic.rb +3 -3
  47. data/lib/when_exe/region/japanese.rb +93 -99
  48. data/lib/when_exe/region/japanese/calendars.rb +396 -397
  49. data/lib/when_exe/region/japanese/epochs.rb +26 -26
  50. data/lib/when_exe/region/japanese/nihon_shoki.rb +71 -71
  51. data/lib/when_exe/region/japanese/notes.rb +1383 -1386
  52. data/lib/when_exe/region/japanese/residues.rb +1306 -1306
  53. data/lib/when_exe/region/japanese/twins.rb +225 -225
  54. data/lib/when_exe/region/japanese/weeks.rb +112 -0
  55. data/lib/when_exe/region/javanese.rb +230 -230
  56. data/lib/when_exe/region/jewish.rb +126 -126
  57. data/lib/when_exe/region/korean.rb +378 -378
  58. data/lib/when_exe/region/m17n.rb +114 -113
  59. data/lib/when_exe/region/martian.rb +258 -255
  60. data/lib/when_exe/region/mayan.rb +32 -32
  61. data/lib/when_exe/region/residue.rb +89 -89
  62. data/lib/when_exe/region/roman.rb +36 -24
  63. data/lib/when_exe/region/ryukyu.rb +97 -97
  64. data/lib/when_exe/region/shire.rb +240 -240
  65. data/lib/when_exe/region/soviet.rb +209 -0
  66. data/lib/when_exe/region/symmetry.rb +50 -50
  67. data/lib/when_exe/region/thai.rb +336 -335
  68. data/lib/when_exe/region/tibetan.rb +316 -315
  69. data/lib/when_exe/region/vietnamese.rb +440 -439
  70. data/lib/when_exe/region/weekdate.rb +80 -80
  71. data/lib/when_exe/region/world.rb +175 -175
  72. data/lib/when_exe/region/yerm.rb +14 -14
  73. data/lib/when_exe/region/zoroastrian.rb +203 -203
  74. data/lib/when_exe/timestandard.rb +707 -681
  75. data/lib/when_exe/tmduration.rb +338 -330
  76. data/lib/when_exe/tmobjects.rb +1346 -1325
  77. data/lib/when_exe/tmposition.rb +2115 -2072
  78. data/lib/when_exe/tmreference.rb +1693 -1669
  79. data/lib/when_exe/version.rb +1 -1
  80. data/link_to_online_documents +1 -1
  81. data/test/examples/JapanHolidaysRFC6350.ics +1 -1
  82. data/test/test.rb +67 -61
  83. data/test/test/basictypes.rb +409 -409
  84. data/test/test/calendarnote.rb +86 -69
  85. data/test/test/calendartypes.rb +97 -97
  86. data/test/test/coordinates.rb +396 -396
  87. data/test/test/ephemeris.rb +83 -74
  88. data/test/test/ephemeris/moon.rb +14 -14
  89. data/test/test/ephemeris/planets.rb +14 -14
  90. data/test/test/ephemeris/sun.rb +14 -14
  91. data/test/test/googlecalendar.rb +194 -176
  92. data/test/test/icalendar.rb +867 -858
  93. data/test/test/inspect.rb +117 -117
  94. data/test/test/parts.rb +487 -487
  95. data/test/test/region/balinese.rb +34 -0
  96. data/test/test/region/chinese.rb +218 -206
  97. data/test/test/region/christian.rb +245 -245
  98. data/test/test/region/coptic.rb +27 -27
  99. data/test/test/region/french.rb +33 -33
  100. data/test/test/region/geologicalage.rb +17 -17
  101. data/test/test/region/indian.rb +57 -57
  102. data/test/test/region/iran.rb +54 -54
  103. data/test/test/region/islamic.rb +18 -18
  104. data/test/test/region/japanese.rb +237 -219
  105. data/test/test/region/jewish.rb +61 -61
  106. data/test/test/region/m17n.rb +184 -184
  107. data/test/test/region/mayan.rb +195 -195
  108. data/test/test/region/residue.rb +147 -139
  109. data/test/test/region/thai.rb +116 -116
  110. data/test/test/region/tibetan.rb +30 -30
  111. data/test/test/region/vietnamese.rb +102 -102
  112. data/test/test/region/yerm.rb +146 -146
  113. data/test/test/timestandard.rb +81 -81
  114. data/test/test/tmobjects.rb +328 -328
  115. data/test/test/tmposition.rb +397 -284
  116. data/test/test/tmreference.rb +157 -157
  117. metadata +13 -10
@@ -1,824 +1,824 @@
1
- # -*- coding: utf-8 -*-
2
- =begin
3
- Copyright (C) 2011-2014 Takashi SUGA
4
-
5
- You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
- =end
7
-
8
- module When
9
-
10
- class BasicTypes::M17n
11
-
12
- Christian = [self, [
13
- "locale:[=en:, ja=ja:, alias]",
14
- "names:[Christian=]",
15
- "[Julian=en:Julian_calendar, ユリウス暦 ]",
16
- "[Gregorian=en:Gregorian_calendar, グレゴリオ暦 ]",
17
- "[RevisedJulian=en:Revised_Julian_calendar, 修正ユリウス暦]",
18
- "[Swedish=en:Swedish_calendar, スウェーデン暦]",
19
- "[Civil in the West=en:Civil_calendar, 西暦, *alias:Civil]"
20
- ]]
21
- end
22
-
23
- class TM::CalendarEra
24
- # Anno Mundi Era
25
- Byzantine = [self, [
26
- "locale:[=en:, ja=ja:, alias]",
27
- "period:[Byzantine=en:Byzantine_calendar, ビザンティン暦=ja:%%<世界創造紀元>]",
28
- ["[AM=en:Anno_Mundi, 世界創造紀元, alias:Anno_Mundi]6497.9.1",
29
- "Calendar Epoch", "989-09-01^Julian?border=[-1,9,1]&note=Roman", "1453=5-29"]
30
- ]]
31
- end
32
-
33
- module CalendarTypes
34
-
35
- #
36
- # Christian Base Calendar
37
- #
38
- class Christian < When::TM::Calendar
39
-
40
- # デフォルトの改暦日付(ユリウス通日)
41
- #
42
- # @private
43
- DefaultReformDate = 2299161 # 1582-10-15
44
-
45
- # @private
46
- #
47
- # ::Date オブジェクトに対応する暦法名
48
- # (require 'Date' されていることの保証は呼び出し側)
49
- #
50
- def self._default_start(date)
51
- case date.start
52
- when ::Date::JULIAN ; 'Julian'
53
- when ::Date::GREGORIAN ; 'Gregorian'
54
- else ; "Civil?reform_jdn=#{date.start}"
55
- end
56
- end
57
-
58
- # 年月日 -> 通日
59
- #
60
- # @see When::CalendarTypes::TableBased#_coordinates_to_number
61
- #
62
- def _coordinates_to_number(y,m,d)
63
- m = (+m + 10) % 12
64
- y = +y + 4716 - m / 10
65
- a = (1461*y.to_i ).div(4)
66
- b = ( 153*m.to_i + 2).div(5)
67
- return a + b + (+d) - 1401
68
- end
69
-
70
- # 通日 - > 年月日
71
- #
72
- # @see When::CalendarTypes::TableBased#_number_to_coordinates
73
- #
74
- def _number_to_coordinates(jdn)
75
- j = jdn.to_i + 1401
76
- y, t = (4*j + 3).divmod(1461)
77
- t = t.div(4)
78
- m, d = (5*t + 2).divmod(153)
79
- d = d.div(5)
80
- m = (m+2) % 12
81
- y = y - 4716 + (13-m) / 12
82
- return [y,m,d]
83
- end
84
-
85
- # 暦要素数
86
- #
87
- # @see When::CalendarTypes::TableBased#_length
88
- #
89
- def _length(date)
90
- yy, mm = date
91
- return super unless(mm)
92
- return ((yy % 4) == 0) ? 29 : 28 if (mm == 1)
93
- return (((((mm + 10) % 12) % 5) % 2) == 0) ? 31 : 30
94
- end
95
-
96
- # 復活祭の遅延日数
97
- #
98
- # @private
99
- def _easter_delay(year)
100
- 0
101
- end
102
-
103
- private
104
-
105
- def _normalize(args=[], options={})
106
- raise TypeError, "#{self.class} is abstract class" unless @label
107
- @note = When.CalendarNote(@note || 'Christian')
108
- super
109
- end
110
- end
111
-
112
- #
113
- # Julian Calendar
114
- #
115
- class Julian < Christian
116
-
117
- # 太陰方程式
118
- #
119
- # @param [Numeric] year 西暦の年数
120
- # @return [Integer] 0 (ユリウス暦では補正なし)
121
- #
122
- def _lunar_equation(year)
123
- 0
124
- end
125
-
126
- # @private
127
- #
128
- # 対応する ::Date の start 属性
129
- def _default_start
130
- ::Date::JULIAN
131
- end
132
-
133
- private
134
-
135
- def _normalize(args=[], options={})
136
- @label ||= 'Christian::Julian'
137
- super
138
- end
139
- end
140
-
141
- #
142
- # Swedish Calendar
143
- #
144
- class Swedish < Julian
145
-
146
- # デフォルトの改暦日付(ユリウス通日)
147
- #
148
- # @private
149
- DefaultReformDate = 2361390 # 1753-03-01
150
-
151
- # @private
152
- # Julian - 17000229 17120229
153
- SwedishCalendarRange = 2342042...2346425
154
-
155
- # @private
156
- ExtraDate = [1712,1,29]
157
-
158
- # @private
159
- Length = {
160
- [1700, nil] => 365,
161
- [1700, 1] => 28,
162
- [1712, nil] => 367,
163
- [1712, 1] => 30
164
- }
165
-
166
- # Ref: http://www.ortelius.de/kalender/east_en.php
167
- # @private
168
- EasterDelay = {
169
- 1741 => -7,
170
- 1742 => -35,
171
- 1744 => -7,
172
- 1745 => -7,
173
- 1747 => -28,
174
- 1748 => -7,
175
- 1750 => -28,
176
- 1751 => -7,
177
- 1752 => -7,
178
- 1802 => +7,
179
- 1805 => +7,
180
- 1818 => +7
181
- }
182
-
183
- # 年月日 -> 通日
184
- #
185
- # @see When::CalendarTypes::TableBased#_coordinates_to_number
186
- #
187
- def _coordinates_to_number(y,m,d)
188
- jdn = super
189
- return SwedishCalendarRange.last if [+y, m, d] == ExtraDate
190
- SwedishCalendarRange.include?(jdn-1) ? jdn-1 : jdn
191
- end
192
-
193
- # 通日 - > 年月日
194
- #
195
- # @see When::CalendarTypes::TableBased#_number_to_coordinates
196
- #
197
- def _number_to_coordinates(jdn)
198
- return ExtraDate.dup if jdn == SwedishCalendarRange.last
199
- super(SwedishCalendarRange.include?(jdn) ? jdn+1 : jdn)
200
- end
201
-
202
- # 暦要素数
203
- #
204
- # @see When::CalendarTypes::TableBased#_length
205
- #
206
- def _length(date)
207
- y, m = date
208
- Length[[+y,m]] || super
209
- end
210
-
211
- # 復活祭の遅延日数
212
- #
213
- # @private
214
- def _easter_delay(year)
215
- EasterDelay[year] || 0
216
- end
217
-
218
- private
219
-
220
- def _normalize(args=[], options={})
221
- @label ||= 'Christian::Swedish'
222
- super
223
- end
224
- end
225
-
226
- #
227
- # Variation of Christian Calendar
228
- #
229
- class ReformVariation < Christian
230
-
231
- # 年月日 -> 通日
232
- #
233
- # @see When::CalendarTypes::TableBased#_coordinates_to_number
234
- #
235
- def _coordinates_to_number(y,m,d)
236
- super - _diff_from_century(((m < 2) ? +y-1 : +y).to_i.div(100))
237
- end
238
-
239
- # 通日 - > 年月日
240
- #
241
- # @see When::CalendarTypes::TableBased#_number_to_coordinates
242
- #
243
- def _number_to_coordinates(jdn)
244
- super(jdn + _diff_from_century(_century_from_jdn(jdn)))
245
- end
246
-
247
- # 暦要素数
248
- #
249
- # @see When::CalendarTypes::TableBased#_length
250
- #
251
- def _length(date)
252
- yy, mm = date
253
- return super unless mm == 1 # 2月でなければユリウス暦と同じ
254
- cc, yy = yy.divmod(100)
255
- return super unless yy == 0 # 100で割り切れない年はユリウス暦と同じ
256
- 29 - (_diff_from_century(cc) - _diff_from_century(cc-1))
257
- end
258
-
259
- # 太陰方程式
260
- #
261
- # @param [Numeric] year 西暦の年数
262
- # @return [Integer] 19年7閏のペースに対する満月の日付の補正量
263
- # @note 太陽暦日の補正も、本メソッドで行う
264
- #
265
- def _lunar_equation(year)
266
- h = +year.div(100)
267
- (8*(h+11)).div(25) - (_diff_from_century(h) + 5)
268
- end
269
- end
270
-
271
- #
272
- # Gregorian Calendar
273
- #
274
- class Gregorian < ReformVariation
275
-
276
- # 百年代 - > ユリウス暦とグレゴリオ暦の差
277
- #
278
- # @param [Integer] century 百年代
279
- #
280
- # @return [Integer] ユリウス暦とグレゴリオ暦の差
281
- #
282
- def _diff_from_century(century)
283
- (3*(century-3)).div(4)+1
284
- end
285
-
286
- # 通日 - > 百年代
287
- #
288
- # @param [Integer] jdn 通日
289
- #
290
- # @return [Integer] 百年代
291
- #
292
- def _century_from_jdn(jdn)
293
- (4 * jdn - 6884477).div(146097)
294
- end
295
-
296
- private
297
-
298
- def _normalize(args=[], options={})
299
- @label ||= 'Christian::Gregorian'
300
- super
301
- end
302
- end
303
-
304
- #
305
- # Revised Julian Calendar
306
- #
307
- class RevisedJulian < ReformVariation
308
-
309
- # デフォルトの改暦日付(ユリウス通日)
310
- #
311
- # @private
312
- DefaultReformDate = 2423707 # 1923-10-14
313
-
314
- # 百年代 - > ユリウス暦と修正ユリウス暦の差
315
- #
316
- # @param [Integer] century 百年代
317
- #
318
- # @return [Integer] ユリウス暦と修正ユリウス暦の差
319
- #
320
- def _diff_from_century(century)
321
- (7*(century-1)).div(9)-1
322
- end
323
-
324
- # 通日 - > 百年代
325
- #
326
- # @param [Integer] jdn 通日
327
- #
328
- # @return [Integer] 百年代
329
- #
330
- def _century_from_jdn(jdn)
331
- (9 * jdn - 15490078).div(328718)
332
- end
333
-
334
- private
335
-
336
- def _normalize(args=[], options={})
337
- @label ||= 'Christian::RevisedJulian'
338
- # @diff ||= [-2, -1, -1, 0, 1, 2, 2, 3, 4, 5] # 1~10世紀の各世紀のユリウス暦と差の日数
339
- super
340
- end
341
- end
342
-
343
- #
344
- # Civil Calendar
345
- #
346
- class Civil < Gregorian
347
-
348
- #
349
- # 改暦日付
350
- #
351
- # @return [Integer]
352
- #
353
- attr_reader :reform_jdn
354
-
355
- # @private
356
- #
357
- # 対応する ::Date の start 属性
358
- alias :_default_start :reform_jdn
359
-
360
- #
361
- # 年初の最初の定義の年
362
- #
363
- # @return [Integer] 年初の最初の定義の年
364
- # @return nil
365
- #
366
- def first_year_of_border
367
- return nil unless @border.kind_of?(When::CalendarTypes::MultiBorder)
368
- year = @border.borders[-1][:key]
369
- year.kind_of?(Integer) ? year : nil
370
- end
371
-
372
- # 年月日 -> 通日
373
- #
374
- # @see When::CalendarTypes::TableBased#_coordinates_to_number
375
- #
376
- def _coordinates_to_number(y,m,d)
377
- skip, limit = @the_length[[y,m]]
378
- d += skip if skip && d >= limit
379
- jdn = @new._coordinates_to_number(y,m,d)
380
- jdn >= @reform_jdn ? jdn : @old._coordinates_to_number(y + @origin_of_MSC - @old.origin_of_MSC, m, d)
381
- end
382
-
383
- # 通日 - > 年月日
384
- #
385
- # @see When::CalendarTypes::TableBased#_number_to_coordinates
386
- #
387
- def _number_to_coordinates(jdn)
388
- if jdn >= @reform_jdn
389
- date = @new._number_to_coordinates(jdn)
390
- else
391
- date = @old._number_to_coordinates(jdn)
392
- date[0] -= @origin_of_MSC - @old.origin_of_MSC
393
- end
394
- skip, limit = @the_length[date[0..-2]]
395
- date[2] -= skip if skip && date[2] >= limit
396
- date
397
- end
398
-
399
- # 暦要素数
400
- #
401
- # @see When::CalendarTypes::TableBased#_length
402
- #
403
- def _length(date)
404
- return @the_length[date][2] if @the_length[date]
405
- yy, mm = date
406
- (yy > @reform_date[0]) ||
407
- (yy == @reform_date[0] && (!mm || mm >= @reform_date[1])) ?
408
- @new._length(date) :
409
- @old._length([yy + @origin_of_MSC - @old.origin_of_MSC, mm])
410
- end
411
-
412
- # 太陰方程式
413
- #
414
- # @param [Numeric] year 西暦の年数
415
- # @return [Integer] 19年7閏のペースに対する満月の日付の補正量
416
- # @note 太陽暦日の補正も、本メソッドで行う
417
- #
418
- def _lunar_equation(year)
419
- year >= @the_easter ? @new._lunar_equation(year) : @old._lunar_equation(year)
420
- end
421
-
422
- # 復活祭の遅延日数
423
- #
424
- # @private
425
- def _easter_delay(year)
426
- @old._easter_delay(year)
427
- end
428
-
429
- private
430
-
431
- # オブジェクトの正規化
432
- #
433
- # @old = 改暦前の暦法(デフォルトはユリウス暦)
434
- # @new = 改暦後の暦法(デフォルトはグレゴリオ暦)
435
- # @reform_date = 改暦日付(月日は 1 オリジンで指定し、0 オリジンに直して保持)
436
- # @reform_jdn = 改暦日付のユリウス通日
437
- # @reform = reform_date か reform_jdn を内容で判別し、どちらかに反映する
438
- # @the_easter = 新暦法の復活祭計算の適用を始める年
439
- # @the_length = 通常と異なる日付となる年月の情報({[年,月]=>[スキップした日数, スキップし始める日, 月の日数]})
440
- #
441
- def _normalize(args=[], options={})
442
- @label ||= 'Christian::Civil'
443
-
444
- # 前後の暦法
445
- @old = When.Calendar(@old || 'Julian')
446
- @new = When.Calendar(@new || 'Gregorian')
447
- @indices ||= @old.indices
448
-
449
- # 改暦日付 (0 オリジン)
450
- @reform = When::Coordinates::Pair._en_pair_date_time(@reform) if @reform.kind_of?(String)
451
- case @reform.length
452
- when 0 ;
453
- when 1 ; @reform_jdn = @reform[0]
454
- else ; @reform_date = @reform
455
- end if @reform.kind_of?(Array)
456
-
457
- if @reform_date
458
- @reform_date = When::Coordinates::Pair._en_pair_date_time(@reform_date) if @reform_date.kind_of?(String)
459
- @reform_date = @reform_date.map {|c| c.to_i}
460
- (1..2).each {|i| @reform_date[i] = @reform_date[i] ? @reform_date[i] - 1 : 0 }
461
- @reform_jdn = @new._coordinates_to_number(*@reform_date)
462
- else
463
- @reform_jdn ||= [@old.class::DefaultReformDate, @new.class::DefaultReformDate].max
464
- @reform_jdn = @reform_jdn.to_i
465
- @reform_date = @new._number_to_coordinates(@reform_jdn)
466
- end
467
- last_date = @old._number_to_coordinates(@reform_jdn-1)
468
-
469
- # 復活祭との前後関係
470
- @the_easter = @reform_jdn > When.CalendarNote('Christian').easter(@reform_date[0], @new) ? @reform_date[0]+1 : @reform_date[0]
471
-
472
- # 月の日数
473
- this_month = @reform_date[0..1]
474
- new_length = @new._length(this_month)
475
- @the_length = {}
476
- if @reform_date[1] == last_date[1] # 同一月内に閉じた改暦
477
- skipped_length = @reform_date[2] - last_date[2] - 1
478
- @the_length[this_month] = [skipped_length, last_date[2]+1, new_length-skipped_length]
479
- else
480
- last_month = [(@reform_date[1] > last_date[1] ? @reform_date[0] : @reform_date[0]-1), last_date[1]]
481
- @the_length[this_month] = [@reform_date[2], 0, new_length - @reform_date[2]]
482
- @the_length[last_month] = [false, false, last_date[2]+1]
483
- end
484
-
485
- super
486
- end
487
-
488
- #
489
- # 整数のindex化
490
- #
491
- def _to_index(date)
492
- digit = date[-1] - @base[date.length-1]
493
- skip, limit = @the_length[date[0..-2]]
494
- skip && digit >= limit ? digit-skip : digit
495
- end
496
-
497
- #
498
- # indexの整数化
499
- #
500
- def _from_index(date)
501
- digit = date[-1]
502
- skip, limit = @the_length[date[0..-2]]
503
- (skip && digit >= limit ? digit+skip : digit)+@base[date.length-1]
504
- end
505
- end
506
-
507
- #
508
- # 日時要素の境界 - 復活祭
509
- #
510
- class Easter < Border
511
-
512
- # 境界の取得
513
- #
514
- # @param [Array<Numeric>] date 境界を計算する年
515
- # @param [When::TM::ReferenceSystem] frame 使用する暦法
516
- #
517
- # @return [Array<Numeric>] その年の境界
518
- #
519
- def border(date=[], frame=When::Gregorian)
520
- frame._encode(frame._number_to_coordinates(frame.note.easter(date[0], frame)), false)
521
- end
522
-
523
- private
524
-
525
- # 要素の正規化
526
- def _normalize(args=[], options={})
527
- @border = [0,0,0]
528
- end
529
- end
530
- end
531
-
532
- #
533
- # キリスト教の暦注(クリスマスと復活祭)
534
- #
535
- class CalendarNote::Christian < CalendarNote
536
-
537
- Notes = [When::BasicTypes::M17n, [
538
- "locale:[=en:, ja=ja:, alias]",
539
- "names:[Christian]",
540
-
541
- # 年の暦注 ----------------------------
542
- [When::BasicTypes::M17n,
543
- "names:[year]"
544
- ],
545
-
546
- # 月の暦注 ----------------------------
547
- [When::BasicTypes::M17n,
548
- "names:[month]",
549
- [When::BasicTypes::M17n,
550
- "names:[Month]"
551
- ]
552
- ],
553
-
554
- # 日の暦注 ----------------------------
555
- [When::BasicTypes::M17n,
556
- "names:[day]",
557
- [When::BasicTypes::M17n, "names:[Week, 七曜]" ],
558
- [When::BasicTypes::M17n, "names:[Easter, 復活祭]" ],
559
- [When::BasicTypes::M17n, "names:[Christmas, クリスマス]"],
560
- [When::BasicTypes::M17n, "names:[Fixed_feast=, 固定祝日=]" ],
561
- [When::BasicTypes::M17n, "names:[Moveable_feast, 移動祝日]" ]
562
- ]
563
- ]]
564
-
565
- # 固定祝日
566
- Fixed_feasts = {
567
- [ 1, 6] => "Epiphany",
568
- [ 3, 1] => "St.David's Day",
569
- [ 3, 17] => "St.Patrick's Day",
570
- [ 3, 25] => "Annunciation-Lady Day",
571
- [ 4, 23] => "St.George's Day",
572
- [ 6, 24] => "Midsummer Day",
573
- [ 9, 14] => "Holy Cross Day",
574
- [ 9, 29] => "Michaelmas Day",
575
- [11, 30] => "St.Andrew's Day",
576
- [12, 13] => "St.Lucia's Day",
577
- [12, 21] => "St.Thomas's Day",
578
- # [12, 25] => "Christmas Day"
579
- }
580
-
581
- # 移動祝日 (日付と曜日による)
582
- moveable_feasts = {}
583
- [[[ 9, 15, 2], "III Quatember"],
584
- [[11, 27, 6], "Advent Sunday"],
585
- [[12, 14, 2], "IV Quatember" ]].each do |pair|
586
- date, name = pair
587
- 7.times do
588
- moveable_feasts[date.dup] = name
589
- date[1] += 1
590
- if date[1] > 30
591
- date[0] += 1
592
- date[1] = 1
593
- end
594
- end
595
- end
596
-
597
- # 移動祝日
598
- Moveable_feasts = {
599
- # 復活祭からの日数による
600
- -63 => "Septuagesima Sunday",
601
- -56 => "Sexagesima Sunday",
602
- -49 => "Quinquagesima Sunday",
603
- -46 => "Ash Wednesday",
604
- -42 => "Quadragesima Sunday",
605
- -40 => "I Quatember",
606
- -35 => "Reminizer Sunday",
607
- -28 => "Oculi Sunday",
608
- -21 => "Laetare Sunday",
609
- -14 => "Judica Sunday",
610
- -7 => "Palmarum",
611
- -2 => "Good Friday",
612
- # 0 => "Easter Day",
613
- 7 => "Low Sunday",
614
- 35 => "Rogation Sunday",
615
- 39 => "Ascension Day",
616
- 49 => "Whitsunday",
617
- 53 => "II Quatember",
618
- 56 => "Trinity Sunday",
619
- 60 => "Corpus Christi",
620
- }.update(moveable_feasts)
621
-
622
- #
623
- # 暦法によってイベントの動作を変えるか否か
624
- #
625
- CalendarDepend = true
626
-
627
- # 週日補正フラグ
628
- # @return [Integer]
629
- attr_reader :w
630
-
631
- # 最も遅い満月の3月0日からの日数
632
- # @return [Integer]
633
- attr_reader :d
634
-
635
- # クリスマスの3月0日からの日数
636
- # @return [Integer]
637
- attr_reader :x
638
-
639
- # 平年数
640
- # @return [Integer]
641
- attr_reader :n
642
-
643
- # 置閏周期
644
- # @return [Integer]
645
- attr_reader :s
646
-
647
- # 月の位相の補正
648
- # @return [Integer]
649
- attr_reader :c
650
-
651
- # ガード
652
- # @return [Integer]
653
- attr_reader :g
654
-
655
- # ベース
656
- # @return [Integer]
657
- attr_reader :b
658
-
659
- # 満月補正フラグ
660
- # @return [Integer]
661
- attr_reader :f
662
-
663
- # 七曜
664
- #
665
- # @param [When::TM::TemporalPosition] date
666
- # @param [When::TM::CalDate] base (not used)
667
- #
668
- # @return [When::Coordinates::Residue] 七曜
669
- #
670
- def week(date, base=nil)
671
- When.Residue('Week')[date.to_i % 7]
672
- end
673
-
674
- # クリスマス
675
- #
676
- # @param [Numeric] date 西暦の年数
677
- # @param [When::TM::TemporalPosition] date
678
- # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
679
- #
680
- # @return [Integer] クリスマスのユリウス通日(dateが西暦の年数の場合)
681
- # @return [When::TM::CalDate] クリスマスのWhen::TM::CalDate(yearがWhen::TM::TemporalPositionの場合)
682
- #
683
- def christmas(date, frame=nil)
684
- _event(date, 'christmas', frame) do |year, frame|
685
- @x - 1 + frame._coordinates_to_number(year, 2, 0)
686
- end
687
- end
688
-
689
- # 復活祭
690
- #
691
- # @param [Numeric] date 西暦の年数
692
- # @param [When::TM::TemporalPosition] date
693
- # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
694
- #
695
- # @return [Integer] 復活祭のユリウス通日(dateが西暦の年数の場合)
696
- # @return [When::TM::CalDate] 復活祭のWhen::TM::CalDate(yearがWhen::TM::TemporalPositionの場合)
697
- #
698
- def easter(date, frame=nil)
699
- _event(date, 'easter', frame) do |year, frame|
700
- golden = (year+@b) % @s + 1
701
- m = (frame._lunar_equation(year) + 11*golden + @c) % 30
702
- if @f == 0
703
- m += 1 if m==0 || m==1 && golden>=@n
704
- else
705
- m += (golden-1) / @f
706
- m -= 30 if m>=@n
707
- end
708
- result = frame._coordinates_to_number(year, 2, 0) + @d - 1 - m
709
- result += @g - (result-@w) % 7 if @w<7
710
- result + frame._easter_delay(year)
711
- end
712
- end
713
-
714
- # イベントの標準的な間隔を返す
715
- # @private
716
- def _delta(parameter=nil)
717
- return When::P1Y
718
- end
719
-
720
- # @private
721
- alias :christmas_delta :_delta
722
-
723
- # @private
724
- alias :easter_delta :_delta
725
-
726
- # 固定祝日
727
- #
728
- # @param [When::TM::TemporalPosition] date
729
- # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
730
- #
731
- # @return [String] 祝日の名称
732
- # @return [nil] 祝日に該当しない
733
- #
734
- def fixed_feast(date, frame=nil)
735
- date = When.Calendar(frame||'Gregorian') ^ date unless date.frame.kind_of?(When::CalendarTypes::Christian)
736
- Fixed_feasts[date.cal_date[-2..-1]]
737
- end
738
-
739
- # 移動祝日
740
- #
741
- # @param [When::TM::TemporalPosition] date
742
- # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
743
- #
744
- # @return [String] 祝日の名称
745
- # @return [nil] 祝日に該当しない
746
- #
747
- def moveable_feast(date, frame=nil)
748
- result = Moveable_feasts[date.to_i - easter(date, frame).to_i]
749
- return result if result
750
- date = When.Calendar(frame||'Gregorian') ^ date unless date.frame.kind_of?(When::CalendarTypes::Christian)
751
- Moveable_feasts[date.cal_date[-2..-1] + [date.to_i % 7]]
752
- end
753
-
754
- private
755
-
756
- # オブジェクトの正規化
757
- # w - 週日補正フラグ(デフォルト 6)
758
- # d - 最も遅い満月 (デフォルト 3月0日から 50日)
759
- # x - クリスマス (デフォルト 3月0日から300日)
760
- # n - 平年数 (デフォルト 12)
761
- # s - 置閏周期 (デフォルト 19)
762
- # c - 月の位相の補正(デフォルト 3)
763
- # g - ガード (デフォルト 7)
764
- # b - ベース (デフォルト 0)
765
- # f - 満月補正フラグ(デフォルト 0)
766
- def _normalize(args=[], options={})
767
- w, d, x, n, s, c, g, b, f = args
768
- @w = (w || @w || 6).to_i
769
- @d = (d || @d || 50).to_i
770
- @x = (x || @x || 300).to_i
771
- @n = (n || @n || 12).to_i
772
- @s = (s || @s || 19).to_i
773
- @c = (c || @c || 3).to_i
774
- @g = (g || @g || 7).to_i
775
- @b = (b || @b || 0).to_i
776
- @f = (f || @f || 0).to_i
777
- @event = 'easter'
778
- @prime ||= [['Month'], ['Week']]
779
- super
780
- end
781
-
782
- #
783
- # 任意の暦をグレゴリオorユリウス暦日に変換
784
- #
785
- def _to_date_for_note(date)
786
- return When.Calendar(When::CalendarTypes::Christian._default_start(date)) ^ date if ::Object.const_defined?(:Date) && date.kind_of?(::Date)
787
- return When::Gregorian ^ date if date.kind_of?(::Time)
788
- return date if date.frame.kind_of?(When::CalendarTypes::Christian)
789
- When.Calendar(date.frame.iri =~ /Coptic/ || date.to_i < 2299161 ? 'Julian' : 'Gregorian') ^ date
790
- end
791
-
792
- # 当該年のイベントの日付
793
- # date : 西暦の年数 or When::TM::(Temporal)Position
794
- # event : イベント名 (String)
795
- # frame : 暦法(デフォルトは When:Gregorian)
796
- #
797
- # @return [Integer] イベントのユリウス通日(dateが西暦の年数の場合)
798
- # @return [When::TM::CalDate] イベントのWhen::TM::CalDate(yearがWhen::TM::(Temporal)Positionの場合)
799
- #
800
- def _event(date, event, frame=nil)
801
- case date
802
- when Numeric
803
- year = date * 1
804
- when When::TimeValue
805
- options = date._attr
806
- options[:precision] = When::DAY
807
- options[:events] = [event]
808
- if frame
809
- frame = When.Calendar(frame)
810
- date = frame.jul_trans(date, options)
811
- else
812
- frame = date.frame
813
- end
814
- year = date.most_significant_coordinate * 1
815
- else
816
- raise TypeError, "Irregal date type: #{date.class}"
817
- end
818
- frame ||= When::Gregorian
819
- result = yield(year, frame)
820
- return result if date.kind_of?(Numeric)
821
- return frame.jul_trans(result, options)
822
- end
823
- end
824
- end
1
+ # -*- coding: utf-8 -*-
2
+ =begin
3
+ Copyright (C) 2011-2014 Takashi SUGA
4
+
5
+ You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
+ =end
7
+
8
+ module When
9
+
10
+ class BasicTypes::M17n
11
+
12
+ Christian = [self, [
13
+ "locale:[=en:, ja=ja:, alias]",
14
+ "names:[Christian=]",
15
+ "[Julian=en:Julian_calendar, ユリウス暦 ]",
16
+ "[Gregorian=en:Gregorian_calendar, グレゴリオ暦 ]",
17
+ "[RevisedJulian=en:Revised_Julian_calendar, 修正ユリウス暦]",
18
+ "[Swedish=en:Swedish_calendar, スウェーデン暦]",
19
+ "[Civil in the West=en:Civil_calendar, 西暦, *alias:Civil]"
20
+ ]]
21
+ end
22
+
23
+ class TM::CalendarEra
24
+ # Anno Mundi Era
25
+ Byzantine = [self, [
26
+ "locale:[=en:, ja=ja:, alias]",
27
+ "period:[Byzantine=en:Byzantine_calendar, ビザンティン暦=ja:%%<世界創造紀元>]",
28
+ ["[AM=en:Anno_Mundi, 世界創造紀元, alias:Anno_Mundi]6497*9.1",
29
+ '@CE', "989*09-01^Julian?border=0*9-1&note=Roman", "1453-5-29"]
30
+ ]]
31
+ end
32
+
33
+ module CalendarTypes
34
+
35
+ #
36
+ # Christian Base Calendar
37
+ #
38
+ class Christian < When::TM::Calendar
39
+
40
+ # デフォルトの改暦日付(ユリウス通日)
41
+ #
42
+ # @private
43
+ DefaultReformDate = 2299161 # 1582-10-15
44
+
45
+ # @private
46
+ #
47
+ # ::Date オブジェクトに対応する暦法名
48
+ # (require 'Date' されていることの保証は呼び出し側)
49
+ #
50
+ def self._default_start(date)
51
+ case date.start
52
+ when ::Date::JULIAN ; 'Julian'
53
+ when ::Date::GREGORIAN ; 'Gregorian'
54
+ else ; "Civil?reform_jdn=#{date.start}"
55
+ end
56
+ end
57
+
58
+ # 年月日 -> 通日
59
+ #
60
+ # @see When::CalendarTypes::TableBased#_coordinates_to_number
61
+ #
62
+ def _coordinates_to_number(y,m,d)
63
+ m = (+m + 10) % 12
64
+ y = +y + 4716 - m / 10
65
+ a = (1461*y.to_i ).div(4)
66
+ b = ( 153*m.to_i + 2).div(5)
67
+ return a + b + (+d) - 1401
68
+ end
69
+
70
+ # 通日 - > 年月日
71
+ #
72
+ # @see When::CalendarTypes::TableBased#_number_to_coordinates
73
+ #
74
+ def _number_to_coordinates(jdn)
75
+ j = jdn.to_i + 1401
76
+ y, t = (4*j + 3).divmod(1461)
77
+ t = t.div(4)
78
+ m, d = (5*t + 2).divmod(153)
79
+ d = d.div(5)
80
+ m = (m+2) % 12
81
+ y = y - 4716 + (13-m) / 12
82
+ return [y,m,d]
83
+ end
84
+
85
+ # 暦要素数
86
+ #
87
+ # @see When::CalendarTypes::TableBased#_length
88
+ #
89
+ def _length(date)
90
+ yy, mm = date
91
+ return super unless(mm)
92
+ return ((yy % 4) == 0) ? 29 : 28 if (mm == 1)
93
+ return (((((mm + 10) % 12) % 5) % 2) == 0) ? 31 : 30
94
+ end
95
+
96
+ # 復活祭の遅延日数
97
+ #
98
+ # @private
99
+ def _easter_delay(year)
100
+ 0
101
+ end
102
+
103
+ private
104
+
105
+ def _normalize(args=[], options={})
106
+ raise TypeError, "#{self.class} is abstract class" unless @label
107
+ @note = When.CalendarNote(@note || 'Christian')
108
+ super
109
+ end
110
+ end
111
+
112
+ #
113
+ # Julian Calendar
114
+ #
115
+ class Julian < Christian
116
+
117
+ # 太陰方程式
118
+ #
119
+ # @param [Numeric] year 西暦の年数
120
+ # @return [Integer] 0 (ユリウス暦では補正なし)
121
+ #
122
+ def _lunar_equation(year)
123
+ 0
124
+ end
125
+
126
+ # @private
127
+ #
128
+ # 対応する ::Date の start 属性
129
+ def _default_start
130
+ ::Date::JULIAN
131
+ end
132
+
133
+ private
134
+
135
+ def _normalize(args=[], options={})
136
+ @label ||= 'Christian::Julian'
137
+ super
138
+ end
139
+ end
140
+
141
+ #
142
+ # Swedish Calendar
143
+ #
144
+ class Swedish < Julian
145
+
146
+ # デフォルトの改暦日付(ユリウス通日)
147
+ #
148
+ # @private
149
+ DefaultReformDate = 2361390 # 1753-03-01
150
+
151
+ # @private
152
+ # Julian - 17000229 17120229
153
+ SwedishCalendarRange = 2342042...2346425
154
+
155
+ # @private
156
+ ExtraDate = [1712,1,29]
157
+
158
+ # @private
159
+ Length = {
160
+ [1700, nil] => 365,
161
+ [1700, 1] => 28,
162
+ [1712, nil] => 367,
163
+ [1712, 1] => 30
164
+ }
165
+
166
+ # Ref: http://www.ortelius.de/kalender/east_en.php
167
+ # @private
168
+ EasterDelay = {
169
+ 1741 => -7,
170
+ 1742 => -35,
171
+ 1744 => -7,
172
+ 1745 => -7,
173
+ 1747 => -28,
174
+ 1748 => -7,
175
+ 1750 => -28,
176
+ 1751 => -7,
177
+ 1752 => -7,
178
+ 1802 => +7,
179
+ 1805 => +7,
180
+ 1818 => +7
181
+ }
182
+
183
+ # 年月日 -> 通日
184
+ #
185
+ # @see When::CalendarTypes::TableBased#_coordinates_to_number
186
+ #
187
+ def _coordinates_to_number(y,m,d)
188
+ jdn = super
189
+ return SwedishCalendarRange.last if [+y, m, d] == ExtraDate
190
+ SwedishCalendarRange.include?(jdn-1) ? jdn-1 : jdn
191
+ end
192
+
193
+ # 通日 - > 年月日
194
+ #
195
+ # @see When::CalendarTypes::TableBased#_number_to_coordinates
196
+ #
197
+ def _number_to_coordinates(jdn)
198
+ return ExtraDate.dup if jdn == SwedishCalendarRange.last
199
+ super(SwedishCalendarRange.include?(jdn) ? jdn+1 : jdn)
200
+ end
201
+
202
+ # 暦要素数
203
+ #
204
+ # @see When::CalendarTypes::TableBased#_length
205
+ #
206
+ def _length(date)
207
+ y, m = date
208
+ Length[[+y,m]] || super
209
+ end
210
+
211
+ # 復活祭の遅延日数
212
+ #
213
+ # @private
214
+ def _easter_delay(year)
215
+ EasterDelay[year] || 0
216
+ end
217
+
218
+ private
219
+
220
+ def _normalize(args=[], options={})
221
+ @label ||= 'Christian::Swedish'
222
+ super
223
+ end
224
+ end
225
+
226
+ #
227
+ # Variation of Christian Calendar
228
+ #
229
+ class ReformVariation < Christian
230
+
231
+ # 年月日 -> 通日
232
+ #
233
+ # @see When::CalendarTypes::TableBased#_coordinates_to_number
234
+ #
235
+ def _coordinates_to_number(y,m,d)
236
+ super - _diff_from_century(((m < 2) ? +y-1 : +y).to_i.div(100))
237
+ end
238
+
239
+ # 通日 - > 年月日
240
+ #
241
+ # @see When::CalendarTypes::TableBased#_number_to_coordinates
242
+ #
243
+ def _number_to_coordinates(jdn)
244
+ super(jdn + _diff_from_century(_century_from_jdn(jdn)))
245
+ end
246
+
247
+ # 暦要素数
248
+ #
249
+ # @see When::CalendarTypes::TableBased#_length
250
+ #
251
+ def _length(date)
252
+ yy, mm = date
253
+ return super unless mm == 1 # 2月でなければユリウス暦と同じ
254
+ cc, yy = yy.divmod(100)
255
+ return super unless yy == 0 # 100で割り切れない年はユリウス暦と同じ
256
+ 29 - (_diff_from_century(cc) - _diff_from_century(cc-1))
257
+ end
258
+
259
+ # 太陰方程式
260
+ #
261
+ # @param [Numeric] year 西暦の年数
262
+ # @return [Integer] 19年7閏のペースに対する満月の日付の補正量
263
+ # @note 太陽暦日の補正も、本メソッドで行う
264
+ #
265
+ def _lunar_equation(year)
266
+ h = +year.div(100)
267
+ (8*(h+11)).div(25) - (_diff_from_century(h) + 5)
268
+ end
269
+ end
270
+
271
+ #
272
+ # Gregorian Calendar
273
+ #
274
+ class Gregorian < ReformVariation
275
+
276
+ # 百年代 - > ユリウス暦とグレゴリオ暦の差
277
+ #
278
+ # @param [Integer] century 百年代
279
+ #
280
+ # @return [Integer] ユリウス暦とグレゴリオ暦の差
281
+ #
282
+ def _diff_from_century(century)
283
+ (3*(century-3)).div(4)+1
284
+ end
285
+
286
+ # 通日 - > 百年代
287
+ #
288
+ # @param [Integer] jdn 通日
289
+ #
290
+ # @return [Integer] 百年代
291
+ #
292
+ def _century_from_jdn(jdn)
293
+ (4 * jdn - 6884477).div(146097)
294
+ end
295
+
296
+ private
297
+
298
+ def _normalize(args=[], options={})
299
+ @label ||= 'Christian::Gregorian'
300
+ super
301
+ end
302
+ end
303
+
304
+ #
305
+ # Revised Julian Calendar
306
+ #
307
+ class RevisedJulian < ReformVariation
308
+
309
+ # デフォルトの改暦日付(ユリウス通日)
310
+ #
311
+ # @private
312
+ DefaultReformDate = 2423707 # 1923-10-14
313
+
314
+ # 百年代 - > ユリウス暦と修正ユリウス暦の差
315
+ #
316
+ # @param [Integer] century 百年代
317
+ #
318
+ # @return [Integer] ユリウス暦と修正ユリウス暦の差
319
+ #
320
+ def _diff_from_century(century)
321
+ (7*(century-1)).div(9)-1
322
+ end
323
+
324
+ # 通日 - > 百年代
325
+ #
326
+ # @param [Integer] jdn 通日
327
+ #
328
+ # @return [Integer] 百年代
329
+ #
330
+ def _century_from_jdn(jdn)
331
+ (9 * jdn - 15490078).div(328718)
332
+ end
333
+
334
+ private
335
+
336
+ def _normalize(args=[], options={})
337
+ @label ||= 'Christian::RevisedJulian'
338
+ # @diff ||= [-2, -1, -1, 0, 1, 2, 2, 3, 4, 5] # 1~10世紀の各世紀のユリウス暦と差の日数
339
+ super
340
+ end
341
+ end
342
+
343
+ #
344
+ # Civil Calendar
345
+ #
346
+ class Civil < Gregorian
347
+
348
+ #
349
+ # 改暦日付
350
+ #
351
+ # @return [Integer]
352
+ #
353
+ attr_reader :reform_jdn
354
+
355
+ # @private
356
+ #
357
+ # 対応する ::Date の start 属性
358
+ alias :_default_start :reform_jdn
359
+
360
+ #
361
+ # 年初の最初の定義の年
362
+ #
363
+ # @return [Integer] 年初の最初の定義の年
364
+ # @return nil
365
+ #
366
+ def first_year_of_border
367
+ return nil unless @border.kind_of?(When::CalendarTypes::MultiBorder)
368
+ year = @border.borders[-1][:key]
369
+ year.kind_of?(Integer) ? year : nil
370
+ end
371
+
372
+ # 年月日 -> 通日
373
+ #
374
+ # @see When::CalendarTypes::TableBased#_coordinates_to_number
375
+ #
376
+ def _coordinates_to_number(y,m,d)
377
+ skip, limit = @the_length[[y,m]]
378
+ d += skip if skip && d >= limit
379
+ jdn = @new._coordinates_to_number(y,m,d)
380
+ jdn >= @reform_jdn ? jdn : @old._coordinates_to_number(y + @origin_of_MSC - @old.origin_of_MSC, m, d)
381
+ end
382
+
383
+ # 通日 - > 年月日
384
+ #
385
+ # @see When::CalendarTypes::TableBased#_number_to_coordinates
386
+ #
387
+ def _number_to_coordinates(jdn)
388
+ if jdn >= @reform_jdn
389
+ date = @new._number_to_coordinates(jdn)
390
+ else
391
+ date = @old._number_to_coordinates(jdn)
392
+ date[0] -= @origin_of_MSC - @old.origin_of_MSC
393
+ end
394
+ skip, limit = @the_length[date[0..-2]]
395
+ date[2] -= skip if skip && date[2] >= limit
396
+ date
397
+ end
398
+
399
+ # 暦要素数
400
+ #
401
+ # @see When::CalendarTypes::TableBased#_length
402
+ #
403
+ def _length(date)
404
+ return @the_length[date][2] if @the_length[date]
405
+ yy, mm = date
406
+ (yy > @reform_date[0]) ||
407
+ (yy == @reform_date[0] && (!mm || mm >= @reform_date[1])) ?
408
+ @new._length(date) :
409
+ @old._length([yy + @origin_of_MSC - @old.origin_of_MSC, mm])
410
+ end
411
+
412
+ # 太陰方程式
413
+ #
414
+ # @param [Numeric] year 西暦の年数
415
+ # @return [Integer] 19年7閏のペースに対する満月の日付の補正量
416
+ # @note 太陽暦日の補正も、本メソッドで行う
417
+ #
418
+ def _lunar_equation(year)
419
+ year >= @the_easter ? @new._lunar_equation(year) : @old._lunar_equation(year)
420
+ end
421
+
422
+ # 復活祭の遅延日数
423
+ #
424
+ # @private
425
+ def _easter_delay(year)
426
+ @old._easter_delay(year)
427
+ end
428
+
429
+ private
430
+
431
+ # オブジェクトの正規化
432
+ #
433
+ # @old = 改暦前の暦法(デフォルトはユリウス暦)
434
+ # @new = 改暦後の暦法(デフォルトはグレゴリオ暦)
435
+ # @reform_date = 改暦日付(月日は 1 オリジンで指定し、0 オリジンに直して保持)
436
+ # @reform_jdn = 改暦日付のユリウス通日
437
+ # @reform = reform_date か reform_jdn を内容で判別し、どちらかに反映する
438
+ # @the_easter = 新暦法の復活祭計算の適用を始める年
439
+ # @the_length = 通常と異なる日付となる年月の情報({[年,月]=>[スキップした日数, スキップし始める日, 月の日数]})
440
+ #
441
+ def _normalize(args=[], options={})
442
+ @label ||= 'Christian::Civil'
443
+
444
+ # 前後の暦法
445
+ @old = When.Calendar(@old || 'Julian')
446
+ @new = When.Calendar(@new || 'Gregorian')
447
+ @indices ||= @old.indices
448
+
449
+ # 改暦日付 (0 オリジン)
450
+ @reform = When::Coordinates::Pair._en_pair_date_time(@reform) if @reform.kind_of?(String)
451
+ case @reform.length
452
+ when 0 ;
453
+ when 1 ; @reform_jdn = @reform[0]
454
+ else ; @reform_date = @reform
455
+ end if @reform.kind_of?(Array)
456
+
457
+ if @reform_date
458
+ @reform_date = When::Coordinates::Pair._en_pair_date_time(@reform_date) if @reform_date.kind_of?(String)
459
+ @reform_date = @reform_date.map {|c| c.to_i}
460
+ (1..2).each {|i| @reform_date[i] = @reform_date[i] ? @reform_date[i] - 1 : 0 }
461
+ @reform_jdn = @new._coordinates_to_number(*@reform_date)
462
+ else
463
+ @reform_jdn ||= [@old.class::DefaultReformDate, @new.class::DefaultReformDate].max
464
+ @reform_jdn = @reform_jdn.to_i
465
+ @reform_date = @new._number_to_coordinates(@reform_jdn)
466
+ end
467
+ last_date = @old._number_to_coordinates(@reform_jdn-1)
468
+
469
+ # 復活祭との前後関係
470
+ @the_easter = @reform_jdn > When.CalendarNote('Christian').easter(@reform_date[0], @new) ? @reform_date[0]+1 : @reform_date[0]
471
+
472
+ # 月の日数
473
+ this_month = @reform_date[0..1]
474
+ new_length = @new._length(this_month)
475
+ @the_length = {}
476
+ if @reform_date[1] == last_date[1] # 同一月内に閉じた改暦
477
+ skipped_length = @reform_date[2] - last_date[2] - 1
478
+ @the_length[this_month] = [skipped_length, last_date[2]+1, new_length-skipped_length]
479
+ else
480
+ last_month = [(@reform_date[1] > last_date[1] ? @reform_date[0] : @reform_date[0]-1), last_date[1]]
481
+ @the_length[this_month] = [@reform_date[2], 0, new_length - @reform_date[2]]
482
+ @the_length[last_month] = [false, false, last_date[2]+1]
483
+ end
484
+
485
+ super
486
+ end
487
+
488
+ #
489
+ # 整数のindex化
490
+ #
491
+ def _to_index(date)
492
+ digit = date[-1] - @base[date.length-1]
493
+ skip, limit = @the_length[date[0..-2]]
494
+ skip && digit >= limit ? digit-skip : digit
495
+ end
496
+
497
+ #
498
+ # indexの整数化
499
+ #
500
+ def _from_index(date)
501
+ digit = date[-1]
502
+ skip, limit = @the_length[date[0..-2]]
503
+ (skip && digit >= limit ? digit+skip : digit)+@base[date.length-1]
504
+ end
505
+ end
506
+
507
+ #
508
+ # 日時要素の境界 - 復活祭
509
+ #
510
+ class Easter < Border
511
+
512
+ # 境界の取得
513
+ #
514
+ # @param [Array<Numeric>] date 境界を計算する年
515
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法
516
+ #
517
+ # @return [Array<Numeric>] その年の境界
518
+ #
519
+ def border(date=[], frame=When::Gregorian)
520
+ frame._encode(frame._number_to_coordinates(frame.note.easter(date[0], frame)), false)
521
+ end
522
+
523
+ private
524
+
525
+ # 要素の正規化
526
+ def _normalize(args=[], options={})
527
+ @border = [0,0,0]
528
+ end
529
+ end
530
+ end
531
+
532
+ #
533
+ # キリスト教の暦注(クリスマスと復活祭)
534
+ #
535
+ class CalendarNote::Christian < CalendarNote
536
+
537
+ Notes = [When::BasicTypes::M17n, [
538
+ "locale:[=en:, ja=ja:, alias]",
539
+ "names:[Christian]",
540
+
541
+ # 年の暦注 ----------------------------
542
+ [When::BasicTypes::M17n,
543
+ "names:[year]"
544
+ ],
545
+
546
+ # 月の暦注 ----------------------------
547
+ [When::BasicTypes::M17n,
548
+ "names:[month]",
549
+ [When::BasicTypes::M17n,
550
+ "names:[Month]"
551
+ ]
552
+ ],
553
+
554
+ # 日の暦注 ----------------------------
555
+ [When::BasicTypes::M17n,
556
+ "names:[day]",
557
+ [When::BasicTypes::M17n, "names:[Week, 七曜]" ],
558
+ [When::BasicTypes::M17n, "names:[Easter, 復活祭]" ],
559
+ [When::BasicTypes::M17n, "names:[Christmas, クリスマス]"],
560
+ [When::BasicTypes::M17n, "names:[Fixed_feast=, 固定祝日=]" ],
561
+ [When::BasicTypes::M17n, "names:[Moveable_feast, 移動祝日]" ]
562
+ ]
563
+ ]]
564
+
565
+ # 固定祝日
566
+ Fixed_feasts = {
567
+ [ 1, 6] => "Epiphany",
568
+ [ 3, 1] => "St.David's Day",
569
+ [ 3, 17] => "St.Patrick's Day",
570
+ [ 3, 25] => "Annunciation-Lady Day",
571
+ [ 4, 23] => "St.George's Day",
572
+ [ 6, 24] => "Midsummer Day",
573
+ [ 9, 14] => "Holy Cross Day",
574
+ [ 9, 29] => "Michaelmas Day",
575
+ [11, 30] => "St.Andrew's Day",
576
+ [12, 13] => "St.Lucia's Day",
577
+ [12, 21] => "St.Thomas's Day",
578
+ # [12, 25] => "Christmas Day"
579
+ }
580
+
581
+ # 移動祝日 (日付と曜日による)
582
+ moveable_feasts = {}
583
+ [[[ 9, 15, 2], "III Quatember"],
584
+ [[11, 27, 6], "Advent Sunday"],
585
+ [[12, 14, 2], "IV Quatember" ]].each do |pair|
586
+ date, name = pair
587
+ 7.times do
588
+ moveable_feasts[date.dup] = name
589
+ date[1] += 1
590
+ if date[1] > 30
591
+ date[0] += 1
592
+ date[1] = 1
593
+ end
594
+ end
595
+ end
596
+
597
+ # 移動祝日
598
+ Moveable_feasts = {
599
+ # 復活祭からの日数による
600
+ -63 => "Septuagesima Sunday",
601
+ -56 => "Sexagesima Sunday",
602
+ -49 => "Quinquagesima Sunday",
603
+ -46 => "Ash Wednesday",
604
+ -42 => "Quadragesima Sunday",
605
+ -40 => "I Quatember",
606
+ -35 => "Reminizer Sunday",
607
+ -28 => "Oculi Sunday",
608
+ -21 => "Laetare Sunday",
609
+ -14 => "Judica Sunday",
610
+ -7 => "Palmarum",
611
+ -2 => "Good Friday",
612
+ # 0 => "Easter Day",
613
+ 7 => "Low Sunday",
614
+ 35 => "Rogation Sunday",
615
+ 39 => "Ascension Day",
616
+ 49 => "Whitsunday",
617
+ 53 => "II Quatember",
618
+ 56 => "Trinity Sunday",
619
+ 60 => "Corpus Christi",
620
+ }.update(moveable_feasts)
621
+
622
+ #
623
+ # 暦法によってイベントの動作を変えるか否か
624
+ #
625
+ CalendarDepend = true
626
+
627
+ # 週日補正フラグ
628
+ # @return [Integer]
629
+ attr_reader :w
630
+
631
+ # 最も遅い満月の3月0日からの日数
632
+ # @return [Integer]
633
+ attr_reader :d
634
+
635
+ # クリスマスの3月0日からの日数
636
+ # @return [Integer]
637
+ attr_reader :x
638
+
639
+ # 平年数
640
+ # @return [Integer]
641
+ attr_reader :n
642
+
643
+ # 置閏周期
644
+ # @return [Integer]
645
+ attr_reader :s
646
+
647
+ # 月の位相の補正
648
+ # @return [Integer]
649
+ attr_reader :c
650
+
651
+ # ガード
652
+ # @return [Integer]
653
+ attr_reader :g
654
+
655
+ # ベース
656
+ # @return [Integer]
657
+ attr_reader :b
658
+
659
+ # 満月補正フラグ
660
+ # @return [Integer]
661
+ attr_reader :f
662
+
663
+ # 七曜
664
+ #
665
+ # @param [When::TM::TemporalPosition] date
666
+ # @param [When::TM::CalDate] base (not used)
667
+ #
668
+ # @return [When::Coordinates::Residue] 七曜
669
+ #
670
+ def week(date, base=nil)
671
+ When.Residue('Week')[date.to_i % 7]
672
+ end
673
+
674
+ # クリスマス
675
+ #
676
+ # @param [Numeric] date 西暦の年数
677
+ # @param [When::TM::TemporalPosition] date
678
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
679
+ #
680
+ # @return [Integer] クリスマスのユリウス通日(dateが西暦の年数の場合)
681
+ # @return [When::TM::CalDate] クリスマスのWhen::TM::CalDate(yearがWhen::TM::TemporalPositionの場合)
682
+ #
683
+ def christmas(date, frame=nil)
684
+ _event(date, 'christmas', frame) do |year, frame|
685
+ @x - 1 + frame._coordinates_to_number(year, 2, 0)
686
+ end
687
+ end
688
+
689
+ # 復活祭
690
+ #
691
+ # @param [Numeric] date 西暦の年数
692
+ # @param [When::TM::TemporalPosition] date
693
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
694
+ #
695
+ # @return [Integer] 復活祭のユリウス通日(dateが西暦の年数の場合)
696
+ # @return [When::TM::CalDate] 復活祭のWhen::TM::CalDate(yearがWhen::TM::TemporalPositionの場合)
697
+ #
698
+ def easter(date, frame=nil)
699
+ _event(date, 'easter', frame) do |year, frame|
700
+ golden = (year+@b) % @s + 1
701
+ m = (frame._lunar_equation(year) + 11*golden + @c) % 30
702
+ if @f == 0
703
+ m += 1 if m==0 || m==1 && golden>=@n
704
+ else
705
+ m += (golden-1) / @f
706
+ m -= 30 if m>=@n
707
+ end
708
+ result = frame._coordinates_to_number(year, 2, 0) + @d - 1 - m
709
+ result += @g - (result-@w) % 7 if @w<7
710
+ result + frame._easter_delay(year)
711
+ end
712
+ end
713
+
714
+ # イベントの標準的な間隔を返す
715
+ # @private
716
+ def _delta(parameter=nil)
717
+ return When::P1Y
718
+ end
719
+
720
+ # @private
721
+ alias :christmas_delta :_delta
722
+
723
+ # @private
724
+ alias :easter_delta :_delta
725
+
726
+ # 固定祝日
727
+ #
728
+ # @param [When::TM::TemporalPosition] date
729
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
730
+ #
731
+ # @return [String] 祝日の名称
732
+ # @return [nil] 祝日に該当しない
733
+ #
734
+ def fixed_feast(date, frame=nil)
735
+ date = When.Calendar(frame||'Gregorian') ^ date unless date.frame.kind_of?(When::CalendarTypes::Christian)
736
+ Fixed_feasts[date.cal_date[-2..-1]]
737
+ end
738
+
739
+ # 移動祝日
740
+ #
741
+ # @param [When::TM::TemporalPosition] date
742
+ # @param [When::TM::ReferenceSystem] frame 使用する暦法(デフォルトは When::Gregorian)
743
+ #
744
+ # @return [String] 祝日の名称
745
+ # @return [nil] 祝日に該当しない
746
+ #
747
+ def moveable_feast(date, frame=nil)
748
+ result = Moveable_feasts[date.to_i - easter(date, frame).to_i]
749
+ return result if result
750
+ date = When.Calendar(frame||'Gregorian') ^ date unless date.frame.kind_of?(When::CalendarTypes::Christian)
751
+ Moveable_feasts[date.cal_date[-2..-1] + [date.to_i % 7]]
752
+ end
753
+
754
+ private
755
+
756
+ # オブジェクトの正規化
757
+ # w - 週日補正フラグ(デフォルト 6)
758
+ # d - 最も遅い満月 (デフォルト 3月0日から 50日)
759
+ # x - クリスマス (デフォルト 3月0日から300日)
760
+ # n - 平年数 (デフォルト 12)
761
+ # s - 置閏周期 (デフォルト 19)
762
+ # c - 月の位相の補正(デフォルト 3)
763
+ # g - ガード (デフォルト 7)
764
+ # b - ベース (デフォルト 0)
765
+ # f - 満月補正フラグ(デフォルト 0)
766
+ def _normalize(args=[], options={})
767
+ w, d, x, n, s, c, g, b, f = args
768
+ @w = (w || @w || 6).to_i
769
+ @d = (d || @d || 50).to_i
770
+ @x = (x || @x || 300).to_i
771
+ @n = (n || @n || 12).to_i
772
+ @s = (s || @s || 19).to_i
773
+ @c = (c || @c || 3).to_i
774
+ @g = (g || @g || 7).to_i
775
+ @b = (b || @b || 0).to_i
776
+ @f = (f || @f || 0).to_i
777
+ @event = 'easter'
778
+ @prime ||= [['Month'], ['Week']]
779
+ super
780
+ end
781
+
782
+ #
783
+ # 任意の暦をグレゴリオorユリウス暦日に変換
784
+ #
785
+ def _to_date_for_note(date)
786
+ return When.Calendar(When::CalendarTypes::Christian._default_start(date)) ^ date if ::Object.const_defined?(:Date) && date.kind_of?(::Date)
787
+ return When::Gregorian ^ date if date.kind_of?(::Time)
788
+ return date if date.frame.kind_of?(When::CalendarTypes::Christian)
789
+ When.Calendar(date.frame.iri =~ /Coptic/ || date.to_i < 2299161 ? 'Julian' : 'Gregorian') ^ date
790
+ end
791
+
792
+ # 当該年のイベントの日付
793
+ # date : 西暦の年数 or When::TM::(Temporal)Position
794
+ # event : イベント名 (String)
795
+ # frame : 暦法(デフォルトは When:Gregorian)
796
+ #
797
+ # @return [Integer] イベントのユリウス通日(dateが西暦の年数の場合)
798
+ # @return [When::TM::CalDate] イベントのWhen::TM::CalDate(yearがWhen::TM::(Temporal)Positionの場合)
799
+ #
800
+ def _event(date, event, frame=nil)
801
+ case date
802
+ when Numeric
803
+ year = date * 1
804
+ when When::TimeValue
805
+ options = date._attr
806
+ options[:precision] = When::DAY
807
+ options[:events] = [event]
808
+ if frame
809
+ frame = When.Calendar(frame)
810
+ date = frame.jul_trans(date, options)
811
+ else
812
+ frame = date.frame
813
+ end
814
+ year = date.most_significant_coordinate * 1
815
+ else
816
+ raise TypeError, "Irregal date type: #{date.class}"
817
+ end
818
+ frame ||= When::Gregorian
819
+ result = yield(year, frame)
820
+ return result if date.kind_of?(Numeric)
821
+ return frame.jul_trans(result, options)
822
+ end
823
+ end
824
+ end