/tools/Ruby/lib/ruby/1.8/date/format.rb

http://github.com/agross/netopenspace · Ruby · 1190 lines · 1027 code · 78 blank · 85 comment · 123 complexity · 5564383d7f6ba5332b5233e71213f3a6 MD5 · raw file

  1. # format.rb: Written by Tadayoshi Funaba 1999-2008
  2. # $Id: format.rb,v 2.43 2008-01-17 20:16:31+09 tadf Exp $
  3. require 'rational'
  4. class Date
  5. module Format # :nodoc:
  6. MONTHS = {
  7. 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
  8. 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
  9. 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
  10. }
  11. DAYS = {
  12. 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
  13. 'thursday' => 4, 'friday' => 5, 'saturday' => 6
  14. }
  15. ABBR_MONTHS = {
  16. 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
  17. 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
  18. 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
  19. }
  20. ABBR_DAYS = {
  21. 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
  22. 'thu' => 4, 'fri' => 5, 'sat' => 6
  23. }
  24. ZONES = {
  25. 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
  26. 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
  27. 'pst' => -8*3600, 'pdt' => -7*3600,
  28. 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
  29. 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
  30. 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
  31. 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
  32. 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
  33. 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
  34. 'z' => 0*3600,
  35. 'utc' => 0*3600, 'wet' => 0*3600,
  36. 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800),
  37. 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600,
  38. 'nst' => -(3*3600+1800),
  39. 'ast' => -4*3600, 'clt' => -4*3600,
  40. 'akdt'=> -8*3600, 'ydt' => -8*3600,
  41. 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600,
  42. 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600,
  43. 'nt' =>-11*3600,
  44. 'idlw'=>-12*3600,
  45. 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600,
  46. 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600,
  47. 'west'=> 1*3600,
  48. 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600,
  49. 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600,
  50. 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600,
  51. 'msd' => 4*3600, 'zp4' => 4*3600,
  52. 'zp5' => 5*3600, 'ist' => (5*3600+1800),
  53. 'zp6' => 6*3600,
  54. 'wast'=> 7*3600,
  55. 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600,
  56. 'jst' => 9*3600, 'kst' => 9*3600,
  57. 'east'=> 10*3600, 'gst' => 10*3600,
  58. 'eadt'=> 11*3600,
  59. 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600,
  60. 'nzdt'=> 13*3600,
  61. 'afghanistan' => 16200, 'alaskan' => -32400,
  62. 'arab' => 10800, 'arabian' => 14400,
  63. 'arabic' => 10800, 'atlantic' => -14400,
  64. 'aus central' => 34200, 'aus eastern' => 36000,
  65. 'azores' => -3600, 'canada central' => -21600,
  66. 'cape verde' => -3600, 'caucasus' => 14400,
  67. 'cen. australia' => 34200, 'central america' => -21600,
  68. 'central asia' => 21600, 'central europe' => 3600,
  69. 'central european' => 3600, 'central pacific' => 39600,
  70. 'central' => -21600, 'china' => 28800,
  71. 'dateline' => -43200, 'e. africa' => 10800,
  72. 'e. australia' => 36000, 'e. europe' => 7200,
  73. 'e. south america' => -10800, 'eastern' => -18000,
  74. 'egypt' => 7200, 'ekaterinburg' => 18000,
  75. 'fiji' => 43200, 'fle' => 7200,
  76. 'greenland' => -10800, 'greenwich' => 0,
  77. 'gtb' => 7200, 'hawaiian' => -36000,
  78. 'india' => 19800, 'iran' => 12600,
  79. 'jerusalem' => 7200, 'korea' => 32400,
  80. 'mexico' => -21600, 'mid-atlantic' => -7200,
  81. 'mountain' => -25200, 'myanmar' => 23400,
  82. 'n. central asia' => 21600, 'nepal' => 20700,
  83. 'new zealand' => 43200, 'newfoundland' => -12600,
  84. 'north asia east' => 28800, 'north asia' => 25200,
  85. 'pacific sa' => -14400, 'pacific' => -28800,
  86. 'romance' => 3600, 'russian' => 10800,
  87. 'sa eastern' => -10800, 'sa pacific' => -18000,
  88. 'sa western' => -14400, 'samoa' => -39600,
  89. 'se asia' => 25200, 'malay peninsula' => 28800,
  90. 'south africa' => 7200, 'sri lanka' => 21600,
  91. 'taipei' => 28800, 'tasmania' => 36000,
  92. 'tokyo' => 32400, 'tonga' => 46800,
  93. 'us eastern' => -18000, 'us mountain' => -25200,
  94. 'vladivostok' => 36000, 'w. australia' => 28800,
  95. 'w. central africa' => 3600, 'w. europe' => 3600,
  96. 'west asia' => 18000, 'west pacific' => 36000,
  97. 'yakutsk' => 32400
  98. }
  99. [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
  100. x.freeze
  101. end
  102. class Bag # :nodoc:
  103. def initialize
  104. @elem = {}
  105. end
  106. def method_missing(t, *args, &block)
  107. t = t.to_s
  108. set = t.chomp!('=')
  109. t = t.intern
  110. if set
  111. @elem[t] = args[0]
  112. else
  113. @elem[t]
  114. end
  115. end
  116. def to_hash
  117. @elem.reject{|k, v| /\A_/ =~ k.to_s || v.nil?}
  118. end
  119. end
  120. end
  121. def emit(e, f) # :nodoc:
  122. case e
  123. when Numeric
  124. sign = %w(+ + -)[e <=> 0]
  125. e = e.abs
  126. end
  127. s = e.to_s
  128. if f[:s] && f[:p] == '0'
  129. f[:w] -= 1
  130. end
  131. if f[:s] && f[:p] == "\s"
  132. s[0,0] = sign
  133. end
  134. if f[:p] != '-'
  135. s = s.rjust(f[:w], f[:p])
  136. end
  137. if f[:s] && f[:p] != "\s"
  138. s[0,0] = sign
  139. end
  140. s = s.upcase if f[:u]
  141. s = s.downcase if f[:d]
  142. s
  143. end
  144. def emit_w(e, w, f) # :nodoc:
  145. f[:w] = [f[:w], w].compact.max
  146. emit(e, f)
  147. end
  148. def emit_n(e, w, f) # :nodoc:
  149. f[:p] ||= '0'
  150. emit_w(e, w, f)
  151. end
  152. def emit_sn(e, w, f) # :nodoc:
  153. if e < 0
  154. w += 1
  155. f[:s] = true
  156. end
  157. emit_n(e, w, f)
  158. end
  159. def emit_z(e, w, f) # :nodoc:
  160. w += 1
  161. f[:s] = true
  162. emit_n(e, w, f)
  163. end
  164. def emit_a(e, w, f) # :nodoc:
  165. f[:p] ||= "\s"
  166. emit_w(e, w, f)
  167. end
  168. def emit_ad(e, w, f) # :nodoc:
  169. if f[:x]
  170. f[:u] = true
  171. f[:d] = false
  172. end
  173. emit_a(e, w, f)
  174. end
  175. def emit_au(e, w, f) # :nodoc:
  176. if f[:x]
  177. f[:u] = false
  178. f[:d] = true
  179. end
  180. emit_a(e, w, f)
  181. end
  182. private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
  183. :emit_a, :emit_ad, :emit_au
  184. def strftime(fmt='%F')
  185. fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do |m|
  186. f = {}
  187. a = $&
  188. s, w, c = $1, $2, $3
  189. if s
  190. s.scan(/./) do |k|
  191. case k
  192. when '-'; f[:p] = '-'
  193. when '_'; f[:p] = "\s"
  194. when '0'; f[:p] = '0'
  195. when '^'; f[:u] = true
  196. when '#'; f[:x] = true
  197. end
  198. end
  199. end
  200. if w
  201. f[:w] = w.to_i
  202. end
  203. case c
  204. when 'A'; emit_ad(DAYNAMES[wday], 0, f)
  205. when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
  206. when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
  207. when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
  208. when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
  209. when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
  210. when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
  211. when 'd', 'Od'; emit_n(mday, 2, f)
  212. when 'e', 'Oe'; emit_a(mday, 2, f)
  213. when 'F'
  214. if m == '%F'
  215. format('%.4d-%02d-%02d', year, mon, mday) # 4p
  216. else
  217. emit_a(strftime('%Y-%m-%d'), 0, f)
  218. end
  219. when 'G'; emit_sn(cwyear, 4, f)
  220. when 'g'; emit_n(cwyear % 100, 2, f)
  221. when 'H', 'OH'; emit_n(hour, 2, f)
  222. when 'h'; emit_ad(strftime('%b'), 0, f)
  223. when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
  224. when 'j'; emit_n(yday, 3, f)
  225. when 'k'; emit_a(hour, 2, f)
  226. when 'L'
  227. emit_n((sec_fraction / MILLISECONDS_IN_DAY).floor, 3, f)
  228. when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
  229. when 'M', 'OM'; emit_n(min, 2, f)
  230. when 'm', 'Om'; emit_n(mon, 2, f)
  231. when 'N'
  232. emit_n((sec_fraction / NANOSECONDS_IN_DAY).floor, 9, f)
  233. when 'n'; "\n"
  234. when 'P'; emit_ad(strftime('%p').downcase, 0, f)
  235. when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
  236. when 'Q'
  237. s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
  238. emit_sn(s, 1, f)
  239. when 'R'; emit_a(strftime('%H:%M'), 0, f)
  240. when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
  241. when 'S', 'OS'; emit_n(sec, 2, f)
  242. when 's'
  243. s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
  244. emit_sn(s, 1, f)
  245. when 'T'
  246. if m == '%T'
  247. format('%02d:%02d:%02d', hour, min, sec) # 4p
  248. else
  249. emit_a(strftime('%H:%M:%S'), 0, f)
  250. end
  251. when 't'; "\t"
  252. when 'U', 'W', 'OU', 'OW'
  253. emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
  254. when 'u', 'Ou'; emit_n(cwday, 1, f)
  255. when 'V', 'OV'; emit_n(cweek, 2, f)
  256. when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
  257. when 'w', 'Ow'; emit_n(wday, 1, f)
  258. when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
  259. when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
  260. when 'Y', 'EY'; emit_sn(year, 4, f)
  261. when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
  262. when 'Z'; emit_au(strftime('%:z'), 0, f)
  263. when /\A(:{0,3})z/
  264. t = $1.size
  265. sign = if offset < 0 then -1 else +1 end
  266. fr = offset.abs
  267. ss = fr.div(SECONDS_IN_DAY) # 4p
  268. hh, ss = ss.divmod(3600)
  269. mm, ss = ss.divmod(60)
  270. if t == 3
  271. if ss.nonzero? then t = 2
  272. elsif mm.nonzero? then t = 1
  273. else t = -1
  274. end
  275. end
  276. case t
  277. when -1
  278. tail = []
  279. sep = ''
  280. when 0
  281. f[:w] -= 2 if f[:w]
  282. tail = ['%02d' % mm]
  283. sep = ''
  284. when 1
  285. f[:w] -= 3 if f[:w]
  286. tail = ['%02d' % mm]
  287. sep = ':'
  288. when 2
  289. f[:w] -= 6 if f[:w]
  290. tail = ['%02d' % mm, '%02d' % ss]
  291. sep = ':'
  292. end
  293. ([emit_z(sign * hh, 2, f)] + tail).join(sep)
  294. when '%'; emit_a('%', 0, f)
  295. when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
  296. when '1'
  297. if $VERBOSE
  298. warn("warning: strftime: %1 is deprecated; forget this")
  299. end
  300. emit_n(jd, 1, f)
  301. when '2'
  302. if $VERBOSE
  303. warn("warning: strftime: %2 is deprecated; use '%Y-%j'")
  304. end
  305. emit_a(strftime('%Y-%j'), 0, f)
  306. when '3'
  307. if $VERBOSE
  308. warn("warning: strftime: %3 is deprecated; use '%F'")
  309. end
  310. emit_a(strftime('%F'), 0, f)
  311. else
  312. a
  313. end
  314. end
  315. end
  316. # alias_method :format, :strftime
  317. def asctime() strftime('%c') end
  318. alias_method :ctime, :asctime
  319. =begin
  320. def iso8601() strftime('%F') end
  321. def rfc3339() iso8601 end
  322. def rfc2822() strftime('%a, %-d %b %Y %T %z') end
  323. alias_method :rfc822, :rfc2822
  324. def jisx0301
  325. if jd < 2405160
  326. iso8601
  327. else
  328. case jd
  329. when 2405160...2419614
  330. g = 'M%02d' % (year - 1867)
  331. when 2419614...2424875
  332. g = 'T%02d' % (year - 1911)
  333. when 2424875...2447535
  334. g = 'S%02d' % (year - 1925)
  335. else
  336. g = 'H%02d' % (year - 1988)
  337. end
  338. g + strftime('.%m.%d')
  339. end
  340. end
  341. def beat(n=0)
  342. i, f = (new_offset(HOURS_IN_DAY).day_fraction * 1000).divmod(1)
  343. ('@%03d' % i) +
  344. if n < 1
  345. ''
  346. else
  347. '.%0*d' % [n, (f / Rational(1, 10**n)).round]
  348. end
  349. end
  350. =end
  351. def self.num_pattern? (s) # :nodoc:
  352. /\A%[EO]?[CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy\d]/ =~ s || /\A\d/ =~ s
  353. end
  354. private_class_method :num_pattern?
  355. def self._strptime_i(str, fmt, e) # :nodoc:
  356. fmt.scan(/%([EO]?(?::{1,3}z|.))|(.)/m) do |s, c|
  357. a = $&
  358. if s
  359. case s
  360. when 'A', 'a'
  361. return unless str.sub!(/\A(#{Format::DAYS.keys.join('|')})/io, '') ||
  362. str.sub!(/\A(#{Format::ABBR_DAYS.keys.join('|')})/io, '')
  363. val = Format::DAYS[$1.downcase] || Format::ABBR_DAYS[$1.downcase]
  364. return unless val
  365. e.wday = val
  366. when 'B', 'b', 'h'
  367. return unless str.sub!(/\A(#{Format::MONTHS.keys.join('|')})/io, '') ||
  368. str.sub!(/\A(#{Format::ABBR_MONTHS.keys.join('|')})/io, '')
  369. val = Format::MONTHS[$1.downcase] || Format::ABBR_MONTHS[$1.downcase]
  370. return unless val
  371. e.mon = val
  372. when 'C', 'EC'
  373. return unless str.sub!(if num_pattern?($')
  374. then /\A([-+]?\d{1,2})/
  375. else /\A([-+]?\d{1,})/
  376. end, '')
  377. val = $1.to_i
  378. e._cent = val
  379. when 'c', 'Ec'
  380. return unless _strptime_i(str, '%a %b %e %H:%M:%S %Y', e)
  381. when 'D'
  382. return unless _strptime_i(str, '%m/%d/%y', e)
  383. when 'd', 'e', 'Od', 'Oe'
  384. return unless str.sub!(/\A( \d|\d{1,2})/, '')
  385. val = $1.to_i
  386. return unless (1..31) === val
  387. e.mday = val
  388. when 'F'
  389. return unless _strptime_i(str, '%Y-%m-%d', e)
  390. when 'G'
  391. return unless str.sub!(if num_pattern?($')
  392. then /\A([-+]?\d{1,4})/
  393. else /\A([-+]?\d{1,})/
  394. end, '')
  395. val = $1.to_i
  396. e.cwyear = val
  397. when 'g'
  398. return unless str.sub!(/\A(\d{1,2})/, '')
  399. val = $1.to_i
  400. return unless (0..99) === val
  401. e.cwyear = val
  402. e._cent ||= if val >= 69 then 19 else 20 end
  403. when 'H', 'k', 'OH'
  404. return unless str.sub!(/\A( \d|\d{1,2})/, '')
  405. val = $1.to_i
  406. return unless (0..24) === val
  407. e.hour = val
  408. when 'I', 'l', 'OI'
  409. return unless str.sub!(/\A( \d|\d{1,2})/, '')
  410. val = $1.to_i
  411. return unless (1..12) === val
  412. e.hour = val
  413. when 'j'
  414. return unless str.sub!(/\A(\d{1,3})/, '')
  415. val = $1.to_i
  416. return unless (1..366) === val
  417. e.yday = val
  418. when 'L'
  419. return unless str.sub!(if num_pattern?($')
  420. then /\A([-+]?\d{1,3})/
  421. else /\A([-+]?\d{1,})/
  422. end, '')
  423. # val = Rational($1.to_i, 10**3)
  424. val = Rational($1.to_i, 10**$1.size)
  425. e.sec_fraction = val
  426. when 'M', 'OM'
  427. return unless str.sub!(/\A(\d{1,2})/, '')
  428. val = $1.to_i
  429. return unless (0..59) === val
  430. e.min = val
  431. when 'm', 'Om'
  432. return unless str.sub!(/\A(\d{1,2})/, '')
  433. val = $1.to_i
  434. return unless (1..12) === val
  435. e.mon = val
  436. when 'N'
  437. return unless str.sub!(if num_pattern?($')
  438. then /\A([-+]?\d{1,9})/
  439. else /\A([-+]?\d{1,})/
  440. end, '')
  441. # val = Rational($1.to_i, 10**9)
  442. val = Rational($1.to_i, 10**$1.size)
  443. e.sec_fraction = val
  444. when 'n', 't'
  445. return unless _strptime_i(str, "\s", e)
  446. when 'P', 'p'
  447. return unless str.sub!(/\A([ap])(?:m\b|\.m\.)/i, '')
  448. e._merid = if $1.downcase == 'a' then 0 else 12 end
  449. when 'Q'
  450. return unless str.sub!(/\A(-?\d{1,})/, '')
  451. val = Rational($1.to_i, 10**3)
  452. e.seconds = val
  453. when 'R'
  454. return unless _strptime_i(str, '%H:%M', e)
  455. when 'r'
  456. return unless _strptime_i(str, '%I:%M:%S %p', e)
  457. when 'S', 'OS'
  458. return unless str.sub!(/\A(\d{1,2})/, '')
  459. val = $1.to_i
  460. return unless (0..60) === val
  461. e.sec = val
  462. when 's'
  463. return unless str.sub!(/\A(-?\d{1,})/, '')
  464. val = $1.to_i
  465. e.seconds = val
  466. when 'T'
  467. return unless _strptime_i(str, '%H:%M:%S', e)
  468. when 'U', 'W', 'OU', 'OW'
  469. return unless str.sub!(/\A(\d{1,2})/, '')
  470. val = $1.to_i
  471. return unless (0..53) === val
  472. e.__send__(if s[-1,1] == 'U' then :wnum0= else :wnum1= end, val)
  473. when 'u', 'Ou'
  474. return unless str.sub!(/\A(\d{1})/, '')
  475. val = $1.to_i
  476. return unless (1..7) === val
  477. e.cwday = val
  478. when 'V', 'OV'
  479. return unless str.sub!(/\A(\d{1,2})/, '')
  480. val = $1.to_i
  481. return unless (1..53) === val
  482. e.cweek = val
  483. when 'v'
  484. return unless _strptime_i(str, '%e-%b-%Y', e)
  485. when 'w'
  486. return unless str.sub!(/\A(\d{1})/, '')
  487. val = $1.to_i
  488. return unless (0..6) === val
  489. e.wday = val
  490. when 'X', 'EX'
  491. return unless _strptime_i(str, '%H:%M:%S', e)
  492. when 'x', 'Ex'
  493. return unless _strptime_i(str, '%m/%d/%y', e)
  494. when 'Y', 'EY'
  495. return unless str.sub!(if num_pattern?($')
  496. then /\A([-+]?\d{1,4})/
  497. else /\A([-+]?\d{1,})/
  498. end, '')
  499. val = $1.to_i
  500. e.year = val
  501. when 'y', 'Ey', 'Oy'
  502. return unless str.sub!(/\A(\d{1,2})/, '')
  503. val = $1.to_i
  504. return unless (0..99) === val
  505. e.year = val
  506. e._cent ||= if val >= 69 then 19 else 20 end
  507. when 'Z', /\A:{0,3}z/
  508. return unless str.sub!(/\A((?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
  509. |[[:alpha:].\s]+(?:standard|daylight)\s+time\b
  510. |[[:alpha:]]+(?:\s+dst)?\b
  511. )/ix, '')
  512. val = $1
  513. e.zone = val
  514. offset = zone_to_diff(val)
  515. e.offset = offset
  516. when '%'
  517. return unless str.sub!(/\A%/, '')
  518. when '+'
  519. return unless _strptime_i(str, '%a %b %e %H:%M:%S %Z %Y', e)
  520. when '1'
  521. if $VERBOSE
  522. warn("warning: strptime: %1 is deprecated; forget this")
  523. end
  524. return unless str.sub!(/\A(\d+)/, '')
  525. val = $1.to_i
  526. e.jd = val
  527. when '2'
  528. if $VERBOSE
  529. warn("warning: strptime: %2 is deprecated; use '%Y-%j'")
  530. end
  531. return unless _strptime_i(str, '%Y-%j', e)
  532. when '3'
  533. if $VERBOSE
  534. warn("warning: strptime: %3 is deprecated; use '%F'")
  535. end
  536. return unless _strptime_i(str, '%F', e)
  537. else
  538. return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
  539. end
  540. else
  541. case c
  542. when /\A[\s\v]/
  543. str.sub!(/\A[\s\v]+/, '')
  544. else
  545. return unless str.sub!(Regexp.new('\\A' + Regexp.quote(a)), '')
  546. end
  547. end
  548. end
  549. end
  550. private_class_method :_strptime_i
  551. def self._strptime(str, fmt='%F')
  552. str = str.dup
  553. e = Format::Bag.new
  554. return unless _strptime_i(str, fmt, e)
  555. if e._cent
  556. if e.cwyear
  557. e.cwyear += e._cent * 100
  558. end
  559. if e.year
  560. e. year += e._cent * 100
  561. end
  562. end
  563. if e._merid
  564. if e.hour
  565. e.hour %= 12
  566. e.hour += e._merid
  567. end
  568. end
  569. unless str.empty?
  570. e.leftover = str
  571. end
  572. e.to_hash
  573. end
  574. def self.s3e(e, y, m, d, bc=false)
  575. unless String === m
  576. m = m.to_s
  577. end
  578. if y && m && !d
  579. y, m, d = d, y, m
  580. end
  581. if y == nil
  582. if d && d.size > 2
  583. y = d
  584. d = nil
  585. end
  586. if d && d[0,1] == "'"
  587. y = d
  588. d = nil
  589. end
  590. end
  591. if y
  592. y.scan(/(\d+)(.+)?/)
  593. if $2
  594. y, d = d, $1
  595. end
  596. end
  597. if m
  598. if m[0,1] == "'" || m.size > 2
  599. y, m, d = m, d, y # us -> be
  600. end
  601. end
  602. if d
  603. if d[0,1] == "'" || d.size > 2
  604. y, d = d, y
  605. end
  606. end
  607. if y
  608. y =~ /([-+])?(\d+)/
  609. if $1 || $2.size > 2
  610. c = false
  611. end
  612. iy = $&.to_i
  613. if bc
  614. iy = -iy + 1
  615. end
  616. e.year = iy
  617. end
  618. if m
  619. m =~ /\d+/
  620. e.mon = $&.to_i
  621. end
  622. if d
  623. d =~ /\d+/
  624. e.mday = $&.to_i
  625. end
  626. if c != nil
  627. e._comp = c
  628. end
  629. end
  630. private_class_method :s3e
  631. def self._parse_day(str, e) # :nodoc:
  632. if str.sub!(/\b(#{Format::ABBR_DAYS.keys.join('|')})[^-\d\s]*/ino, ' ')
  633. e.wday = Format::ABBR_DAYS[$1.downcase]
  634. true
  635. =begin
  636. elsif str.sub!(/\b(?!\dth)(su|mo|tu|we|th|fr|sa)\b/in, ' ')
  637. e.wday = %w(su mo tu we th fr sa).index($1.downcase)
  638. true
  639. =end
  640. end
  641. end
  642. def self._parse_time(str, e) # :nodoc:
  643. if str.sub!(
  644. /(
  645. (?:
  646. \d+\s*:\s*\d+
  647. (?:
  648. \s*:\s*\d+(?:[,.]\d*)?
  649. )?
  650. |
  651. \d+\s*h(?:\s*\d+m?(?:\s*\d+s?)?)?
  652. )
  653. (?:
  654. \s*
  655. [ap](?:m\b|\.m\.)
  656. )?
  657. |
  658. \d+\s*[ap](?:m\b|\.m\.)
  659. )
  660. (?:
  661. \s*
  662. (
  663. (?:gmt|utc?)?[-+]\d+(?:[,.:]\d+(?::\d+)?)?
  664. |
  665. [[:alpha:].\s]+(?:standard|daylight)\stime\b
  666. |
  667. [[:alpha:]]+(?:\sdst)?\b
  668. )
  669. )?
  670. /inx,
  671. ' ')
  672. t = $1
  673. e.zone = $2 if $2
  674. t =~ /\A(\d+)h?
  675. (?:\s*:?\s*(\d+)m?
  676. (?:
  677. \s*:?\s*(\d+)(?:[,.](\d+))?s?
  678. )?
  679. )?
  680. (?:\s*([ap])(?:m\b|\.m\.))?/inx
  681. e.hour = $1.to_i
  682. e.min = $2.to_i if $2
  683. e.sec = $3.to_i if $3
  684. e.sec_fraction = Rational($4.to_i, 10**$4.size) if $4
  685. if $5
  686. e.hour %= 12
  687. if $5.downcase == 'p'
  688. e.hour += 12
  689. end
  690. end
  691. true
  692. end
  693. end
  694. =begin
  695. def self._parse_beat(str, e) # :nodoc:
  696. if str.sub!(/@\s*(\d+)(?:[,.](\d*))?/, ' ')
  697. beat = Rational($1.to_i)
  698. beat += Rational($2.to_i, 10**$2.size) if $2
  699. secs = Rational(beat, 1000)
  700. h, min, s, fr = self.day_fraction_to_time(secs)
  701. e.hour = h
  702. e.min = min
  703. e.sec = s
  704. e.sec_fraction = fr * 86400
  705. e.zone = '+01:00'
  706. true
  707. end
  708. end
  709. =end
  710. def self._parse_eu(str, e) # :nodoc:
  711. if str.sub!(
  712. /'?(\d+)[^-\d\s]*
  713. \s*
  714. (#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
  715. (?:
  716. \s*
  717. (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
  718. \s*
  719. ('?-?\d+(?:(?:st|nd|rd|th)\b)?)
  720. )?
  721. /inox,
  722. ' ') # '
  723. s3e(e, $4, Format::ABBR_MONTHS[$2.downcase], $1,
  724. $3 && $3[0,1].downcase == 'b')
  725. true
  726. end
  727. end
  728. def self._parse_us(str, e) # :nodoc:
  729. if str.sub!(
  730. /\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-\d\s']*
  731. \s*
  732. ('?\d+)[^-\d\s']*
  733. (?:
  734. \s*
  735. (c(?:e|\.e\.)|b(?:ce|\.c\.e\.)|a(?:d|\.d\.)|b(?:c|\.c\.))?
  736. \s*
  737. ('?-?\d+)
  738. )?
  739. /inox,
  740. ' ') # '
  741. s3e(e, $4, Format::ABBR_MONTHS[$1.downcase], $2,
  742. $3 && $3[0,1].downcase == 'b')
  743. true
  744. end
  745. end
  746. def self._parse_iso(str, e) # :nodoc:
  747. if str.sub!(/('?[-+]?\d+)-(\d+)-('?-?\d+)/n, ' ')
  748. s3e(e, $1, $2, $3)
  749. true
  750. end
  751. end
  752. def self._parse_iso2(str, e) # :nodoc:
  753. if str.sub!(/\b(\d{2}|\d{4})?-?w(\d{2})(?:-?(\d))?\b/in, ' ')
  754. e.cwyear = $1.to_i if $1
  755. e.cweek = $2.to_i
  756. e.cwday = $3.to_i if $3
  757. true
  758. elsif str.sub!(/-w-(\d)\b/in, ' ')
  759. e.cwday = $1.to_i
  760. true
  761. elsif str.sub!(/--(\d{2})?-(\d{2})\b/n, ' ')
  762. e.mon = $1.to_i if $1
  763. e.mday = $2.to_i
  764. true
  765. elsif str.sub!(/--(\d{2})(\d{2})?\b/n, ' ')
  766. e.mon = $1.to_i
  767. e.mday = $2.to_i if $2
  768. true
  769. elsif /[,.](\d{2}|\d{4})-\d{3}\b/n !~ str &&
  770. str.sub!(/\b(\d{2}|\d{4})-(\d{3})\b/n, ' ')
  771. e.year = $1.to_i
  772. e.yday = $2.to_i
  773. true
  774. elsif /\d-\d{3}\b/n !~ str &&
  775. str.sub!(/\b-(\d{3})\b/n, ' ')
  776. e.yday = $1.to_i
  777. true
  778. end
  779. end
  780. def self._parse_jis(str, e) # :nodoc:
  781. if str.sub!(/\b([mtsh])(\d+)\.(\d+)\.(\d+)/in, ' ')
  782. era = { 'm'=>1867,
  783. 't'=>1911,
  784. 's'=>1925,
  785. 'h'=>1988
  786. }[$1.downcase]
  787. e.year = $2.to_i + era
  788. e.mon = $3.to_i
  789. e.mday = $4.to_i
  790. true
  791. end
  792. end
  793. def self._parse_vms(str, e) # :nodoc:
  794. if str.sub!(/('?-?\d+)-(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
  795. -('?-?\d+)/inox, ' ')
  796. s3e(e, $3, Format::ABBR_MONTHS[$2.downcase], $1)
  797. true
  798. elsif str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})[^-]*
  799. -('?-?\d+)(?:-('?-?\d+))?/inox, ' ')
  800. s3e(e, $3, Format::ABBR_MONTHS[$1.downcase], $2)
  801. true
  802. end
  803. end
  804. def self._parse_sla(str, e) # :nodoc:
  805. if str.sub!(%r|('?-?\d+)/\s*('?\d+)(?:\D\s*('?-?\d+))?|n, ' ') # '
  806. s3e(e, $3, $1, $2)
  807. true
  808. end
  809. end
  810. def self._parse_dot(str, e) # :nodoc:
  811. if str.sub!(%r|('?-?\d+)\.\s*('?\d+)\.\s*('?-?\d+)|n, ' ') # '
  812. s3e(e, $1, $2, $3)
  813. true
  814. end
  815. end
  816. def self._parse_year(str, e) # :nodoc:
  817. if str.sub!(/'(\d+)\b/n, ' ')
  818. e.year = $1.to_i
  819. true
  820. end
  821. end
  822. def self._parse_mon(str, e) # :nodoc:
  823. if str.sub!(/\b(#{Format::ABBR_MONTHS.keys.join('|')})\S*/ino, ' ')
  824. e.mon = Format::ABBR_MONTHS[$1.downcase]
  825. true
  826. end
  827. end
  828. def self._parse_mday(str, e) # :nodoc:
  829. if str.sub!(/(\d+)(st|nd|rd|th)\b/in, ' ')
  830. e.mday = $1.to_i
  831. true
  832. end
  833. end
  834. def self._parse_ddd(str, e) # :nodoc:
  835. if str.sub!(
  836. /([-+]?)(\d{2,14})
  837. (?:
  838. \s*
  839. t?
  840. \s*
  841. (\d{2,6})?(?:[,.](\d*))?
  842. )?
  843. (?:
  844. \s*
  845. (
  846. z\b
  847. |
  848. [-+]\d{1,4}\b
  849. |
  850. \[[-+]?\d[^\]]*\]
  851. )
  852. )?
  853. /inx,
  854. ' ')
  855. case $2.size
  856. when 2
  857. if $3.nil? && $4
  858. e.sec = $2[-2, 2].to_i
  859. else
  860. e.mday = $2[ 0, 2].to_i
  861. end
  862. when 4
  863. if $3.nil? && $4
  864. e.sec = $2[-2, 2].to_i
  865. e.min = $2[-4, 2].to_i
  866. else
  867. e.mon = $2[ 0, 2].to_i
  868. e.mday = $2[ 2, 2].to_i
  869. end
  870. when 6
  871. if $3.nil? && $4
  872. e.sec = $2[-2, 2].to_i
  873. e.min = $2[-4, 2].to_i
  874. e.hour = $2[-6, 2].to_i
  875. else
  876. e.year = ($1 + $2[ 0, 2]).to_i
  877. e.mon = $2[ 2, 2].to_i
  878. e.mday = $2[ 4, 2].to_i
  879. end
  880. when 8, 10, 12, 14
  881. if $3.nil? && $4
  882. e.sec = $2[-2, 2].to_i
  883. e.min = $2[-4, 2].to_i
  884. e.hour = $2[-6, 2].to_i
  885. e.mday = $2[-8, 2].to_i
  886. if $2.size >= 10
  887. e.mon = $2[-10, 2].to_i
  888. end
  889. if $2.size == 12
  890. e.year = ($1 + $2[-12, 2]).to_i
  891. end
  892. if $2.size == 14
  893. e.year = ($1 + $2[-14, 4]).to_i
  894. e._comp = false
  895. end
  896. else
  897. e.year = ($1 + $2[ 0, 4]).to_i
  898. e.mon = $2[ 4, 2].to_i
  899. e.mday = $2[ 6, 2].to_i
  900. e.hour = $2[ 8, 2].to_i if $2.size >= 10
  901. e.min = $2[10, 2].to_i if $2.size >= 12
  902. e.sec = $2[12, 2].to_i if $2.size >= 14
  903. e._comp = false
  904. end
  905. when 3
  906. if $3.nil? && $4
  907. e.sec = $2[-2, 2].to_i
  908. e.min = $2[-3, 1].to_i
  909. else
  910. e.yday = $2[ 0, 3].to_i
  911. end
  912. when 5
  913. if $3.nil? && $4
  914. e.sec = $2[-2, 2].to_i
  915. e.min = $2[-4, 2].to_i
  916. e.hour = $2[-5, 1].to_i
  917. else
  918. e.year = ($1 + $2[ 0, 2]).to_i
  919. e.yday = $2[ 2, 3].to_i
  920. end
  921. when 7
  922. if $3.nil? && $4
  923. e.sec = $2[-2, 2].to_i
  924. e.min = $2[-4, 2].to_i
  925. e.hour = $2[-6, 2].to_i
  926. e.mday = $2[-7, 1].to_i
  927. else
  928. e.year = ($1 + $2[ 0, 4]).to_i
  929. e.yday = $2[ 4, 3].to_i
  930. end
  931. end
  932. if $3
  933. if $4
  934. case $3.size
  935. when 2, 4, 6
  936. e.sec = $3[-2, 2].to_i
  937. e.min = $3[-4, 2].to_i if $3.size >= 4
  938. e.hour = $3[-6, 2].to_i if $3.size >= 6
  939. end
  940. else
  941. case $3.size
  942. when 2, 4, 6
  943. e.hour = $3[ 0, 2].to_i
  944. e.min = $3[ 2, 2].to_i if $3.size >= 4
  945. e.sec = $3[ 4, 2].to_i if $3.size >= 6
  946. end
  947. end
  948. end
  949. if $4
  950. e.sec_fraction = Rational($4.to_i, 10**$4.size)
  951. end
  952. if $5
  953. e.zone = $5
  954. if e.zone[0,1] == '['
  955. o, n, = e.zone[1..-2].split(':')
  956. e.zone = n || o
  957. if /\A\d/ =~ o
  958. o = format('+%s', o)
  959. end
  960. e.offset = zone_to_diff(o)
  961. end
  962. end
  963. true
  964. end
  965. end
  966. private_class_method :_parse_day, :_parse_time, # :_parse_beat,
  967. :_parse_eu, :_parse_us, :_parse_iso, :_parse_iso2,
  968. :_parse_jis, :_parse_vms, :_parse_sla, :_parse_dot,
  969. :_parse_year, :_parse_mon, :_parse_mday, :_parse_ddd
  970. def self._parse(str, comp=false)
  971. str = str.dup
  972. e = Format::Bag.new
  973. e._comp = comp
  974. str.gsub!(/[^-+',.\/:@[:alnum:]\[\]\x80-\xff]+/n, ' ')
  975. _parse_time(str, e) # || _parse_beat(str, e)
  976. _parse_day(str, e)
  977. _parse_eu(str, e) ||
  978. _parse_us(str, e) ||
  979. _parse_iso(str, e) ||
  980. _parse_jis(str, e) ||
  981. _parse_vms(str, e) ||
  982. _parse_sla(str, e) ||
  983. _parse_dot(str, e) ||
  984. _parse_iso2(str, e) ||
  985. _parse_year(str, e) ||
  986. _parse_mon(str, e) ||
  987. _parse_mday(str, e) ||
  988. _parse_ddd(str, e)
  989. if str.sub!(/\b(bc\b|bce\b|b\.c\.|b\.c\.e\.)/in, ' ')
  990. if e.year
  991. e.year = -e.year + 1
  992. end
  993. end
  994. if str.sub!(/\A\s*(\d{1,2})\s*\z/n, ' ')
  995. if e.hour && !e.mday
  996. v = $1.to_i
  997. if (1..31) === v
  998. e.mday = v
  999. end
  1000. end
  1001. if e.mday && !e.hour
  1002. v = $1.to_i
  1003. if (0..24) === v
  1004. e.hour = v
  1005. end
  1006. end
  1007. end
  1008. if e._comp
  1009. if e.cwyear
  1010. if e.cwyear >= 0 && e.cwyear <= 99
  1011. e.cwyear += if e.cwyear >= 69
  1012. then 1900 else 2000 end
  1013. end
  1014. end
  1015. if e.year
  1016. if e.year >= 0 && e.year <= 99
  1017. e.year += if e.year >= 69
  1018. then 1900 else 2000 end
  1019. end
  1020. end
  1021. end
  1022. e.offset ||= zone_to_diff(e.zone) if e.zone
  1023. e.to_hash
  1024. end
  1025. def self.zone_to_diff(zone) # :nodoc:
  1026. zone = zone.downcase
  1027. if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
  1028. dst = $1 == 'daylight'
  1029. else
  1030. dst = zone.sub!(/\s+dst\z/, '')
  1031. end
  1032. if Format::ZONES.include?(zone)
  1033. offset = Format::ZONES[zone]
  1034. offset += 3600 if dst
  1035. elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
  1036. sign = $1
  1037. if zone.include?(':')
  1038. hour, min, sec, = zone.split(':')
  1039. elsif zone.include?(',') || zone.include?('.')
  1040. hour, fr, = zone.split(/[,.]/)
  1041. min = Rational(fr.to_i, 10**fr.size) * 60
  1042. else
  1043. case zone.size
  1044. when 3
  1045. hour = zone[0,1]
  1046. min = zone[1,2]
  1047. else
  1048. hour = zone[0,2]
  1049. min = zone[2,2]
  1050. sec = zone[4,2]
  1051. end
  1052. end
  1053. offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
  1054. offset *= -1 if sign == '-'
  1055. end
  1056. offset
  1057. end
  1058. end
  1059. class DateTime < Date
  1060. def strftime(fmt='%FT%T%:z')
  1061. super(fmt)
  1062. end
  1063. def self._strptime(str, fmt='%FT%T%z')
  1064. super(str, fmt)
  1065. end
  1066. =begin
  1067. def iso8601_timediv(n) # :nodoc:
  1068. strftime('T%T' +
  1069. if n < 1
  1070. ''
  1071. else
  1072. '.%0*d' % [n, (sec_fraction / SECONDS_IN_DAY / (10**n)).round]
  1073. end +
  1074. '%:z')
  1075. end
  1076. private :iso8601_timediv
  1077. def iso8601(n=0)
  1078. super() + iso8601_timediv(n)
  1079. end
  1080. def rfc3339(n=0) iso8601(n) end
  1081. def jisx0301(n=0)
  1082. super() + iso8601_timediv(n)
  1083. end
  1084. =end
  1085. end