motion-date 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1316 @@
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
+ # XXX this is required in MacRuby otherwise it conflicts with NSObject#zone
134
+ def zone; @elem[:zone]; end
135
+ def zone=(z); @elem[:zone]=z; end
136
+ end
137
+
138
+ end
139
+
140
+ def emit(e, f) # :nodoc:
141
+ case e
142
+ when Numeric
143
+ sign = %w(+ + -)[e <=> 0]
144
+ e = e.abs
145
+ end
146
+
147
+ s = e.to_s
148
+
149
+ if f[:s] && f[:p] == '0'
150
+ f[:w] -= 1
151
+ end
152
+
153
+ if f[:s] && f[:p] == "\s"
154
+ s[0,0] = sign
155
+ end
156
+
157
+ if f[:p] != '-'
158
+ s = s.rjust(f[:w], f[:p])
159
+ end
160
+
161
+ if f[:s] && f[:p] != "\s"
162
+ s[0,0] = sign
163
+ end
164
+
165
+ s = s.upcase if f[:u]
166
+ s = s.downcase if f[:d]
167
+ s
168
+ end
169
+
170
+ def emit_w(e, w, f) # :nodoc:
171
+ f[:w] = [f[:w], w].compact.max
172
+ emit(e, f)
173
+ end
174
+
175
+ def emit_n(e, w, f) # :nodoc:
176
+ f[:p] ||= '0'
177
+ emit_w(e, w, f)
178
+ end
179
+
180
+ def emit_sn(e, w, f) # :nodoc:
181
+ if e < 0
182
+ w += 1
183
+ f[:s] = true
184
+ end
185
+ emit_n(e, w, f)
186
+ end
187
+
188
+ def emit_z(e, w, f) # :nodoc:
189
+ w += 1
190
+ f[:s] = true
191
+ emit_n(e, w, f)
192
+ end
193
+
194
+ def emit_a(e, w, f) # :nodoc:
195
+ f[:p] ||= "\s"
196
+ emit_w(e, w, f)
197
+ end
198
+
199
+ def emit_ad(e, w, f) # :nodoc:
200
+ if f[:x]
201
+ f[:u] = true
202
+ f[:d] = false
203
+ end
204
+ emit_a(e, w, f)
205
+ end
206
+
207
+ def emit_au(e, w, f) # :nodoc:
208
+ if f[:x]
209
+ f[:u] = false
210
+ f[:d] = true
211
+ end
212
+ emit_a(e, w, f)
213
+ end
214
+
215
+ private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
216
+ :emit_a, :emit_ad, :emit_au
217
+
218
+ def strftime(fmt='%F')
219
+ fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do
220
+ f = {}
221
+ m = $&
222
+ s, w, c = $1, $2, $3
223
+ if s
224
+ s.scan(/./) do |k|
225
+ case k
226
+ when '-'; f[:p] = '-'
227
+ when '_'; f[:p] = "\s"
228
+ when '0'; f[:p] = '0'
229
+ when '^'; f[:u] = true
230
+ when '#'; f[:x] = true
231
+ end
232
+ end
233
+ end
234
+ if w
235
+ f[:w] = w.to_i
236
+ end
237
+ case c
238
+ when 'A'; emit_ad(DAYNAMES[wday], 0, f)
239
+ when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
240
+ when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
241
+ when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
242
+ when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
243
+ when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
244
+ when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
245
+ when 'd', 'Od'; emit_n(mday, 2, f)
246
+ when 'e', 'Oe'; emit_a(mday, 2, f)
247
+ when 'F'
248
+ if m == '%F'
249
+ format('%.4d-%02d-%02d', year, mon, mday) # 4p
250
+ else
251
+ emit_a(strftime('%Y-%m-%d'), 0, f)
252
+ end
253
+ when 'G'; emit_sn(cwyear, 4, f)
254
+ when 'g'; emit_n(cwyear % 100, 2, f)
255
+ when 'H', 'OH'; emit_n(hour, 2, f)
256
+ when 'h'; emit_ad(strftime('%b'), 0, f)
257
+ when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
258
+ when 'j'; emit_n(yday, 3, f)
259
+ when 'k'; emit_a(hour, 2, f)
260
+ when 'L'
261
+ f[:p] = nil
262
+ w = f[:w] || 3
263
+ u = 10**w
264
+ emit_n((sec_fraction * u).floor, w, f)
265
+ when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
266
+ when 'M', 'OM'; emit_n(min, 2, f)
267
+ when 'm', 'Om'; emit_n(mon, 2, f)
268
+ when 'N'
269
+ f[:p] = nil
270
+ w = f[:w] || 9
271
+ u = 10**w
272
+ emit_n((sec_fraction * u).floor, w, f)
273
+ when 'n'; emit_a("\n", 0, f)
274
+ when 'P'; emit_ad(strftime('%p').downcase, 0, f)
275
+ when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
276
+ when 'Q'
277
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
278
+ emit_sn(s, 1, f)
279
+ when 'R'; emit_a(strftime('%H:%M'), 0, f)
280
+ when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
281
+ when 'S', 'OS'; emit_n(sec, 2, f)
282
+ when 's'
283
+ s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
284
+ emit_sn(s, 1, f)
285
+ when 'T'
286
+ if m == '%T'
287
+ format('%02d:%02d:%02d', hour, min, sec) # 4p
288
+ else
289
+ emit_a(strftime('%H:%M:%S'), 0, f)
290
+ end
291
+ when 't'; emit_a("\t", 0, f)
292
+ when 'U', 'W', 'OU', 'OW'
293
+ emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
294
+ when 'u', 'Ou'; emit_n(cwday, 1, f)
295
+ when 'V', 'OV'; emit_n(cweek, 2, f)
296
+ when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
297
+ when 'w', 'Ow'; emit_n(wday, 1, f)
298
+ when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
299
+ when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
300
+ when 'Y', 'EY'; emit_sn(year, 4, f)
301
+ when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
302
+ when 'Z'; emit_au(strftime('%:z'), 0, f)
303
+ when /\A(:{0,3})z/
304
+ t = $1.size
305
+ sign = if offset < 0 then -1 else +1 end
306
+ fr = offset.abs
307
+ ss = fr.div(SECONDS_IN_DAY) # 4p
308
+ hh, ss = ss.divmod(3600)
309
+ mm, ss = ss.divmod(60)
310
+ if t == 3
311
+ if ss.nonzero? then t = 2
312
+ elsif mm.nonzero? then t = 1
313
+ else t = -1
314
+ end
315
+ end
316
+ case t
317
+ when -1
318
+ tail = []
319
+ sep = ''
320
+ when 0
321
+ f[:w] -= 2 if f[:w]
322
+ tail = ['%02d' % mm]
323
+ sep = ''
324
+ when 1
325
+ f[:w] -= 3 if f[:w]
326
+ tail = ['%02d' % mm]
327
+ sep = ':'
328
+ when 2
329
+ f[:w] -= 6 if f[:w]
330
+ tail = ['%02d' % mm, '%02d' % ss]
331
+ sep = ':'
332
+ end
333
+ ([emit_z(sign * hh, 2, f)] + tail).join(sep)
334
+ when '%'; emit_a('%', 0, f)
335
+ when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
336
+ else
337
+ m
338
+ end
339
+ end
340
+ end
341
+
342
+ # alias_method :format, :strftime
343
+
344
+ def asctime() strftime('%c') end
345
+
346
+ alias_method :ctime, :asctime
347
+
348
+ def iso8601() strftime('%F') end
349
+
350
+ def rfc3339() iso8601 end
351
+
352
+ def xmlschema() iso8601 end # :nodoc:
353
+
354
+ def rfc2822() strftime('%a, %-d %b %Y %T %z') end
355
+
356
+ alias_method :rfc822, :rfc2822
357
+
358
+ def httpdate() new_offset(0).strftime('%a, %d %b %Y %T GMT') end # :nodoc:
359
+
360
+ def jisx0301
361
+ if jd < 2405160
362
+ iso8601
363
+ else
364
+ case jd
365
+ when 2405160...2419614
366
+ g = 'M%02d' % (year - 1867)
367
+ when 2419614...2424875
368
+ g = 'T%02d' % (year - 1911)
369
+ when 2424875...2447535
370
+ g = 'S%02d' % (year - 1925)
371
+ else
372
+ g = 'H%02d' % (year - 1988)
373
+ end
374
+ g + strftime('.%m.%d')
375
+ end
376
+ end
377
+
378
+ =begin
379
+ def beat(n=0)
380
+ i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
381
+ ('@%03d' % i) +
382
+ if n < 1
383
+ ''
384
+ else
385
+ '.%0*d' % [n, (f / Rational(1, 10**n)).round]
386
+ end
387
+ end
388
+ =end
389
+
390
+ def self.num_pattern? (s) # :nodoc:
391
+ /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
392
+ end
393
+
394
+ private_class_method :num_pattern?
395
+
396
+ def self._strptime_i(str, fmt, e) # :nodoc:
397
+ fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c|
398
+ a = $&
399
+ if s
400
+ case s
401
+ when 'A', 'a'
402
+ return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
403
+ str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
404
+ val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
405
+ return unless val
406
+ e.wday = val
407
+ when 'B', 'b', 'h'
408
+ return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
409
+ str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
410
+ val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
411
+ return unless val
412
+ e.mon = val
413
+ when 'C', 'EC'
414
+ return unless str.sub!(if num_pattern?($')
415
+ then /\A([-+]?\d{1,2})/
416
+ else /\A([-+]?\d{1,})/
417
+ end, '')
418
+ val = $1.to_i
419
+ e._cent = val
420
+ when 'c', 'Ec'
421
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
422
+ when 'D'
423
+ return unless _strptime_i(str, '%m/%d/%y', e)
424
+ when 'd', 'e', 'Od', 'Oe'
425
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
426
+ val = $1.to_i
427
+ return unless (1..31) === val
428
+ e.mday = val
429
+ when 'F'
430
+ return unless _strptime_i(str, '%Y-%m-%d', e)
431
+ when 'G'
432
+ return unless str.sub!(if num_pattern?($')
433
+ then /\A([-+]?\d{1,4})/
434
+ else /\A([-+]?\d{1,})/
435
+ end, '')
436
+ val = $1.to_i
437
+ e.cwyear = val
438
+ when 'g'
439
+ return unless str.sub!(/\A(\d{1,2})/, '')
440
+ val = $1.to_i
441
+ return unless (0..99) === val
442
+ e.cwyear = val
443
+ e._cent ||= if val >= 69 then 19 else 20 end
444
+ when 'H', 'k', 'OH'
445
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
446
+ val = $1.to_i
447
+ return unless (0..24) === val
448
+ e.hour = val
449
+ when 'I', 'l', 'OI'
450
+ return unless str.sub!(/\A( \d|\d{1,2})/, '')
451
+ val = $1.to_i
452
+ return unless (1..12) === val
453
+ e.hour = val
454
+ when 'j'
455
+ return unless str.sub!(/\A(\d{1,3})/, '')
456
+ val = $1.to_i
457
+ return unless (1..366) === val
458
+ e.yday = val
459
+ when 'L'
460
+ return unless str.sub!(if num_pattern?($')
461
+ then /\A([-+]?\d{1,3})/
462
+ else /\A([-+]?\d{1,})/
463
+ end, '')
464
+ # val = Rational($1.to_i, 10**3)
465
+ val = Rational($1.to_i, 10**$1.size)
466
+ e.sec_fraction = val
467
+ when 'M', 'OM'
468
+ return unless str.sub!(/\A(\d{1,2})/, '')
469
+ val = $1.to_i
470
+ return unless (0..59) === val
471
+ e.min = val
472
+ when 'm', 'Om'
473
+ return unless str.sub!(/\A(\d{1,2})/, '')
474
+ val = $1.to_i
475
+ return unless (1..12) === val
476
+ e.mon = val
477
+ when 'N'
478
+ return unless str.sub!(if num_pattern?($')
479
+ then /\A([-+]?\d{1,9})/
480
+ else /\A([-+]?\d{1,})/
481
+ end, '')
482
+ # val = Rational($1.to_i, 10**9)
483
+ val = Rational($1.to_i, 10**$1.size)
484
+ e.sec_fraction = val
485
+ when 'n', 't'
486
+ return unless _strptime_i(str, "\s", e)
487
+ when 'P', 'p'
488
+ return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
489
+ e._merid = if $1.downcase == 'a' then 0 else 12 end
490
+ when 'Q'
491
+ return unless str.sub!(/\A(-?\d{1,})/, '')
492
+ val = Rational($1.to_i, 10**3)
493
+ e.seconds = val
494
+ when 'R'
495
+ return unless _strptime_i(str, '%H:%M', e)
496
+ when 'r'
497
+ return unless _strptime_i(str, '%I:%M:%S %p', e)
498
+ when 'S', 'OS'
499
+ return unless str.sub!(/\A(\d{1,2})/, '')
500
+ val = $1.to_i
501
+ return unless (0..60) === val
502
+ e.sec = val
503
+ when 's'
504
+ return unless str.sub!(/\A(-?\d{1,})/, '')
505
+ val = $1.to_i
506
+ e.seconds = val
507
+ when 'T'
508
+ return unless _strptime_i(str, '%H:%M:%S', e)
509
+ when 'U', 'W', 'OU', 'OW'
510
+ return unless str.sub!(/\A(\d{1,2})/, '')
511
+ val = $1.to_i
512
+ return unless (0..53) === val
513
+ e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val)
514
+ when 'u', 'Ou'
515
+ return unless str.sub!(/\A(\d{1})/, '')
516
+ val = $1.to_i
517
+ return unless (1..7) === val
518
+ e.cwday = val
519
+ when 'V', 'OV'
520
+ return unless str.sub!(/\A(\d{1,2})/, '')
521
+ val = $1.to_i
522
+ return unless (1..53) === val
523
+ e.cweek = val
524
+ when 'v'
525
+ return unless _strptime_i(str, '%e-%b-%Y', e)
526
+ when 'w'
527
+ return unless str.sub!(/\A(\d{1})/, '')
528
+ val = $1.to_i
529
+ return unless (0..6) === val
530
+ e.wday = val
531
+ when 'X', 'EX'
532
+ return unless _strptime_i(str, '%H:%M:%S', e)
533
+ when 'x', 'Ex'
534
+ return unless _strptime_i(str, '%m/%d/%y', e)
535
+ when 'Y', 'EY'
536
+ return unless str.sub!(if num_pattern?($')
537
+ then /\A([-+]?\d{1,4})/
538
+ else /\A([-+]?\d{1,})/
539
+ end, '')
540
+ val = $1.to_i
541
+ e.year = val
542
+ when 'y', 'Ey', 'Oy'
543
+ return unless str.sub!(/\A(\d{1,2})/, '')
544
+ val = $1.to_i
545
+ return unless (0..99) === val
546
+ e.year = val
547
+ e._cent ||= if val >= 69 then 19 else 20 end
548
+ when 'Z', /\A:{0,3}z/
549
+ return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
550
+ |[[:alpha:].\s]+(?:standard|daylight)\s+time\b
551
+ |[[:alpha:]]+(?:\s+dst)?\b
552
+ )/ix, '')
553
+ val = $1
554
+ e.zone = val
555
+ offset = zone_to_diff(val)
556
+ e.offset = offset
557
+ when '%'
558
+ return unless str.sub!(/\A%/, '')
559
+ when '+'
560
+ return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
561
+ else
562
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
563
+ end
564
+ else
565
+ case c
566
+ when /\A\s/
567
+ str.sub!(/\A\s+/, '')
568
+ else
569
+ return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
570
+ end
571
+ end
572
+ end
573
+ end
574
+
575
+ private_class_method :_strptime_i
576
+
577
+ def self._strptime(str, fmt='%F')
578
+ str = str.dup
579
+ e = Format::Bag.new
580
+ return unless _strptime_i(str, fmt, e)
581
+
582
+ if e._cent
583
+ if e.cwyear
584
+ e.cwyear += e._cent * 100
585
+ end
586
+ if e.year
587
+ e. year += e._cent * 100
588
+ end
589
+ end
590
+
591
+ if e._merid
592
+ if e.hour
593
+ e.hour %= 12
594
+ e.hour += e._merid
595
+ end
596
+ end
597
+
598
+ unless str.empty?
599
+ e.leftover = str
600
+ end
601
+
602
+ e.to_hash
603
+ end
604
+
605
+ def self.s3e(e, y, m, d, bc=false)
606
+ unless String === m
607
+ m = m.to_s
608
+ end
609
+
610
+ if y && m && !d
611
+ y, m, d = d, y, m
612
+ end
613
+
614
+ if y == nil
615
+ if d && d.size > 2
616
+ y = d
617
+ d = nil
618
+ end
619
+ if d && d[0,1] == "'"
620
+ y = d
621
+ d = nil
622
+ end
623
+ end
624
+
625
+ if y
626
+ y.scan(/(\d+)(.+)?/)
627
+ if $2
628
+ y, d = d, $1
629
+ end
630
+ end
631
+
632
+ if m
633
+ if m[0,1] == "'" || m.size > 2
634
+ y, m, d = m, d, y # us -> be
635
+ end
636
+ end
637
+
638
+ if d
639
+ if d[0,1] == "'" || d.size > 2
640
+ y, d = d, y
641
+ end
642
+ end
643
+
644
+ if y
645
+ y =~ /([-+])?(\d+)/
646
+ if $1 || $2.size > 2
647
+ c = false
648
+ end
649
+ iy = $&.to_i
650
+ if bc
651
+ iy = -iy + 1
652
+ end
653
+ e.year = iy
654
+ end
655
+
656
+ if m
657
+ m =~ /\d+/
658
+ e.mon = $&.to_i
659
+ end
660
+
661
+ if d
662
+ d =~ /\d+/
663
+ e.mday = $&.to_i
664
+ end
665
+
666
+ if c != nil
667
+ e._comp = c
668
+ end
669
+
670
+ end
671
+
672
+ private_class_method :s3e
673
+
674
+ def self._parse_day(str, e) # :nodoc:
675
+ if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/io, ' ')
676
+ e.wday = Format::ABBR_DAYS[$1.downcase]
677
+ true
678
+ =begin
679
+ elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/i, ' ')
680
+ e.wday = %w(su mo tu we th fr sa).index($1.downcase)
681
+ true
682
+ =end
683
+ end
684
+ end
685
+
686
+ def self._parse_time(str, e) # :nodoc:
687
+ if str.sub!(
688
+ /(
689
+ (?:
690
+ \d+\s*:\s*\d+
691
+ (?:
692
+ \s*:\s*\d+(?:[,.]\d*)?
693
+ )?
694
+ |
695
+ \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
696
+ )
697
+ (?:
698
+ \s*
699
+ [ap](?:m\b|\.m\.)
700
+ )?
701
+ |
702
+ \d+\s*[ap](?:m\b|\.m\.)
703
+ )
704
+ (?:
705
+ \s*
706
+ (
707
+ (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
708
+ |
709
+ [[:alpha:].\s]+(?:standard|daylight)\stime\b
710
+ |
711
+ [[:alpha:]]+(?:\sdst)?\b
712
+ )
713
+ )?
714
+ /ix,
715
+ ' ')
716
+
717
+ t = $1
718
+ e.zone = $2 if $2
719
+
720
+ t =~ /\A(\d+)h?
721
+ (?:\s*:?\s*(\d+)m?
722
+ (?:
723
+ \s*:?\s*(\d+)(?:[,.](\d+))?s?
724
+ )?
725
+ )?
726
+ (?:\s*([ap])(?:m\b|\.m\.))?/ix
727
+
728
+ e.hour = $1.to_i
729
+ e.min = $2.to_i if $2
730
+ e.sec = $3.to_i if $3
731
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
732
+
733
+ if $5
734
+ e.hour %= 12
735
+ if $5.downcase == 'p'
736
+ e.hour += 12
737
+ end
738
+ end
739
+ true
740
+ end
741
+ end
742
+
743
+ =begin
744
+ def self._parse_beat(str, e) # :nodoc:
745
+ if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
746
+ beat = Rational($1.to_i)
747
+ beat += Rational($2.to_i, 10**$2.size) if $2
748
+ secs = Rational(beat, 1000)
749
+ h, min, s, fr = self.day_fraction_to_time(secs)
750
+ e.hour = h
751
+ e.min = min
752
+ e.sec = s
753
+ e.sec_fraction = fr * 86400
754
+ e.zone = '+01:00'
755
+ true
756
+ end
757
+ end
758
+ =end
759
+
760
+ def self._parse_eu(str, e) # :nodoc:
761
+ if str.sub!(
762
+ /'?(\d+)[^-\d\s]*
763
+ \s*
764
+ (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
765
+ (?:
766
+ \s*
767
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
768
+ \s*
769
+ ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
770
+ )?
771
+ /iox,
772
+ ' ') # '
773
+ s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
774
+ $3 && $3[0,1].downcase == 'b')
775
+ true
776
+ end
777
+ end
778
+
779
+ def self._parse_us(str, e) # :nodoc:
780
+ if str.sub!(
781
+ /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
782
+ \s*
783
+ ('?\d+)[^-\d\s']*
784
+ (?:
785
+ \s*
786
+ (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
787
+ \s*
788
+ ('?-?\d+)
789
+ )?
790
+ /iox,
791
+ ' ') # '
792
+ s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
793
+ $3 && $3[0,1].downcase == 'b')
794
+ true
795
+ end
796
+ end
797
+
798
+ def self._parse_iso(str, e) # :nodoc:
799
+ if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/, ' ')
800
+ s3e(e, $1, $2, $3)
801
+ true
802
+ end
803
+ end
804
+
805
+ def self._parse_iso2(str, e) # :nodoc:
806
+ if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/i, ' ')
807
+ e.cwyear = $1.to_i if $1
808
+ e.cweek = $2.to_i
809
+ e.cwday = $3.to_i if $3
810
+ true
811
+ elsif str.sub!(/-w-(\d)\b/i, ' ')
812
+ e.cwday = $1.to_i
813
+ true
814
+ elsif str.sub!(/--(\d{2})?-(\d{2})\b/, ' ')
815
+ e.mon = $1.to_i if $1
816
+ e.mday = $2.to_i
817
+ true
818
+ elsif str.sub!(/--(\d{2})(\d{2})?\b/, ' ')
819
+ e.mon = $1.to_i
820
+ e.mday = $2.to_i if $2
821
+ true
822
+ elsif /[,.](\d{2}|\d{4})-\d{3}\b/ !~ str &&
823
+ str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/, ' ')
824
+ e.year = $1.to_i
825
+ e.yday = $2.to_i
826
+ true
827
+ elsif /\d-\d{3}\b/ !~ str &&
828
+ str.sub!(/\b-(\d{3})\b/, ' ')
829
+ e.yday = $1.to_i
830
+ true
831
+ end
832
+ end
833
+
834
+ def self._parse_jis(str, e) # :nodoc:
835
+ if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/i, ' ')
836
+ era = { 'm'=>1867,
837
+ 't'=>1911,
838
+ 's'=>1925,
839
+ 'h'=>1988
840
+ }[$1.downcase]
841
+ e.year = $2.to_i + era
842
+ e.mon = $3.to_i
843
+ e.mday = $4.to_i
844
+ true
845
+ end
846
+ end
847
+
848
+ def self._parse_vms(str, e) # :nodoc:
849
+ if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
850
+ -('?-?\d+)/iox, ' ')
851
+ s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
852
+ true
853
+ elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
854
+ -('?-?\d+)(?:-('?-?\d+))?/iox, ' ')
855
+ s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
856
+ true
857
+ end
858
+ end
859
+
860
+ def self._parse_sla(str, e) # :nodoc:
861
+ if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|, ' ') # '
862
+ s3e(e, $1, $2, $3)
863
+ true
864
+ end
865
+ end
866
+
867
+ def self._parse_dot(str, e) # :nodoc:
868
+ if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|, ' ') # '
869
+ s3e(e, $1, $2, $3)
870
+ true
871
+ end
872
+ end
873
+
874
+ def self._parse_year(str, e) # :nodoc:
875
+ if str.sub!(/'(\d+)\b/, ' ')
876
+ e.year = $1.to_i
877
+ true
878
+ end
879
+ end
880
+
881
+ def self._parse_mon(str, e) # :nodoc:
882
+ if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/io, ' ')
883
+ e.mon = Format::ABBR_MONTHS[$1.downcase]
884
+ true
885
+ end
886
+ end
887
+
888
+ def self._parse_mday(str, e) # :nodoc:
889
+ if str.sub!(/(\d+)(st|nd|rd|th)\b/i, ' ')
890
+ e.mday = $1.to_i
891
+ true
892
+ end
893
+ end
894
+
895
+ def self._parse_ddd(str, e) # :nodoc:
896
+ if str.sub!(
897
+ /([-+]?)(\d{2,14})
898
+ (?:
899
+ \s*
900
+ t?
901
+ \s*
902
+ (\d{2,6})?(?:[,.](\d*))?
903
+ )?
904
+ (?:
905
+ \s*
906
+ (
907
+ z\b
908
+ |
909
+ [-+]\d{1,4}\b
910
+ |
911
+ \[[-+]?\d[^\]]*\]
912
+ )
913
+ )?
914
+ /ix,
915
+ ' ')
916
+ case $2.size
917
+ when 2
918
+ if $3.nil? && $4
919
+ e.sec = $2[-2, 2].to_i
920
+ else
921
+ e.mday = $2[ 0, 2].to_i
922
+ end
923
+ when 4
924
+ if $3.nil? && $4
925
+ e.sec = $2[-2, 2].to_i
926
+ e.min = $2[-4, 2].to_i
927
+ else
928
+ e.mon = $2[ 0, 2].to_i
929
+ e.mday = $2[ 2, 2].to_i
930
+ end
931
+ when 6
932
+ if $3.nil? && $4
933
+ e.sec = $2[-2, 2].to_i
934
+ e.min = $2[-4, 2].to_i
935
+ e.hour = $2[-6, 2].to_i
936
+ else
937
+ e.year = ($1 + $2[ 0, 2]).to_i
938
+ e.mon = $2[ 2, 2].to_i
939
+ e.mday = $2[ 4, 2].to_i
940
+ end
941
+ when 8, 10, 12, 14
942
+ if $3.nil? && $4
943
+ e.sec = $2[-2, 2].to_i
944
+ e.min = $2[-4, 2].to_i
945
+ e.hour = $2[-6, 2].to_i
946
+ e.mday = $2[-8, 2].to_i
947
+ if $2.size >= 10
948
+ e.mon = $2[-10, 2].to_i
949
+ end
950
+ if $2.size == 12
951
+ e.year = ($1 + $2[-12, 2]).to_i
952
+ end
953
+ if $2.size == 14
954
+ e.year = ($1 + $2[-14, 4]).to_i
955
+ e._comp = false
956
+ end
957
+ else
958
+ e.year = ($1 + $2[ 0, 4]).to_i
959
+ e.mon = $2[ 4, 2].to_i
960
+ e.mday = $2[ 6, 2].to_i
961
+ e.hour = $2[ 8, 2].to_i if $2.size >= 10
962
+ e.min = $2[10, 2].to_i if $2.size >= 12
963
+ e.sec = $2[12, 2].to_i if $2.size >= 14
964
+ e._comp = false
965
+ end
966
+ when 3
967
+ if $3.nil? && $4
968
+ e.sec = $2[-2, 2].to_i
969
+ e.min = $2[-3, 1].to_i
970
+ else
971
+ e.yday = $2[ 0, 3].to_i
972
+ end
973
+ when 5
974
+ if $3.nil? && $4
975
+ e.sec = $2[-2, 2].to_i
976
+ e.min = $2[-4, 2].to_i
977
+ e.hour = $2[-5, 1].to_i
978
+ else
979
+ e.year = ($1 + $2[ 0, 2]).to_i
980
+ e.yday = $2[ 2, 3].to_i
981
+ end
982
+ when 7
983
+ if $3.nil? && $4
984
+ e.sec = $2[-2, 2].to_i
985
+ e.min = $2[-4, 2].to_i
986
+ e.hour = $2[-6, 2].to_i
987
+ e.mday = $2[-7, 1].to_i
988
+ else
989
+ e.year = ($1 + $2[ 0, 4]).to_i
990
+ e.yday = $2[ 4, 3].to_i
991
+ end
992
+ end
993
+ if $3
994
+ if $4
995
+ case $3.size
996
+ when 2, 4, 6
997
+ e.sec = $3[-2, 2].to_i
998
+ e.min = $3[-4, 2].to_i if $3.size >= 4
999
+ e.hour = $3[-6, 2].to_i if $3.size >= 6
1000
+ end
1001
+ else
1002
+ case $3.size
1003
+ when 2, 4, 6
1004
+ e.hour = $3[ 0, 2].to_i
1005
+ e.min = $3[ 2, 2].to_i if $3.size >= 4
1006
+ e.sec = $3[ 4, 2].to_i if $3.size >= 6
1007
+ end
1008
+ end
1009
+ end
1010
+ if $4
1011
+ e.sec_fraction = Rational($4.to_i, 10**$4.size)
1012
+ end
1013
+ if $5
1014
+ e.zone = $5
1015
+ if e.zone[0,1] == '['
1016
+ o, n, = e.zone[1..-2].split(':')
1017
+ e.zone = n || o
1018
+ if /\A\d/ =~ o
1019
+ o = format('+%s', o)
1020
+ end
1021
+ e.offset = zone_to_diff(o)
1022
+ end
1023
+ end
1024
+ true
1025
+ end
1026
+ end
1027
+
1028
+ private_class_method :_parse_day, :_parse_time, # :_parse_beat,
1029
+ :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
1030
+ :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
1031
+ :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
1032
+
1033
+ def self._parse(str, comp=true)
1034
+ str = str.dup
1035
+
1036
+ e = Format::Bag.new
1037
+
1038
+ e._comp = comp
1039
+
1040
+ str.gsub!(/[^-+',.\/:@[:alnum:]\[\]]+/, ' ')
1041
+
1042
+ _parse_time(str, e) # || _parse_beat(str, e)
1043
+ _parse_day(str, e)
1044
+
1045
+ _parse_eu(str, e) ||
1046
+ _parse_us(str, e) ||
1047
+ _parse_iso(str, e) ||
1048
+ _parse_jis(str, e) ||
1049
+ _parse_vms(str, e) ||
1050
+ _parse_sla(str, e) ||
1051
+ _parse_dot(str, e) ||
1052
+ _parse_iso2(str, e) ||
1053
+ _parse_year(str, e) ||
1054
+ _parse_mon(str, e) ||
1055
+ _parse_mday(str, e) ||
1056
+ _parse_ddd(str, e)
1057
+
1058
+ if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/i, ' ')
1059
+ if e.year
1060
+ e.year = -e.year + 1
1061
+ end
1062
+ end
1063
+
1064
+ if str.sub!(/\A\s*(\d{1,2})\s*\z/, ' ')
1065
+ if e.hour && !e.mday
1066
+ v = $1.to_i
1067
+ if (1..31) === v
1068
+ e.mday = v
1069
+ end
1070
+ end
1071
+ if e.mday && !e.hour
1072
+ v = $1.to_i
1073
+ if (0..24) === v
1074
+ e.hour = v
1075
+ end
1076
+ end
1077
+ end
1078
+
1079
+ if e._comp
1080
+ if e.cwyear
1081
+ if e.cwyear >= 0 && e.cwyear <= 99
1082
+ e.cwyear += if e.cwyear >= 69
1083
+ then 1900 else 2000 end
1084
+ end
1085
+ end
1086
+ if e.year
1087
+ if e.year >= 0 && e.year <= 99
1088
+ e.year += if e.year >= 69
1089
+ then 1900 else 2000 end
1090
+ end
1091
+ end
1092
+ end
1093
+
1094
+ e.offset ||= zone_to_diff(e.zone) if e.zone
1095
+
1096
+ e.to_hash
1097
+ end
1098
+
1099
+ def self._iso8601(str) # :nodoc:
1100
+ if /\A\s*(([-+]?\d{2,}|-)-\d{2}-\d{2}|
1101
+ ([-+]?\d{2,})?-\d{3}|
1102
+ (\d{2}|\d{4})?-w\d{2}-\d|
1103
+ -w-\d)
1104
+ (t
1105
+ \d{2}:\d{2}(:\d{2}([,.]\d+)?)?
1106
+ (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
1107
+ _parse(str)
1108
+ elsif /\A\s*(([-+]?(\d{2}|\d{4})|--)\d{2}\d{2}|
1109
+ ([-+]?(\d{2}|\d{4}))?\d{3}|-\d{3}|
1110
+ (\d{2}|\d{4})?w\d{2}\d)
1111
+ (t?
1112
+ \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
+ elsif /\A\s*(\d{2}\d{2}(\d{2}([,.]\d+)?)?
1119
+ (z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
1120
+ _parse(str)
1121
+ end
1122
+ end
1123
+
1124
+ def self._rfc3339(str) # :nodoc:
1125
+ if /\A\s*-?\d{4}-\d{2}-\d{2} # allow minus, anyway
1126
+ (t|\s)
1127
+ \d{2}:\d{2}:\d{2}(\.\d+)?
1128
+ (z|[-+]\d{2}:\d{2})\s*\z/ix =~ str
1129
+ _parse(str)
1130
+ end
1131
+ end
1132
+
1133
+ def self._xmlschema(str) # :nodoc:
1134
+ if /\A\s*(-?\d{4,})(?:-(\d{2})(?:-(\d{2}))?)?
1135
+ (?:t
1136
+ (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
1137
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1138
+ e = Format::Bag.new
1139
+ e.year = $1.to_i
1140
+ e.mon = $2.to_i if $2
1141
+ e.mday = $3.to_i if $3
1142
+ e.hour = $4.to_i if $4
1143
+ e.min = $5.to_i if $5
1144
+ e.sec = $6.to_i if $6
1145
+ e.sec_fraction = Rational($7.to_i, 10**$7.size) if $7
1146
+ if $8
1147
+ e.zone = $8
1148
+ e.offset = zone_to_diff($8)
1149
+ end
1150
+ e.to_hash
1151
+ elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
1152
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1153
+ e = Format::Bag.new
1154
+ e.hour = $1.to_i if $1
1155
+ e.min = $2.to_i if $2
1156
+ e.sec = $3.to_i if $3
1157
+ e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
1158
+ if $5
1159
+ e.zone = $5
1160
+ e.offset = zone_to_diff($5)
1161
+ end
1162
+ e.to_hash
1163
+ elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
1164
+ (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
1165
+ e = Format::Bag.new
1166
+ e.mon = $1.to_i if $1
1167
+ e.mday = $2.to_i if $2
1168
+ e.mday = $3.to_i if $3
1169
+ if $4
1170
+ e.zone = $4
1171
+ e.offset = zone_to_diff($4)
1172
+ end
1173
+ e.to_hash
1174
+ end
1175
+ end
1176
+
1177
+ def self._rfc2822(str) # :nodoc:
1178
+ if /\A\s*(?:(?:#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+)?
1179
+ \d{1,2}\s+
1180
+ (?:#{Format::ABBR_MONTHS.keys.join('|')})\s+
1181
+ -?(\d{2,})\s+ # allow minus, anyway
1182
+ \d{2}:\d{2}(:\d{2})?\s*
1183
+ (?:[-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/iox =~ str
1184
+ e = _parse(str, false)
1185
+ if (($1.nil?) || ($1.size < 4))
1186
+ if e[:year] < 50
1187
+ e[:year] += 2000
1188
+ elsif e[:year] < 1000
1189
+ e[:year] += 1900
1190
+ end
1191
+ end
1192
+ e
1193
+ end
1194
+ end
1195
+
1196
+ class << self; alias_method :_rfc822, :_rfc2822 end
1197
+
1198
+ def self._httpdate(str) # :nodoc:
1199
+ if /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+
1200
+ \d{2}\s+
1201
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1202
+ -?\d{4}\s+ # allow minus, anyway
1203
+ \d{2}:\d{2}:\d{2}\s+
1204
+ gmt\s*\z/iox =~ str
1205
+ _rfc2822(str)
1206
+ elsif /\A\s*(#{Format::DAYS.keys.join('|')})\s*,\s+
1207
+ \d{2}\s*-\s*
1208
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s*-\s*
1209
+ \d{2}\s+
1210
+ \d{2}:\d{2}:\d{2}\s+
1211
+ gmt\s*\z/iox =~ str
1212
+ _parse(str)
1213
+ elsif /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s+
1214
+ (#{Format::ABBR_MONTHS.keys.join('|')})\s+
1215
+ \d{1,2}\s+
1216
+ \d{2}:\d{2}:\d{2}\s+
1217
+ \d{4}\s*\z/iox =~ str
1218
+ _parse(str)
1219
+ end
1220
+ end
1221
+
1222
+ def self._jisx0301(str) # :nodoc:
1223
+ if /\A\s*[mtsh]?\d{2}\.\d{2}\.\d{2}
1224
+ (t
1225
+ (\d{2}:\d{2}(:\d{2}([,.]\d*)?)?
1226
+ (z|[-+]\d{2}(:?\d{2})?)?)?)?\s*\z/ix =~ str
1227
+ if /\A\s*\d/ =~ str
1228
+ _parse(str.sub(/\A\s*(\d)/, 'h\1'))
1229
+ else
1230
+ _parse(str)
1231
+ end
1232
+ else
1233
+ _iso8601(str)
1234
+ end
1235
+ end
1236
+
1237
+ t = Module.new do
1238
+
1239
+ private
1240
+
1241
+ def zone_to_diff(zone) # :nodoc:
1242
+ zone = zone.downcase
1243
+ if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
1244
+ dst = $1 == 'daylight'
1245
+ else
1246
+ dst = zone.sub!(/\s+dst\z/, '')
1247
+ end
1248
+ if Format::ZONES.include?(zone)
1249
+ offset = Format::ZONES[zone]
1250
+ offset += 3600 if dst
1251
+ elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
1252
+ sign = $1
1253
+ if zone.include?(':')
1254
+ hour, min, sec, = zone.split(':')
1255
+ elsif zone.include?(',') || zone.include?('.')
1256
+ hour, fr, = zone.split(/[,.]/)
1257
+ min = Rational(fr.to_i, 10**fr.size) * 60
1258
+ else
1259
+ case zone.size
1260
+ when 3
1261
+ hour = zone[0,1]
1262
+ min = zone[1,2]
1263
+ else
1264
+ hour = zone[0,2]
1265
+ min = zone[2,2]
1266
+ sec = zone[4,2]
1267
+ end
1268
+ end
1269
+ offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
1270
+ offset *= -1 if sign == '-'
1271
+ end
1272
+ offset
1273
+ end
1274
+
1275
+ end
1276
+
1277
+ extend t
1278
+ include t
1279
+
1280
+ end
1281
+
1282
+ class DateTime < Date
1283
+
1284
+ def strftime(fmt='%FT%T%:z')
1285
+ super(fmt)
1286
+ end
1287
+
1288
+ def self._strptime(str, fmt='%FT%T%z')
1289
+ super(str, fmt)
1290
+ end
1291
+
1292
+ def iso8601_timediv(n) # :nodoc:
1293
+ strftime('T%T' +
1294
+ if n < 1
1295
+ ''
1296
+ else
1297
+ '.%0*d' % [n, (sec_fraction / Rational(1, 10**n)).round]
1298
+ end +
1299
+ '%:z')
1300
+ end
1301
+
1302
+ private :iso8601_timediv
1303
+
1304
+ def iso8601(n=0)
1305
+ super() + iso8601_timediv(n)
1306
+ end
1307
+
1308
+ def rfc3339(n=0) iso8601(n) end
1309
+
1310
+ def xmlschema(n=0) iso8601(n) end # :nodoc:
1311
+
1312
+ def jisx0301(n=0)
1313
+ super() + iso8601_timediv(n)
1314
+ end
1315
+
1316
+ end