PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

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

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