hijri 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0478df4d8c70d30b3d704918f17ecd12cf7a2775
4
+ data.tar.gz: f234a98f8cf1a465fea1f6985feb52e8c972fd5d
5
+ SHA512:
6
+ metadata.gz: d9025bc5ff49e22468aab6d681ca8646e7daa05486ed2a5c69cea8280e867d2dbeb836f215ea4c9101d09093046275cdb92ee787d74fee1acca5618b563aaaab
7
+ data.tar.gz: 06da097f084dc64776813237fe62bdbb2833e87bb7a4e7965a426ce16e63b07ba7b7de012b22094d26cc91bf8211dca7c4c5effa3739bab94e05bebe3bb70ca6
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.rdoc
3
+ LICENSE.txt
@@ -0,0 +1,4 @@
1
+ Gemfile.lock
2
+ doc/
3
+ pkg/
4
+ vendor/cache/*.gem
@@ -0,0 +1 @@
1
+ --markup rdoc --title "hijri Documentation" --protected
@@ -0,0 +1,4 @@
1
+ === 0.0.1 / 2012-08-05
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Abdulaziz AlShetwi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # Hijri
2
+
3
+ #####Hijri Date library for Ruby.
4
+ hijri is full Islamic Hijri calendar lib for ruby. The way it work is to convert Gregorian date to absolute date then convert it to Hijri date.
5
+ ### Hijri Calendar (from Wikipedia)
6
+ The Islamic calendar or Muslim calendar or Hijri calendar: is a lunar calendar consisting of 12 lunar months in a year of 354 or 355 days. It is used to date events in many Muslim countries (concurrently with the Gregorian calendar), and used by Muslims everywhere to determine the proper day on which to celebrate Islamic holy days and festivals. The first year was the year during which the emigration of the Islamic prophet Muhammad from Mecca to Medina, known as the Hijra, occurred. Each numbered year is designated either H for Hijra or AH for the Latin anno Hegirae (in the year of the Hijra).[1] A limited number of years before Hijra (BH) are used to date events related to Islam, such as the birth of Muhammad in 53 BH.[2] The current Islamic year is 1431 AH, from approximately 18 December 2009 (evening) to 6 December 2010 (evening).
7
+
8
+ (read more in wikipedia)[http://en.wikipedia.org/wiki/Islamic_calendar]
9
+
10
+
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'hijri'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install hijri
25
+
26
+ ## Usage
27
+
28
+ DateTime.now.to_hijri
29
+ hijri = Hijri.new 1430, 1, 3
30
+ hijri.to_greo
31
+
32
+
33
+
34
+ ## TODO
35
+
36
+ - [ ] Add Hijri::Date and Hijri::DateTime.
37
+ - [ ] Accept test error with one day range.
38
+ - [ ] Add Hijri.now to create Hijri::DateTime object.
39
+ - [ ] Add Hijri.today to create Hijri::Date object.
40
+ - [ ] Implement strftime method.
41
+
42
+
43
+ ## Contributing
44
+
45
+ 1. Fork it
46
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
47
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
48
+ 4. Push to the branch (`git push origin my-new-feature`)
49
+ 5. Create new Pull Request
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require 'rake'
6
+
7
+ require 'rake/testtask'
8
+ Rake::TestTask.new do |test|
9
+ test.libs << 'test'
10
+ test.pattern = 'test/**/test_*.rb'
11
+ test.verbose = true
12
+ end
13
+
14
+ require 'yard'
15
+ YARD::Rake::YardocTask.new
16
+ task :doc => :yard
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/hijri/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "hijri"
7
+ gem.version = Hijri::VERSION
8
+ gem.summary = %q{Hijri Date Library for Ruby}
9
+ gem.description = %q{hijri is full Islamic Hijri calendar lib for ruby.}
10
+ gem.license = "MIT"
11
+ gem.authors = ["Abdulaziz AlShetwi"]
12
+ gem.email = "ecleeld@gmail.com"
13
+ gem.homepage = "https://rubygems.org/gems/hijri"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_development_dependency 'bundler', '~> 1.0'
21
+ gem.add_development_dependency 'rake', '~> 0.8'
22
+ gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
23
+ gem.add_development_dependency 'yard', '~> 0.8'
24
+ end
@@ -0,0 +1,1313 @@
1
+ # format.rb: Written by Tadayoshi Funaba 1999-2009
2
+ # $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
3
+
4
+ class Date
5
+
6
+ module Format # :nodoc:
7
+
8
+ MONTHS = {
9
+ 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
10
+ 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
11
+ 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
12
+ }
13
+
14
+ DAYS = {
15
+ 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
16
+ 'thursday' => 4, 'friday' => 5, 'saturday' => 6
17
+ }
18
+
19
+ ABBR_MONTHS = {
20
+ 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
21
+ 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
22
+ 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
23
+ }
24
+
25
+ ABBR_DAYS = {
26
+ 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
27
+ 'thu' => 4, 'fri' => 5, 'sat' => 6
28
+ }
29
+
30
+ ZONES = {
31
+ 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
32
+ 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
33
+ 'pst' => -8*3600, 'pdt' => -7*3600,
34
+ 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
35
+ 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
36
+ 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
37
+ 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
38
+ 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
39
+ 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
40
+ 'z' => 0*3600,
41
+
42
+ 'utc' => 0*3600, 'wet' => 0*3600,
43
+ 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800),
44
+ 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600,
45
+ 'nst' => -(3*3600+1800),
46
+ 'ast' => -4*3600, 'clt' => -4*3600,
47
+ 'akdt'=> -8*3600, 'ydt' => -8*3600,
48
+ 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600,
49
+ 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600,
50
+ 'nt' =>-11*3600,
51
+ 'idlw'=>-12*3600,
52
+ 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600,
53
+ 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600,
54
+ 'west'=> 1*3600,
55
+ 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600,
56
+ 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600,
57
+ 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600,
58
+ 'msd' => 4*3600, 'zp4' => 4*3600,
59
+ 'zp5' => 5*3600, 'ist' => (5*3600+1800),
60
+ 'zp6' => 6*3600,
61
+ 'wast'=> 7*3600,
62
+ 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600,
63
+ 'jst' => 9*3600, 'kst' => 9*3600,
64
+ 'east'=> 10*3600, 'gst' => 10*3600,
65
+ 'eadt'=> 11*3600,
66
+ 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600,
67
+ 'nzdt'=> 13*3600,
68
+
69
+ 'afghanistan' => 16200, 'alaskan' => -32400,
70
+ 'arab' => 10800, 'arabian' => 14400,
71
+ 'arabic' => 10800, 'atlantic' => -14400,
72
+ 'aus central' => 34200, 'aus eastern' => 36000,
73
+ 'azores' => -3600, 'canada central' => -21600,
74
+ 'cape verde' => -3600, 'caucasus' => 14400,
75
+ 'cen. australia' => 34200, 'central america' => -21600,
76
+ 'central asia' => 21600, 'central europe' => 3600,
77
+ 'central european' => 3600, 'central pacific' => 39600,
78
+ 'central' => -21600, 'china' => 28800,
79
+ 'dateline' => -43200, 'e. africa' => 10800,
80
+ 'e. australia' => 36000, 'e. europe' => 7200,
81
+ 'e. south america' => -10800, 'eastern' => -18000,
82
+ 'egypt' => 7200, 'ekaterinburg' => 18000,
83
+ 'fiji' => 43200, 'fle' => 7200,
84
+ 'greenland' => -10800, 'greenwich' => 0,
85
+ 'gtb' => 7200, 'hawaiian' => -36000,
86
+ 'india' => 19800, 'iran' => 12600,
87
+ 'jerusalem' => 7200, 'korea' => 32400,
88
+ 'mexico' => -21600, 'mid-atlantic' => -7200,
89
+ 'mountain' => -25200, 'myanmar' => 23400,
90
+ 'n. central asia' => 21600, 'nepal' => 20700,
91
+ 'new zealand' => 43200, 'newfoundland' => -12600,
92
+ 'north asia east' => 28800, 'north asia' => 25200,
93
+ 'pacific sa' => -14400, 'pacific' => -28800,
94
+ 'romance' => 3600, 'russian' => 10800,
95
+ 'sa eastern' => -10800, 'sa pacific' => -18000,
96
+ 'sa western' => -14400, 'samoa' => -39600,
97
+ 'se asia' => 25200, 'malay peninsula' => 28800,
98
+ 'south africa' => 7200, 'sri lanka' => 21600,
99
+ 'taipei' => 28800, 'tasmania' => 36000,
100
+ 'tokyo' => 32400, 'tonga' => 46800,
101
+ 'us eastern' => -18000, 'us mountain' => -25200,
102
+ 'vladivostok' => 36000, 'w. australia' => 28800,
103
+ 'w. central africa' => 3600, 'w. europe' => 3600,
104
+ 'west asia' => 18000, 'west pacific' => 36000,
105
+ 'yakutsk' => 32400
106
+ }
107
+
108
+ [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
109
+ x.freeze
110
+ end
111
+
112
+ class Bag # :nodoc:
113
+
114
+ def initialize
115
+ @elem = {}
116
+ end
117
+
118
+ def method_missing(t, *args, &block)
119
+ t = t.to_s
120
+ set = t.chomp!('=')
121
+ t = t.intern
122
+ if set
123
+ @elem[t] = args[0]
124
+ else
125
+ @elem[t]
126
+ end
127
+ end
128
+
129
+ def to_hash
130
+ @elem.reject{|k, v| /\A_/ =~ k.to_s || v.nil?}
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+
137
+ def emit(e, f) # :nodoc:
138
+ case e
139
+ when Numeric
140
+ sign = %w(+ + -)[e <=> 0]
141
+ e = e.abs
142
+ end
143
+
144
+ s = e.to_s
145
+
146
+ if f[:s] && f[:p] == '0'
147
+ f[:w] -= 1
148
+ end
149
+
150
+ if f[:s] && f[:p] == "\s"
151
+ s[0,0] = sign
152
+ end
153
+
154
+ if f[:p] != '-'
155
+ s = s.rjust(f[:w], f[:p])
156
+ end
157
+
158
+ if f[:s] && f[:p] != "\s"
159
+ s[0,0] = sign
160
+ end
161
+
162
+ s = s.upcase if f[:u]
163
+ s = s.downcase if f[:d]
164
+ s
165
+ end
166
+
167
+ def emit_w(e, w, f) # :nodoc:
168
+ f[:w] = [f[:w], w].compact.max
169
+ emit(e, f)
170
+ end
171
+
172
+ def emit_n(e, w, f) # :nodoc:
173
+ f[:p] ||= '0'
174
+ emit_w(e, w, f)
175
+ end
176
+
177
+ def emit_sn(e, w, f) # :nodoc:
178
+ if e < 0
179
+ w += 1
180
+ f[:s] = true
181
+ end
182
+ emit_n(e, w, f)
183
+ end
184
+
185
+ def emit_z(e, w, f) # :nodoc:
186
+ w += 1
187
+ f[:s] = true
188
+ emit_n(e, w, f)
189
+ end
190
+
191
+ def emit_a(e, w, f) # :nodoc:
192
+ f[:p] ||= "\s"
193
+ emit_w(e, w, f)
194
+ end
195
+
196
+ def emit_ad(e, w, f) # :nodoc:
197
+ if f[:x]
198
+ f[:u] = true
199
+ f[:d] = false
200
+ end
201
+ emit_a(e, w, f)
202
+ end
203
+
204
+ def emit_au(e, w, f) # :nodoc:
205
+ if f[:x]
206
+ f[:u] = false
207
+ f[:d] = true
208
+ end
209
+ emit_a(e, w, f)
210
+ end
211
+
212
+ private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
213
+ :emit_a, :emit_ad, :emit_au
214
+
215
+ def strftime(fmt='%F')
216
+ fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do
217
+ f = {}
218
+ m = $&
219
+ s, w, c = $1, $2, $3
220
+ if s
221
+ s.scan(/./) do |k|
222
+ case k
223
+ when '-'; f[:p] = '-'
224
+ when '_'; f[:p] = "\s"
225
+ when '0'; f[:p] = '0'
226
+ when '^'; f[:u] = true
227
+ when '#'; f[:x] = true
228
+ end
229
+ end
230
+ end
231
+ if w
232
+ f[:w] = w.to_i
233
+ end
234
+ case c
235
+ when 'A'; emit_ad(DAYNAMES[wday], 0, f)
236
+ when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
237
+ when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
238
+ when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
239
+ when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
240
+ when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
241
+ when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
242
+ when 'd', 'Od'; emit_n(mday, 2, f)
243
+ when 'e', 'Oe'; emit_a(mday, 2, f)
244
+ when 'F'
245
+ if m == '%F'
246
+ format('%.4d-%02d-%02d', year, mon, mday) # 4p
247
+ else
248
+ emit_a(strftime('%Y-%m-%d'), 0, f)
249
+ end
250
+ when 'G'; emit_sn(cwyear, 4, f)
251
+ when 'g'; emit_n(cwyear % 100, 2, f)
252
+ when 'H', 'OH'; emit_n(hour, 2, f)
253
+ when 'h'; emit_ad(strftime('%b'), 0, f)
254
+ when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
255
+ when 'j'; emit_n(yday, 3, f)
256
+ when 'k'; emit_a(hour, 2, f)
257
+ when 'L'
258
+ f[:p] = nil
259
+ w = f[:w] || 3
260
+ u = 10**w
261
+ emit_n((sec_fraction * u).floor, w, f)
262
+ when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
263
+ when 'M', 'OM'; emit_n(min, 2, f)
264
+ when 'm', 'Om'; emit_n(mon, 2, f)
265
+ when 'N'
266
+ f[:p] = nil
267
+ w = f[:w] || 9
268
+ u = 10**w
269
+ emit_n((sec_fraction * u).floor, w, f)
270
+ when 'n'; emit_a("\n", 0, f)
271
+ when 'P'; emit_ad(strftime('%p').downcase, 0, f)
272
+ when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
273
+ when 'Q'
274
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
275
+ emit_sn(s, 1, f)
276
+ when 'R'; emit_a(strftime('%H:%M'), 0, f)
277
+ when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
278
+ when 'S', 'OS'; emit_n(sec, 2, f)
279
+ when 's'
280
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
281
+ emit_sn(s, 1, f)
282
+ when 'T'
283
+ if m == '%T'
284
+ format('%02d:%02d:%02d', hour, min, sec) # 4p
285
+ else
286
+ emit_a(strftime('%H:%M:%S'), 0, f)
287
+ end
288
+ when 't'; emit_a("\t", 0, f)
289
+ when 'U', 'W', 'OU', 'OW'
290
+ emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
291
+ when 'u', 'Ou'; emit_n(cwday, 1, f)
292
+ when 'V', 'OV'; emit_n(cweek, 2, f)
293
+ when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
294
+ when 'w', 'Ow'; emit_n(wday, 1, f)
295
+ when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
296
+ when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
297
+ when 'Y', 'EY'; emit_sn(year, 4, f)
298
+ when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
299
+ when 'Z'; emit_au(strftime('%:z'), 0, f)
300
+ when /\A(:{0,3})z/
301
+ t = $1.size
302
+ sign = if offset < 0 then -1 else +1 end
303
+ fr = offset.abs
304
+ ss = fr.div(SECONDS_IN_DAY) # 4p
305
+ hh, ss = ss.divmod(3600)
306
+ mm, ss = ss.divmod(60)
307
+ if t == 3
308
+ if ss.nonzero? then t = 2
309
+ elsif mm.nonzero? then t = 1
310
+ else t = -1
311
+ end
312
+ end
313
+ case t
314
+ when -1
315
+ tail = []
316
+ sep = ''
317
+ when 0
318
+ f[:w] -= 2 if f[:w]
319
+ tail = ['%02d' % mm]
320
+ sep = ''
321
+ when 1
322
+ f[:w] -= 3 if f[:w]
323
+ tail = ['%02d' % mm]
324
+ sep = ':'
325
+ when 2
326
+ f[:w] -= 6 if f[:w]
327
+ tail = ['%02d' % mm, '%02d' % ss]
328
+ sep = ':'
329
+ end
330
+ ([emit_z(sign * hh, 2, f)] + tail).join(sep)
331
+ when '%'; emit_a('%', 0, f)
332
+ when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
333
+ else
334
+ m
335
+ end
336
+ end
337
+ end
338
+
339
+ # alias_method :format, :strftime
340
+
341
+ def asctime() strftime('%c') end
342
+
343
+ alias_method :ctime, :asctime
344
+
345
+ def iso8601() strftime('%F') end
346
+
347
+ def rfc3339() iso8601 end
348
+
349
+ def xmlschema() iso8601 end # :nodoc:
350
+
351
+ def rfc2822() strftime('%a, %-d %b %Y %T %z') end
352
+
353
+ alias_method :rfc822, :rfc2822
354
+
355
+ def httpdate() new_offset(0).strftime('%a, %d %b %Y %T GMT') end # :nodoc:
356
+
357
+ def jisx0301
358
+ if jd < 2405160
359
+ iso8601
360
+ else
361
+ case jd
362
+ when 2405160...2419614
363
+ g = 'M%02d' % (year - 1867)
364
+ when 2419614...2424875
365
+ g = 'T%02d' % (year - 1911)
366
+ when 2424875...2447535
367
+ g = 'S%02d' % (year - 1925)
368
+ else
369
+ g = 'H%02d' % (year - 1988)
370
+ end
371
+ g + strftime('.%m.%d')
372
+ end
373
+ end
374
+
375
+ =begin
376
+ def beat(n=0)
377
+ i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
378
+ ('@%03d' % i) +
379
+ if n < 1
380
+ ''
381
+ else
382
+ '.%0*d' % [n, (f / Rational(1, 10**n)).round]
383
+ end
384
+ end
385
+ =end
386
+
387
+ def self.num_pattern? (s) # :nodoc:
388
+ /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
389
+ end
390
+
391
+ private_class_method :num_pattern?
392
+
393
+ def self._strptime_i(str, fmt, e) # :nodoc:
394
+ fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c|
395
+ a = $&
396
+ if s
397
+ case s
398
+ when 'A', 'a'
399
+ return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
400
+ str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
401
+ val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
402
+ return unless val
403
+ e.wday = val
404
+ when 'B', 'b', 'h'
405
+ return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
406
+ str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
407
+ val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
408
+ return unless val
409
+ e.mon = val
410
+ when 'C', 'EC'
411
+ return unless str.sub!(if num_pattern?($')
412
+ then /\A([-+]?\d{1,2})/
413
+ else /\A([-+]?\d{1,})/
414
+ end, '')
415
+ val = $1.to_i
416
+ e._cent = val
417
+ when 'c', 'Ec'
418
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
419
+ when 'D'
420
+ return unless _strptime_i(str, '%m/%d/%y', e)
421
+ when 'd', 'e', 'Od', 'Oe'
422
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
423
+ val = $1.to_i
424
+ return unless (1..31) === val
425
+ e.mday = val
426
+ when 'F'
427
+ return unless _strptime_i(str, '%Y-%m-%d', e)
428
+ when 'G'
429
+ return unless str.sub!(if num_pattern?($')
430
+ then /\A([-+]?\d{1,4})/
431
+ else /\A([-+]?\d{1,})/
432
+ end, '')
433
+ val = $1.to_i
434
+ e.cwyear = val
435
+ when 'g'
436
+ return unless str.sub!(/\A(\d{1,2})/, '')
437
+ val = $1.to_i
438
+ return unless (0..99) === val
439
+ e.cwyear = val
440
+ e._cent ||= if val >= 69 then 19 else 20 end
441
+ when 'H', 'k', 'OH'
442
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
443
+ val = $1.to_i
444
+ return unless (0..24) === val
445
+ e.hour = val
446
+ when 'I', 'l', 'OI'
447
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
448
+ val = $1.to_i
449
+ return unless (1..12) === val
450
+ e.hour = val
451
+ when 'j'
452
+ return unless str.sub!(/\A(\d{1,3})/, '')
453
+ val = $1.to_i
454
+ return unless (1..366) === val
455
+ e.yday = val
456
+ when 'L'
457
+ return unless str.sub!(if num_pattern?($')
458
+ then /\A([-+]?\d{1,3})/
459
+ else /\A([-+]?\d{1,})/
460
+ end, '')
461
+ # val = Rational($1.to_i, 10**3)
462
+ val = Rational($1.to_i, 10**$1.size)
463
+ e.sec_fraction = val
464
+ when 'M', 'OM'
465
+ return unless str.sub!(/\A(\d{1,2})/, '')
466
+ val = $1.to_i
467
+ return unless (0..59) === val
468
+ e.min = val
469
+ when 'm', 'Om'
470
+ return unless str.sub!(/\A(\d{1,2})/, '')
471
+ val = $1.to_i
472
+ return unless (1..12) === val
473
+ e.mon = val
474
+ when 'N'
475
+ return unless str.sub!(if num_pattern?($')
476
+ then /\A([-+]?\d{1,9})/
477
+ else /\A([-+]?\d{1,})/
478
+ end, '')
479
+ # val = Rational($1.to_i, 10**9)
480
+ val = Rational($1.to_i, 10**$1.size)
481
+ e.sec_fraction = val
482
+ when 'n', 't'
483
+ return unless _strptime_i(str, "\s", e)
484
+ when 'P', 'p'
485
+ return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
486
+ e._merid = if $1.downcase == 'a' then 0 else 12 end
487
+ when 'Q'
488
+ return unless str.sub!(/\A(-?\d{1,})/, '')
489
+ val = Rational($1.to_i, 10**3)
490
+ e.seconds = val
491
+ when 'R'
492
+ return unless _strptime_i(str, '%H:%M', e)
493
+ when 'r'
494
+ return unless _strptime_i(str, '%I:%M:%S %p', e)
495
+ when 'S', 'OS'
496
+ return unless str.sub!(/\A(\d{1,2})/, '')
497
+ val = $1.to_i
498
+ return unless (0..60) === val
499
+ e.sec = val
500
+ when 's'
501
+ return unless str.sub!(/\A(-?\d{1,})/, '')
502
+ val = $1.to_i
503
+ e.seconds = val
504
+ when 'T'
505
+ return unless _strptime_i(str, '%H:%M:%S', e)
506
+ when 'U', 'W', 'OU', 'OW'
507
+ return unless str.sub!(/\A(\d{1,2})/, '')
508
+ val = $1.to_i
509
+ return unless (0..53) === val
510
+ e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val)
511
+ when 'u', 'Ou'
512
+ return unless str.sub!(/\A(\d{1})/, '')
513
+ val = $1.to_i
514
+ return unless (1..7) === val
515
+ e.cwday = val
516
+ when 'V', 'OV'
517
+ return unless str.sub!(/\A(\d{1,2})/, '')
518
+ val = $1.to_i
519
+ return unless (1..53) === val
520
+ e.cweek = val
521
+ when 'v'
522
+ return unless _strptime_i(str, '%e-%b-%Y', e)
523
+ when 'w'
524
+ return unless str.sub!(/\A(\d{1})/, '')
525
+ val = $1.to_i
526
+ return unless (0..6) === val
527
+ e.wday = val
528
+ when 'X', 'EX'
529
+ return unless _strptime_i(str, '%H:%M:%S', e)
530
+ when 'x', 'Ex'
531
+ return unless _strptime_i(str, '%m/%d/%y', e)
532
+ when 'Y', 'EY'
533
+ return unless str.sub!(if num_pattern?($')
534
+ then /\A([-+]?\d{1,4})/
535
+ else /\A([-+]?\d{1,})/
536
+ end, '')
537
+ val = $1.to_i
538
+ e.year = val
539
+ when 'y', 'Ey', 'Oy'
540
+ return unless str.sub!(/\A(\d{1,2})/, '')
541
+ val = $1.to_i
542
+ return unless (0..99) === val
543
+ e.year = val
544
+ e._cent ||= if val >= 69 then 19 else 20 end
545
+ when 'Z', /\A:{0,3}z/
546
+ return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
547
+ |[[:alpha:].\s]+(?:standard|daylight)\s+time\b
548
+ |[[:alpha:]]+(?:\s+dst)?\b
549
+ )/ix, '')
550
+ val = $1
551
+ e.zone = val
552
+ offset = zone_to_diff(val)
553
+ e.offset = offset
554
+ when '%'
555
+ return unless str.sub!(/\A%/, '')
556
+ when '+'
557
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
558
+ else
559
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
560
+ end
561
+ else
562
+ case c
563
+ when /\A\s/
564
+ str.sub!(/\A\s+/, '')
565
+ else
566
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
567
+ end
568
+ end
569
+ end
570
+ end
571
+
572
+ private_class_method :_strptime_i
573
+
574
+ def self._strptime(str, fmt='%F')
575
+ str = str.dup
576
+ e = Format::Bag.new
577
+ return unless _strptime_i(str, fmt, e)
578
+
579
+ if e._cent
580
+ if e.cwyear
581
+ e.cwyear += e._cent * 100
582
+ end
583
+ if e.year
584
+ e. year += e._cent * 100
585
+ end
586
+ end
587
+
588
+ if e._merid
589
+ if e.hour
590
+ e.hour %= 12
591
+ e.hour += e._merid
592
+ end
593
+ end
594
+
595
+ unless str.empty?
596
+ e.leftover = str
597
+ end
598
+
599
+ e.to_hash
600
+ end
601
+
602
+ def self.s3e(e, y, m, d, bc=false)
603
+ unless String === m
604
+ m = m.to_s
605
+ end
606
+
607
+ if y && m && !d
608
+ y, m, d = d, y, m
609
+ end
610
+
611
+ if y == nil
612
+ if d && d.size > 2
613
+ y = d
614
+ d = nil
615
+ end
616
+ if d && d[0,1] == "'"
617
+ y = d
618
+ d = nil
619
+ end
620
+ end
621
+
622
+ if y
623
+ y.scan(/(\d+)(.+)?/)
624
+ if $2
625
+ y, d = d, $1
626
+ end
627
+ end
628
+
629
+ if m
630
+ if m[0,1] == "'" || m.size > 2
631
+ y, m, d = m, d, y # us -> be
632
+ end
633
+ end
634
+
635
+ if d
636
+ if d[0,1] == "'" || d.size > 2
637
+ y, d = d, y
638
+ end
639
+ end
640
+
641
+ if y
642
+ y =~ /([-+])?(\d+)/
643
+ if $1 || $2.size > 2
644
+ c = false
645
+ end
646
+ iy = $&.to_i
647
+ if bc
648
+ iy = -iy + 1
649
+ end
650
+ e.year = iy
651
+ end
652
+
653
+ if m
654
+ m =~ /\d+/
655
+ e.mon = $&.to_i
656
+ end
657
+
658
+ if d
659
+ d =~ /\d+/
660
+ e.mday = $&.to_i
661
+ end
662
+
663
+ if c != nil
664
+ e._comp = c
665
+ end
666
+
667
+ end
668
+
669
+ private_class_method :s3e
670
+
671
+ def self._parse_day(str, e) # :nodoc:
672
+ if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/io, ' ')
673
+ e.wday = Format::ABBR_DAYS[$1.downcase]
674
+ true
675
+ =begin
676
+ elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/i, ' ')
677
+ e.wday = %w(su mo tu we th fr sa).index($1.downcase)
678
+ true
679
+ =end
680
+ end
681
+ end
682
+
683
+ def self._parse_time(str, e) # :nodoc:
684
+ if str.sub!(
685
+ /(
686
+ (?:
687
+ \d+\s*:\s*\d+
688
+ (?:
689
+ \s*:\s*\d+(?:[,.]\d*)?
690
+ )?
691
+ |
692
+ \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
693
+ )
694
+ (?:
695
+ \s*
696
+ [ap](?:m\b|\.m\.)
697
+ )?
698
+ |
699
+ \d+\s*[ap](?:m\b|\.m\.)
700
+ )
701
+ (?:
702
+ \s*
703
+ (
704
+ (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
705
+ |
706
+ [[:alpha:].\s]+(?:standard|daylight)\stime\b
707
+ |
708
+ [[:alpha:]]+(?:\sdst)?\b
709
+ )
710
+ )?
711
+ /ix,
712
+ ' ')
713
+
714
+ t = $1
715
+ e.zone = $2 if $2
716
+
717
+ t =~ /\A(\d+)h?
718
+ (?:\s*:?\s*(\d+)m?
719
+ (?:
720
+ \s*:?\s*(\d+)(?:[,.](\d+))?s?
721
+ )?
722
+ )?
723
+ (?:\s*([ap])(?:m\b|\.m\.))?/ix
724
+
725
+ e.hour = $1.to_i
726
+ e.min = $2.to_i if $2
727
+ e.sec = $3.to_i if $3
728
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
729
+
730
+ if $5
731
+ e.hour %= 12
732
+ if $5.downcase == 'p'
733
+ e.hour += 12
734
+ end
735
+ end
736
+ true
737
+ end
738
+ end
739
+
740
+ =begin
741
+ def self._parse_beat(str, e) # :nodoc:
742
+ if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
743
+ beat = Rational($1.to_i)
744
+ beat += Rational($2.to_i, 10**$2.size) if $2
745
+ secs = Rational(beat, 1000)
746
+ h, min, s, fr = self.day_fraction_to_time(secs)
747
+ e.hour = h
748
+ e.min = min
749
+ e.sec = s
750
+ e.sec_fraction = fr * 86400
751
+ e.zone = '+01:00'
752
+ true
753
+ end
754
+ end
755
+ =end
756
+
757
+ def self._parse_eu(str, e) # :nodoc:
758
+ if str.sub!(
759
+ /'?(\d+)[^-\d\s]*
760
+ \s*
761
+ (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
762
+ (?:
763
+ \s*
764
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
765
+ \s*
766
+ ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
767
+ )?
768
+ /iox,
769
+ ' ') # '
770
+ s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
771
+ $3 && $3[0,1].downcase == 'b')
772
+ true
773
+ end
774
+ end
775
+
776
+ def self._parse_us(str, e) # :nodoc:
777
+ if str.sub!(
778
+ /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
779
+ \s*
780
+ ('?\d+)[^-\d\s']*
781
+ (?:
782
+ \s*
783
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
784
+ \s*
785
+ ('?-?\d+)
786
+ )?
787
+ /iox,
788
+ ' ') # '
789
+ s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
790
+ $3 && $3[0,1].downcase == 'b')
791
+ true
792
+ end
793
+ end
794
+
795
+ def self._parse_iso(str, e) # :nodoc:
796
+ if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/, ' ')
797
+ s3e(e, $1, $2, $3)
798
+ true
799
+ end
800
+ end
801
+
802
+ def self._parse_iso2(str, e) # :nodoc:
803
+ if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/i, ' ')
804
+ e.cwyear = $1.to_i if $1
805
+ e.cweek = $2.to_i
806
+ e.cwday = $3.to_i if $3
807
+ true
808
+ elsif str.sub!(/-w-(\d)\b/i, ' ')
809
+ e.cwday = $1.to_i
810
+ true
811
+ elsif str.sub!(/--(\d{2})?-(\d{2})\b/, ' ')
812
+ e.mon = $1.to_i if $1
813
+ e.mday = $2.to_i
814
+ true
815
+ elsif str.sub!(/--(\d{2})(\d{2})?\b/, ' ')
816
+ e.mon = $1.to_i
817
+ e.mday = $2.to_i if $2
818
+ true
819
+ elsif /[,.](\d{2}|\d{4})-\d{3}\b/ !~ str &&
820
+ str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/, ' ')
821
+ e.year = $1.to_i
822
+ e.yday = $2.to_i
823
+ true
824
+ elsif /\d-\d{3}\b/ !~ str &&
825
+ str.sub!(/\b-(\d{3})\b/, ' ')
826
+ e.yday = $1.to_i
827
+ true
828
+ end
829
+ end
830
+
831
+ def self._parse_jis(str, e) # :nodoc:
832
+ if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/i, ' ')
833
+ era = { 'm'=>1867,
834
+ 't'=>1911,
835
+ 's'=>1925,
836
+ 'h'=>1988
837
+ }[$1.downcase]
838
+ e.year = $2.to_i + era
839
+ e.mon = $3.to_i
840
+ e.mday = $4.to_i
841
+ true
842
+ end
843
+ end
844
+
845
+ def self._parse_vms(str, e) # :nodoc:
846
+ if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
847
+ -('?-?\d+)/iox, ' ')
848
+ s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
849
+ true
850
+ elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
851
+ -('?-?\d+)(?:-('?-?\d+))?/iox, ' ')
852
+ s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
853
+ true
854
+ end
855
+ end
856
+
857
+ def self._parse_sla(str, e) # :nodoc:
858
+ if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|, ' ') # '
859
+ s3e(e, $1, $2, $3)
860
+ true
861
+ end
862
+ end
863
+
864
+ def self._parse_dot(str, e) # :nodoc:
865
+ if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|, ' ') # '
866
+ s3e(e, $1, $2, $3)
867
+ true
868
+ end
869
+ end
870
+
871
+ def self._parse_year(str, e) # :nodoc:
872
+ if str.sub!(/'(\d+)\b/, ' ')
873
+ e.year = $1.to_i
874
+ true
875
+ end
876
+ end
877
+
878
+ def self._parse_mon(str, e) # :nodoc:
879
+ if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/io, ' ')
880
+ e.mon = Format::ABBR_MONTHS[$1.downcase]
881
+ true
882
+ end
883
+ end
884
+
885
+ def self._parse_mday(str, e) # :nodoc:
886
+ if str.sub!(/(\d+)(st|nd|rd|th)\b/i, ' ')
887
+ e.mday = $1.to_i
888
+ true
889
+ end
890
+ end
891
+
892
+ def self._parse_ddd(str, e) # :nodoc:
893
+ if str.sub!(
894
+ /([-+]?)(\d{2,14})
895
+ (?:
896
+ \s*
897
+ t?
898
+ \s*
899
+ (\d{2,6})?(?:[,.](\d*))?
900
+ )?
901
+ (?:
902
+ \s*
903
+ (
904
+ z\b
905
+ |
906
+ [-+]\d{1,4}\b
907
+ |
908
+ \[[-+]?\d[^\]]*\]
909
+ )
910
+ )?
911
+ /ix,
912
+ ' ')
913
+ case $2.size
914
+ when 2
915
+ if $3.nil? && $4
916
+ e.sec = $2[-2, 2].to_i
917
+ else
918
+ e.mday = $2[ 0, 2].to_i
919
+ end
920
+ when 4
921
+ if $3.nil? && $4
922
+ e.sec = $2[-2, 2].to_i
923
+ e.min = $2[-4, 2].to_i
924
+ else
925
+ e.mon = $2[ 0, 2].to_i
926
+ e.mday = $2[ 2, 2].to_i
927
+ end
928
+ when 6
929
+ if $3.nil? && $4
930
+ e.sec = $2[-2, 2].to_i
931
+ e.min = $2[-4, 2].to_i
932
+ e.hour = $2[-6, 2].to_i
933
+ else
934
+ e.year = ($1 + $2[ 0, 2]).to_i
935
+ e.mon = $2[ 2, 2].to_i
936
+ e.mday = $2[ 4, 2].to_i
937
+ end
938
+ when 8, 10, 12, 14
939
+ if $3.nil? && $4
940
+ e.sec = $2[-2, 2].to_i
941
+ e.min = $2[-4, 2].to_i
942
+ e.hour = $2[-6, 2].to_i
943
+ e.mday = $2[-8, 2].to_i
944
+ if $2.size >= 10
945
+ e.mon = $2[-10, 2].to_i
946
+ end
947
+ if $2.size == 12
948
+ e.year = ($1 + $2[-12, 2]).to_i
949
+ end
950
+ if $2.size == 14
951
+ e.year = ($1 + $2[-14, 4]).to_i
952
+ e._comp = false
953
+ end
954
+ else
955
+ e.year = ($1 + $2[ 0, 4]).to_i
956
+ e.mon = $2[ 4, 2].to_i
957
+ e.mday = $2[ 6, 2].to_i
958
+ e.hour = $2[ 8, 2].to_i if $2.size >= 10
959
+ e.min = $2[10, 2].to_i if $2.size >= 12
960
+ e.sec = $2[12, 2].to_i if $2.size >= 14
961
+ e._comp = false
962
+ end
963
+ when 3
964
+ if $3.nil? && $4
965
+ e.sec = $2[-2, 2].to_i
966
+ e.min = $2[-3, 1].to_i
967
+ else
968
+ e.yday = $2[ 0, 3].to_i
969
+ end
970
+ when 5
971
+ if $3.nil? && $4
972
+ e.sec = $2[-2, 2].to_i
973
+ e.min = $2[-4, 2].to_i
974
+ e.hour = $2[-5, 1].to_i
975
+ else
976
+ e.year = ($1 + $2[ 0, 2]).to_i
977
+ e.yday = $2[ 2, 3].to_i
978
+ end
979
+ when 7
980
+ if $3.nil? && $4
981
+ e.sec = $2[-2, 2].to_i
982
+ e.min = $2[-4, 2].to_i
983
+ e.hour = $2[-6, 2].to_i
984
+ e.mday = $2[-7, 1].to_i
985
+ else
986
+ e.year = ($1 + $2[ 0, 4]).to_i
987
+ e.yday = $2[ 4, 3].to_i
988
+ end
989
+ end
990
+ if $3
991
+ if $4
992
+ case $3.size
993
+ when 2, 4, 6
994
+ e.sec = $3[-2, 2].to_i
995
+ e.min = $3[-4, 2].to_i if $3.size >= 4
996
+ e.hour = $3[-6, 2].to_i if $3.size >= 6
997
+ end
998
+ else
999
+ case $3.size
1000
+ when 2, 4, 6
1001
+ e.hour = $3[ 0, 2].to_i
1002
+ e.min = $3[ 2, 2].to_i if $3.size >= 4
1003
+ e.sec = $3[ 4, 2].to_i if $3.size >= 6
1004
+ end
1005
+ end
1006
+ end
1007
+ if $4
1008
+ e.sec_fraction = Rational($4.to_i, 10**$4.size)
1009
+ end
1010
+ if $5
1011
+ e.zone = $5
1012
+ if e.zone[0,1] == '['
1013
+ o, n, = e.zone[1..-2].split(':')
1014
+ e.zone = n || o
1015
+ if /\A\d/ =~ o
1016
+ o = format('+%s', o)
1017
+ end
1018
+ e.offset = zone_to_diff(o)
1019
+ end
1020
+ end
1021
+ true
1022
+ end
1023
+ end
1024
+
1025
+ private_class_method :_parse_day, :_parse_time, # :_parse_beat,
1026
+ :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
1027
+ :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
1028
+ :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
1029
+
1030
+ def self._parse(str, comp=true)
1031
+ str = str.dup
1032
+
1033
+ e = Format::Bag.new
1034
+
1035
+ e._comp = comp
1036
+
1037
+ str.gsub!(/[^-+',.\/:@[:alnum:]\[\]]+/, ' ')
1038
+
1039
+ _parse_time(str, e) # || _parse_beat(str, e)
1040
+ _parse_day(str, e)
1041
+
1042
+ _parse_eu(str, e) ||
1043
+ _parse_us(str, e) ||
1044
+ _parse_iso(str, e) ||
1045
+ _parse_jis(str, e) ||
1046
+ _parse_vms(str, e) ||
1047
+ _parse_sla(str, e) ||
1048
+ _parse_dot(str, e) ||
1049
+ _parse_iso2(str, e) ||
1050
+ _parse_year(str, e) ||
1051
+ _parse_mon(str, e) ||
1052
+ _parse_mday(str, e) ||
1053
+ _parse_ddd(str, e)
1054
+
1055
+ if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/i, ' ')
1056
+ if e.year
1057
+ e.year = -e.year + 1
1058
+ end
1059
+ end
1060
+
1061
+ if str.sub!(/\A\s*(\d{1,2})\s*\z/, ' ')
1062
+ if e.hour && !e.mday
1063
+ v = $1.to_i
1064
+ if (1..31) === v
1065
+ e.mday = v
1066
+ end
1067
+ end
1068
+ if e.mday && !e.hour
1069
+ v = $1.to_i
1070
+ if (0..24) === v
1071
+ e.hour = v
1072
+ end
1073
+ end
1074
+ end
1075
+
1076
+ if e._comp
1077
+ if e.cwyear
1078
+ if e.cwyear >= 0 && e.cwyear <= 99
1079
+ e.cwyear += if e.cwyear >= 69
1080
+ then 1900 else 2000 end
1081
+ end
1082
+ end
1083
+ if e.year
1084
+ if e.year >= 0 && e.year <= 99
1085
+ e.year += if e.year >= 69
1086
+ then 1900 else 2000 end
1087
+ end
1088
+ end
1089
+ end
1090
+
1091
+ e.offset ||= zone_to_diff(e.zone) if e.zone
1092
+
1093
+ e.to_hash
1094
+ end
1095
+
1096
+ def self._iso8601(str) # :nodoc:
1097
+ if /\A\s*(([-+]?\d{2,}|-)-\d{2}-\d{2}|
1098
+ ([-+]?\d{2,})?-\d{3}|
1099
+ (\d{2}|\d{4})?-w\d{2}-\d|
1100
+ -w-\d)
1101
+ (t
1102
+ \d{2}:\d{2}(:\d{2}([,.]\d+)?)?
1103
+ (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
1104
+ _parse(str)
1105
+ elsif /\A\s*(([-+]?(\d{2}|\d{4})|--)\d{2}\d{2}|
1106
+ ([-+]?(\d{2}|\d{4}))?\d{3}|-\d{3}|
1107
+ (\d{2}|\d{4})?w\d{2}\d)
1108
+ (t?
1109
+ \d{2}\d{2}(\d{2}([,.]\d+)?)?
1110
+ (z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
1111
+ _parse(str)
1112
+ elsif /\A\s*(\d{2}:\d{2}(:\d{2}([,.]\d+)?)?
1113
+ (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
1114
+ _parse(str)
1115
+ elsif /\A\s*(\d{2}\d{2}(\d{2}([,.]\d+)?)?
1116
+ (z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
1117
+ _parse(str)
1118
+ end
1119
+ end
1120
+
1121
+ def self._rfc3339(str) # :nodoc:
1122
+ if /\A\s*-?\d{4}-\d{2}-\d{2} # allow minus, anyway
1123
+ (t|\s)
1124
+ \d{2}:\d{2}:\d{2}(\.\d+)?
1125
+ (z|[-+]\d{2}:\d{2})\s*\z/ix =~ str
1126
+ _parse(str)
1127
+ end
1128
+ end
1129
+
1130
+ def self._xmlschema(str) # :nodoc:
1131
+ if /\A\s*(-?\d{4,})(?:-(\d{2})(?:-(\d{2}))?)?
1132
+ (?:t
1133
+ (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
1134
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1135
+ e = Format::Bag.new
1136
+ e.year = $1.to_i
1137
+ e.mon = $2.to_i if $2
1138
+ e.mday = $3.to_i if $3
1139
+ e.hour = $4.to_i if $4
1140
+ e.min = $5.to_i if $5
1141
+ e.sec = $6.to_i if $6
1142
+ e.sec_fraction = Rational($7.to_i, 10**$7.size) if $7
1143
+ if $8
1144
+ e.zone = $8
1145
+ e.offset = zone_to_diff($8)
1146
+ end
1147
+ e.to_hash
1148
+ elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
1149
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1150
+ e = Format::Bag.new
1151
+ e.hour = $1.to_i if $1
1152
+ e.min = $2.to_i if $2
1153
+ e.sec = $3.to_i if $3
1154
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
1155
+ if $5
1156
+ e.zone = $5
1157
+ e.offset = zone_to_diff($5)
1158
+ end
1159
+ e.to_hash
1160
+ elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
1161
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1162
+ e = Format::Bag.new
1163
+ e.mon = $1.to_i if $1
1164
+ e.mday = $2.to_i if $2
1165
+ e.mday = $3.to_i if $3
1166
+ if $4
1167
+ e.zone = $4
1168
+ e.offset = zone_to_diff($4)
1169
+ end
1170
+ e.to_hash
1171
+ end
1172
+ end
1173
+
1174
+ def self._rfc2822(str) # :nodoc:
1175
+ if /\A\s*(?:(?:#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+)?
1176
+ \d{1,2}\s+
1177
+ (?:#{Format::ABBR_MONTHS.keys.join('|')})\s+
1178
+ -?(\d{2,})\s+ # allow minus, anyway
1179
+ \d{2}:\d{2}(:\d{2})?\s*
1180
+ (?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/iox =~ str
1181
+ e = _parse(str, false)
1182
+ if $1.size < 4
1183
+ if e[:year] < 50
1184
+ e[:year] += 2000
1185
+ elsif e[:year] < 1000
1186
+ e[:year] += 1900
1187
+ end
1188
+ end
1189
+ e
1190
+ end
1191
+ end
1192
+
1193
+ class << self; alias_method :_rfc822, :_rfc2822 end
1194
+
1195
+ def self._httpdate(str) # :nodoc:
1196
+ if /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+
1197
+ \d{2}\s+
1198
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1199
+ -?\d{4}\s+ # allow minus, anyway
1200
+ \d{2}:\d{2}:\d{2}\s+
1201
+ gmt\s*\z/iox =~ str
1202
+ _rfc2822(str)
1203
+ elsif /\A\s*(#{Format::DAYS.keys.join('|')})\s*,\s+
1204
+ \d{2}\s*-\s*
1205
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s*-\s*
1206
+ \d{2}\s+
1207
+ \d{2}:\d{2}:\d{2}\s+
1208
+ gmt\s*\z/iox =~ str
1209
+ _parse(str)
1210
+ elsif /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s+
1211
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1212
+ \d{1,2}\s+
1213
+ \d{2}:\d{2}:\d{2}\s+
1214
+ \d{4}\s*\z/iox =~ str
1215
+ _parse(str)
1216
+ end
1217
+ end
1218
+
1219
+ def self._jisx0301(str) # :nodoc:
1220
+ if /\A\s*[mtsh]?\d{2}\.\d{2}\.\d{2}
1221
+ (t
1222
+ (\d{2}:\d{2}(:\d{2}([,.]\d*)?)?
1223
+ (z|[-+]\d{2}(:?\d{2})?)?)?)?\s*\z/ix =~ str
1224
+ if /\A\s*\d/ =~ str
1225
+ _parse(str.sub(/\A\s*(\d)/, 'h\1'))
1226
+ else
1227
+ _parse(str)
1228
+ end
1229
+ else
1230
+ _iso8601(str)
1231
+ end
1232
+ end
1233
+
1234
+ t = Module.new do
1235
+
1236
+ private
1237
+
1238
+ def zone_to_diff(zone) # :nodoc:
1239
+ zone = zone.downcase
1240
+ if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
1241
+ dst = $1 == 'daylight'
1242
+ else
1243
+ dst = zone.sub!(/\s+dst\z/, '')
1244
+ end
1245
+ if Format::ZONES.include?(zone)
1246
+ offset = Format::ZONES[zone]
1247
+ offset += 3600 if dst
1248
+ elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
1249
+ sign = $1
1250
+ if zone.include?(':')
1251
+ hour, min, sec, = zone.split(':')
1252
+ elsif zone.include?(',') || zone.include?('.')
1253
+ hour, fr, = zone.split(/[,.]/)
1254
+ min = Rational(fr.to_i, 10**fr.size) * 60
1255
+ else
1256
+ case zone.size
1257
+ when 3
1258
+ hour = zone[0,1]
1259
+ min = zone[1,2]
1260
+ else
1261
+ hour = zone[0,2]
1262
+ min = zone[2,2]
1263
+ sec = zone[4,2]
1264
+ end
1265
+ end
1266
+ offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
1267
+ offset *= -1 if sign == '-'
1268
+ end
1269
+ offset
1270
+ end
1271
+
1272
+ end
1273
+
1274
+ extend t
1275
+ include t
1276
+
1277
+ end
1278
+
1279
+ class DateTime < Date
1280
+
1281
+ def strftime(fmt='%FT%T%:z')
1282
+ super(fmt)
1283
+ end
1284
+
1285
+ def self._strptime(str, fmt='%FT%T%z')
1286
+ super(str, fmt)
1287
+ end
1288
+
1289
+ def iso8601_timediv(n) # :nodoc:
1290
+ strftime('T%T' +
1291
+ if n < 1
1292
+ ''
1293
+ else
1294
+ '.%0*d' % [n, (sec_fraction / Rational(1, 10**n)).round]
1295
+ end +
1296
+ '%:z')
1297
+ end
1298
+
1299
+ private :iso8601_timediv
1300
+
1301
+ def iso8601(n=0)
1302
+ super() + iso8601_timediv(n)
1303
+ end
1304
+
1305
+ def rfc3339(n=0) iso8601(n) end
1306
+
1307
+ def xmlschema(n=0) iso8601(n) end # :nodoc:
1308
+
1309
+ def jisx0301(n=0)
1310
+ super() + iso8601_timediv(n)
1311
+ end
1312
+
1313
+ end