PageRenderTime 33ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/test/ruby/test_time_tz.rb

http://github.com/ruby/ruby
Ruby | 784 lines | 708 code | 70 blank | 6 comment | 45 complexity | fb987a85399a22367e5a95286248d862 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # frozen_string_literal: false
  2. require 'test/unit'
  3. require '-test-/time'
  4. class TestTimeTZ < Test::Unit::TestCase
  5. has_right_tz = true
  6. has_lisbon_tz = true
  7. force_tz_test = ENV["RUBY_FORCE_TIME_TZ_TEST"] == "yes"
  8. case RUBY_PLATFORM
  9. when /linux/
  10. force_tz_test = true
  11. when /darwin|freebsd|openbsd/
  12. has_lisbon_tz = false
  13. force_tz_test = true
  14. end
  15. if force_tz_test
  16. module Util
  17. def with_tz(tz)
  18. old = ENV["TZ"]
  19. begin
  20. ENV["TZ"] = tz
  21. yield
  22. ensure
  23. ENV["TZ"] = old
  24. end
  25. end
  26. end
  27. else
  28. module Util
  29. def with_tz(tz)
  30. if ENV["TZ"] == tz
  31. yield
  32. end
  33. end
  34. end
  35. end
  36. module Util
  37. def have_tz_offset?(tz)
  38. with_tz(tz) {!Time.now.utc_offset.zero?}
  39. end
  40. def format_gmtoff(gmtoff, colon=false)
  41. if gmtoff < 0
  42. expected = "-"
  43. gmtoff = -gmtoff
  44. else
  45. expected = "+"
  46. end
  47. gmtoff /= 60
  48. expected << "%02d" % [gmtoff / 60]
  49. expected << ":" if colon
  50. expected << "%02d" % [gmtoff % 60]
  51. expected
  52. end
  53. def format_gmtoff2(gmtoff)
  54. if gmtoff < 0
  55. expected = "-"
  56. gmtoff = -gmtoff
  57. else
  58. expected = "+"
  59. end
  60. expected << "%02d:%02d:%02d" % [gmtoff / 3600, gmtoff % 3600 / 60, gmtoff % 60]
  61. expected
  62. end
  63. def group_by(e, &block)
  64. if e.respond_to? :group_by
  65. e.group_by(&block)
  66. else
  67. h = {}
  68. e.each {|o|
  69. (h[yield(o)] ||= []) << o
  70. }
  71. h
  72. end
  73. end
  74. end
  75. include Util
  76. extend Util
  77. has_right_tz &&= have_tz_offset?("right/America/Los_Angeles")
  78. has_lisbon_tz &&= have_tz_offset?("Europe/Lisbon")
  79. CORRECT_TOKYO_DST_1951 = with_tz("Asia/Tokyo") {
  80. if Time.local(1951, 5, 6, 12, 0, 0).dst? # noon, DST
  81. if Time.local(1951, 5, 6, 1, 0, 0).dst? # DST with fixed tzdata
  82. Time.local(1951, 9, 8, 23, 0, 0).dst? ? "2018f" : "2018e"
  83. end
  84. end
  85. }
  86. CORRECT_KIRITIMATI_SKIP_1994 = with_tz("Pacific/Kiritimati") {
  87. Time.local(1994, 12, 31, 0, 0, 0).year == 1995
  88. }
  89. def time_to_s(t)
  90. t.to_s
  91. end
  92. def assert_time_constructor(tz, expected, method, args, message=nil)
  93. m = message ? "#{message}\n" : ""
  94. m << "TZ=#{tz} Time.#{method}(#{args.map {|arg| arg.inspect }.join(', ')})"
  95. real = time_to_s(Time.send(method, *args))
  96. assert_equal(expected, real, m)
  97. end
  98. def test_localtime_zone
  99. t = with_tz("America/Los_Angeles") {
  100. Time.local(2000, 1, 1)
  101. }
  102. skip "force_tz_test is false on this environment" unless t
  103. z1 = t.zone
  104. z2 = with_tz(tz="Asia/Singapore") {
  105. t.localtime.zone
  106. }
  107. assert_equal(z2, z1)
  108. end
  109. def test_america_los_angeles
  110. with_tz(tz="America/Los_Angeles") {
  111. assert_time_constructor(tz, "2007-03-11 03:00:00 -0700", :local, [2007,3,11,2,0,0])
  112. assert_time_constructor(tz, "2007-03-11 03:59:59 -0700", :local, [2007,3,11,2,59,59])
  113. assert_equal("PST", Time.new(0x1_0000_0000_0000_0000, 1).zone)
  114. assert_equal("PDT", Time.new(0x1_0000_0000_0000_0000, 8).zone)
  115. assert_equal(false, Time.new(0x1_0000_0000_0000_0000, 1).isdst)
  116. assert_equal(true, Time.new(0x1_0000_0000_0000_0000, 8).isdst)
  117. }
  118. end
  119. def test_america_managua
  120. with_tz(tz="America/Managua") {
  121. assert_time_constructor(tz, "1993-01-01 01:00:00 -0500", :local, [1993,1,1,0,0,0])
  122. assert_time_constructor(tz, "1993-01-01 01:59:59 -0500", :local, [1993,1,1,0,59,59])
  123. }
  124. end
  125. def test_asia_singapore
  126. with_tz(tz="Asia/Singapore") {
  127. assert_time_constructor(tz, "1981-12-31 23:59:59 +0730", :local, [1981,12,31,23,59,59])
  128. assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,0,0])
  129. assert_time_constructor(tz, "1982-01-01 00:59:59 +0800", :local, [1982,1,1,0,29,59])
  130. assert_time_constructor(tz, "1982-01-01 00:30:00 +0800", :local, [1982,1,1,0,30,0])
  131. }
  132. end
  133. def test_asia_tokyo
  134. with_tz(tz="Asia/Tokyo") {
  135. h = CORRECT_TOKYO_DST_1951 ? 0 : 2
  136. assert_time_constructor(tz, "1951-05-06 0#{h+1}:00:00 +1000", :local, [1951,5,6,h,0,0])
  137. assert_time_constructor(tz, "1951-05-06 0#{h+1}:59:59 +1000", :local, [1951,5,6,h,59,59])
  138. assert_time_constructor(tz, "2010-06-10 06:13:28 +0900", :local, [2010,6,10,6,13,28])
  139. }
  140. end
  141. def test_asia_kuala_lumpur
  142. with_tz(tz="Asia/Kuala_Lumpur") {
  143. assert_time_constructor(tz, "1933-01-01 00:20:00 +0720", :local, [1933])
  144. }
  145. end
  146. def test_canada_newfoundland
  147. with_tz(tz="America/St_Johns") {
  148. assert_time_constructor(tz, "2007-11-03 23:00:59 -0230", :new, [2007,11,3,23,0,59,:dst])
  149. assert_time_constructor(tz, "2007-11-03 23:01:00 -0230", :new, [2007,11,3,23,1,0,:dst])
  150. assert_time_constructor(tz, "2007-11-03 23:59:59 -0230", :new, [2007,11,3,23,59,59,:dst])
  151. assert_time_constructor(tz, "2007-11-04 00:00:00 -0230", :new, [2007,11,4,0,0,0,:dst])
  152. assert_time_constructor(tz, "2007-11-04 00:00:59 -0230", :new, [2007,11,4,0,0,59,:dst])
  153. assert_time_constructor(tz, "2007-11-03 23:01:00 -0330", :new, [2007,11,3,23,1,0,:std])
  154. assert_time_constructor(tz, "2007-11-03 23:59:59 -0330", :new, [2007,11,3,23,59,59,:std])
  155. assert_time_constructor(tz, "2007-11-04 00:00:59 -0330", :new, [2007,11,4,0,0,59,:std])
  156. assert_time_constructor(tz, "2007-11-04 00:01:00 -0330", :new, [2007,11,4,0,1,0,:std])
  157. }
  158. end
  159. def test_europe_brussels
  160. with_tz(tz="Europe/Brussels") {
  161. assert_time_constructor(tz, "1916-04-30 23:59:59 +0100", :local, [1916,4,30,23,59,59])
  162. assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1], "[ruby-core:30672] [Bug #3411]")
  163. assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,0,59,59])
  164. assert_time_constructor(tz, "1916-05-01 01:00:00 +0200", :local, [1916,5,1,1,0,0])
  165. assert_time_constructor(tz, "1916-05-01 01:59:59 +0200", :local, [1916,5,1,1,59,59])
  166. }
  167. end
  168. def test_europe_berlin
  169. with_tz(tz="Europe/Berlin") {
  170. assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [2011,10,30,2,0,0], "[ruby-core:67345] [Bug #10698]")
  171. assert_time_constructor(tz, "2011-10-30 02:00:00 +0100", :local, [0,0,2,30,10,2011,nil,nil,false,nil])
  172. assert_time_constructor(tz, "2011-10-30 02:00:00 +0200", :local, [0,0,2,30,10,2011,nil,nil,true,nil])
  173. }
  174. end
  175. def test_europe_lisbon
  176. with_tz("Europe/Lisbon") {
  177. assert_equal("LMT", Time.new(-0x1_0000_0000_0000_0000).zone)
  178. }
  179. end if has_lisbon_tz
  180. def test_pacific_kiritimati
  181. with_tz(tz="Pacific/Kiritimati") {
  182. assert_time_constructor(tz, "1994-12-30 00:00:00 -1000", :local, [1994,12,30,0,0,0])
  183. assert_time_constructor(tz, "1994-12-30 23:59:59 -1000", :local, [1994,12,30,23,59,59])
  184. if CORRECT_KIRITIMATI_SKIP_1994
  185. assert_time_constructor(tz, "1995-01-01 00:00:00 +1400", :local, [1994,12,31,0,0,0])
  186. assert_time_constructor(tz, "1995-01-01 23:59:59 +1400", :local, [1994,12,31,23,59,59])
  187. assert_time_constructor(tz, "1995-01-01 00:00:00 +1400", :local, [1995,1,1,0,0,0])
  188. else
  189. assert_time_constructor(tz, "1994-12-31 23:59:59 -1000", :local, [1994,12,31,23,59,59])
  190. assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,1,0,0,0])
  191. assert_time_constructor(tz, "1995-01-02 23:59:59 +1400", :local, [1995,1,1,23,59,59])
  192. end
  193. assert_time_constructor(tz, "1995-01-02 00:00:00 +1400", :local, [1995,1,2,0,0,0])
  194. }
  195. end
  196. def test_right_utc
  197. with_tz(tz="right/UTC") {
  198. assert_time_constructor(tz, "2008-12-31 23:59:59 UTC", :utc, [2008,12,31,23,59,59])
  199. assert_time_constructor(tz, "2008-12-31 23:59:60 UTC", :utc, [2008,12,31,23,59,60])
  200. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,24,0,0])
  201. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2009,1,1,0,0,0])
  202. }
  203. end if has_right_tz
  204. def test_right_utc_switching
  205. with_tz("UTC") { # ensure no leap second timezone
  206. assert_equal(4102444800, Time.utc(2100,1,1,0,0,0).to_i)
  207. with_tz(tz="right/UTC") {
  208. assert_time_constructor(tz, "2008-12-31 23:59:59 UTC", :utc, [2008,12,31,23,59,59])
  209. assert_time_constructor(tz, "2008-12-31 23:59:60 UTC", :utc, [2008,12,31,23,59,60])
  210. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,24,0,0])
  211. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2009,1,1,0,0,0])
  212. assert_not_equal(4102444800, Time.utc(2100,1,1,0,0,0).to_i)
  213. }
  214. }
  215. with_tz("right/UTC") {
  216. assert_not_equal(4102444800, Time.utc(2100,1,1,0,0,0).to_i)
  217. with_tz(tz="UTC") {
  218. assert_time_constructor(tz, "2008-12-31 23:59:59 UTC", :utc, [2008,12,31,23,59,59])
  219. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,23,59,60])
  220. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2008,12,31,24,0,0])
  221. assert_time_constructor(tz, "2009-01-01 00:00:00 UTC", :utc, [2009,1,1,0,0,0])
  222. assert_equal(4102444800, Time.utc(2100,1,1,0,0,0).to_i)
  223. }
  224. }
  225. end if has_right_tz
  226. def test_right_america_los_angeles
  227. with_tz(tz="right/America/Los_Angeles") {
  228. assert_time_constructor(tz, "2008-12-31 15:59:59 -0800", :local, [2008,12,31,15,59,59])
  229. assert_time_constructor(tz, "2008-12-31 15:59:60 -0800", :local, [2008,12,31,15,59,60])
  230. assert_time_constructor(tz, "2008-12-31 16:00:00 -0800", :local, [2008,12,31,16,0,0])
  231. }
  232. end if has_right_tz
  233. def test_utc_names
  234. assert_predicate(Time.new(2019, 1, 1, 0, 0, 0, "UTC"), :utc?)
  235. assert_predicate(Time.new(2019, 1, 1, 0, 0, 0, "utc"), :utc?)
  236. assert_predicate(Time.new(2019, 1, 1, 0, 0, 0, "Z"), :utc?)
  237. end
  238. def test_military_names
  239. assert_equal( +1*3600, Time.new(2019, 1, 1, 0, 0, 0, "A").gmtoff)
  240. assert_equal( +2*3600, Time.new(2019, 1, 1, 0, 0, 0, "B").gmtoff)
  241. assert_equal( +3*3600, Time.new(2019, 1, 1, 0, 0, 0, "C").gmtoff)
  242. assert_equal( +4*3600, Time.new(2019, 1, 1, 0, 0, 0, "D").gmtoff)
  243. assert_equal( +5*3600, Time.new(2019, 1, 1, 0, 0, 0, "E").gmtoff)
  244. assert_equal( +6*3600, Time.new(2019, 1, 1, 0, 0, 0, "F").gmtoff)
  245. assert_equal( +7*3600, Time.new(2019, 1, 1, 0, 0, 0, "G").gmtoff)
  246. assert_equal( +8*3600, Time.new(2019, 1, 1, 0, 0, 0, "H").gmtoff)
  247. assert_equal( +9*3600, Time.new(2019, 1, 1, 0, 0, 0, "I").gmtoff)
  248. assert_equal(+10*3600, Time.new(2019, 1, 1, 0, 0, 0, "K").gmtoff)
  249. assert_equal(+11*3600, Time.new(2019, 1, 1, 0, 0, 0, "L").gmtoff)
  250. assert_equal(+12*3600, Time.new(2019, 1, 1, 0, 0, 0, "M").gmtoff)
  251. assert_equal( -1*3600, Time.new(2019, 1, 1, 0, 0, 0, "N").gmtoff)
  252. assert_equal( -2*3600, Time.new(2019, 1, 1, 0, 0, 0, "O").gmtoff)
  253. assert_equal( -3*3600, Time.new(2019, 1, 1, 0, 0, 0, "P").gmtoff)
  254. assert_equal( -4*3600, Time.new(2019, 1, 1, 0, 0, 0, "Q").gmtoff)
  255. assert_equal( -5*3600, Time.new(2019, 1, 1, 0, 0, 0, "R").gmtoff)
  256. assert_equal( -6*3600, Time.new(2019, 1, 1, 0, 0, 0, "S").gmtoff)
  257. assert_equal( -7*3600, Time.new(2019, 1, 1, 0, 0, 0, "T").gmtoff)
  258. assert_equal( -8*3600, Time.new(2019, 1, 1, 0, 0, 0, "U").gmtoff)
  259. assert_equal( -9*3600, Time.new(2019, 1, 1, 0, 0, 0, "V").gmtoff)
  260. assert_equal(-10*3600, Time.new(2019, 1, 1, 0, 0, 0, "W").gmtoff)
  261. assert_equal(-11*3600, Time.new(2019, 1, 1, 0, 0, 0, "X").gmtoff)
  262. assert_equal(-12*3600, Time.new(2019, 1, 1, 0, 0, 0, "Y").gmtoff)
  263. assert_equal( 0, Time.new(2019, 1, 1, 0, 0, 0, "Z").gmtoff)
  264. assert_equal( +1*3600, Time.at(0, in: "A").gmtoff)
  265. assert_equal( +2*3600, Time.at(0, in: "B").gmtoff)
  266. assert_equal( +3*3600, Time.at(0, in: "C").gmtoff)
  267. assert_equal( +4*3600, Time.at(0, in: "D").gmtoff)
  268. assert_equal( +5*3600, Time.at(0, in: "E").gmtoff)
  269. assert_equal( +6*3600, Time.at(0, in: "F").gmtoff)
  270. assert_equal( +7*3600, Time.at(0, in: "G").gmtoff)
  271. assert_equal( +8*3600, Time.at(0, in: "H").gmtoff)
  272. assert_equal( +9*3600, Time.at(0, in: "I").gmtoff)
  273. assert_equal(+10*3600, Time.at(0, in: "K").gmtoff)
  274. assert_equal(+11*3600, Time.at(0, in: "L").gmtoff)
  275. assert_equal(+12*3600, Time.at(0, in: "M").gmtoff)
  276. assert_equal( -1*3600, Time.at(0, in: "N").gmtoff)
  277. assert_equal( -2*3600, Time.at(0, in: "O").gmtoff)
  278. assert_equal( -3*3600, Time.at(0, in: "P").gmtoff)
  279. assert_equal( -4*3600, Time.at(0, in: "Q").gmtoff)
  280. assert_equal( -5*3600, Time.at(0, in: "R").gmtoff)
  281. assert_equal( -6*3600, Time.at(0, in: "S").gmtoff)
  282. assert_equal( -7*3600, Time.at(0, in: "T").gmtoff)
  283. assert_equal( -8*3600, Time.at(0, in: "U").gmtoff)
  284. assert_equal( -9*3600, Time.at(0, in: "V").gmtoff)
  285. assert_equal(-10*3600, Time.at(0, in: "W").gmtoff)
  286. assert_equal(-11*3600, Time.at(0, in: "X").gmtoff)
  287. assert_equal(-12*3600, Time.at(0, in: "Y").gmtoff)
  288. assert_equal( 0, Time.at(0, in: "Z").gmtoff)
  289. end
  290. MON2NUM = {
  291. "Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6,
  292. "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12
  293. }
  294. @testnum = 0
  295. def self.gen_test_name(hint)
  296. @testnum += 1
  297. s = "test_gen_#{@testnum}"
  298. s.sub(/gen_/) { "gen" + "_#{hint}_".gsub(/[^0-9A-Za-z]+/, '_') }
  299. end
  300. def self.parse_zdump_line(line)
  301. return nil if /\A\#/ =~ line || /\A\s*\z/ =~ line
  302. if /\A(\S+)\s+
  303. \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+UTC?
  304. \s+=\s+
  305. \S+\s+(\S+)\s+(\d+)\s+(\d\d):(\d\d):(\d\d)\s+(\d+)\s+\S+
  306. \s+isdst=\d+\s+gmtoff=(-?\d+)\n
  307. \z/x !~ line
  308. raise "unexpected zdump line: #{line.inspect}"
  309. end
  310. tz, u_mon, u_day, u_hour, u_min, u_sec, u_year,
  311. l_mon, l_day, l_hour, l_min, l_sec, l_year, gmtoff = $~.captures
  312. u_year = u_year.to_i
  313. u_mon = MON2NUM[u_mon]
  314. u_day = u_day.to_i
  315. u_hour = u_hour.to_i
  316. u_min = u_min.to_i
  317. u_sec = u_sec.to_i
  318. l_year = l_year.to_i
  319. l_mon = MON2NUM[l_mon]
  320. l_day = l_day.to_i
  321. l_hour = l_hour.to_i
  322. l_min = l_min.to_i
  323. l_sec = l_sec.to_i
  324. gmtoff = gmtoff.to_i
  325. [tz,
  326. [u_year, u_mon, u_day, u_hour, u_min, u_sec],
  327. [l_year, l_mon, l_day, l_hour, l_min, l_sec],
  328. gmtoff]
  329. end
  330. def self.gen_zdump_test(data)
  331. sample = []
  332. data.each_line {|line|
  333. s = parse_zdump_line(line)
  334. sample << s if s
  335. }
  336. sample.each {|tz, u, l, gmtoff|
  337. expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u
  338. expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
  339. mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})"
  340. mesg = "#{mesg_utc}.localtime"
  341. define_method(gen_test_name(tz)) {
  342. with_tz(tz) {
  343. t = nil
  344. assert_nothing_raised(mesg) { t = Time.utc(*u) }
  345. assert_equal(expected_utc, time_to_s(t), mesg_utc)
  346. assert_nothing_raised(mesg) { t.localtime }
  347. assert_equal(expected, time_to_s(t), mesg)
  348. assert_equal(gmtoff, t.gmtoff)
  349. assert_equal(format_gmtoff(gmtoff), t.strftime("%z"))
  350. assert_equal(format_gmtoff(gmtoff, true), t.strftime("%:z"))
  351. assert_equal(format_gmtoff2(gmtoff), t.strftime("%::z"))
  352. assert_equal(Encoding::US_ASCII, t.zone.encoding)
  353. }
  354. }
  355. }
  356. group_by(sample) {|tz, _, _, _| tz }.each {|tz, a|
  357. a.each_with_index {|(_, _, l, gmtoff), i|
  358. expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
  359. monotonic_to_past = i == 0 || (a[i-1][2] <=> l) < 0
  360. monotonic_to_future = i == a.length-1 || (l <=> a[i+1][2]) < 0
  361. if monotonic_to_past && monotonic_to_future
  362. define_method(gen_test_name(tz)) {
  363. with_tz(tz) {
  364. assert_time_constructor(tz, expected, :local, l)
  365. assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil])
  366. assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil])
  367. assert_time_constructor(tz, expected, :new, l)
  368. assert_time_constructor(tz, expected, :new, l+[:std])
  369. assert_time_constructor(tz, expected, :new, l+[:dst])
  370. }
  371. }
  372. elsif monotonic_to_past && !monotonic_to_future
  373. define_method(gen_test_name(tz)) {
  374. with_tz(tz) {
  375. assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, true, nil])
  376. assert_time_constructor(tz, expected, :new, l+[:dst])
  377. }
  378. }
  379. elsif !monotonic_to_past && monotonic_to_future
  380. define_method(gen_test_name(tz)) {
  381. with_tz(tz) {
  382. assert_time_constructor(tz, expected, :local, l.reverse+[nil, nil, false, nil])
  383. assert_time_constructor(tz, expected, :new, l+[:std])
  384. }
  385. }
  386. else
  387. define_method(gen_test_name(tz)) {
  388. flunk("time in reverse order: TZ=#{tz} #{expected}")
  389. }
  390. end
  391. }
  392. }
  393. end
  394. gen_zdump_test <<'End'
  395. America/Lima Sun Apr 1 03:59:59 1990 UTC = Sat Mar 31 23:59:59 1990 PEST isdst=1 gmtoff=-14400
  396. America/Lima Sun Apr 1 04:00:00 1990 UTC = Sat Mar 31 23:00:00 1990 PET isdst=0 gmtoff=-18000
  397. America/Lima Sat Jan 1 04:59:59 1994 UTC = Fri Dec 31 23:59:59 1993 PET isdst=0 gmtoff=-18000
  398. America/Lima Sat Jan 1 05:00:00 1994 UTC = Sat Jan 1 01:00:00 1994 PEST isdst=1 gmtoff=-14400
  399. America/Lima Fri Apr 1 03:59:59 1994 UTC = Thu Mar 31 23:59:59 1994 PEST isdst=1 gmtoff=-14400
  400. America/Lima Fri Apr 1 04:00:00 1994 UTC = Thu Mar 31 23:00:00 1994 PET isdst=0 gmtoff=-18000
  401. America/Los_Angeles Sun Apr 2 09:59:59 2006 UTC = Sun Apr 2 01:59:59 2006 PST isdst=0 gmtoff=-28800
  402. America/Los_Angeles Sun Apr 2 10:00:00 2006 UTC = Sun Apr 2 03:00:00 2006 PDT isdst=1 gmtoff=-25200
  403. America/Los_Angeles Sun Oct 29 08:59:59 2006 UTC = Sun Oct 29 01:59:59 2006 PDT isdst=1 gmtoff=-25200
  404. America/Los_Angeles Sun Oct 29 09:00:00 2006 UTC = Sun Oct 29 01:00:00 2006 PST isdst=0 gmtoff=-28800
  405. America/Los_Angeles Sun Mar 11 09:59:59 2007 UTC = Sun Mar 11 01:59:59 2007 PST isdst=0 gmtoff=-28800
  406. America/Los_Angeles Sun Mar 11 10:00:00 2007 UTC = Sun Mar 11 03:00:00 2007 PDT isdst=1 gmtoff=-25200
  407. America/Los_Angeles Sun Nov 4 08:59:59 2007 UTC = Sun Nov 4 01:59:59 2007 PDT isdst=1 gmtoff=-25200
  408. America/Los_Angeles Sun Nov 4 09:00:00 2007 UTC = Sun Nov 4 01:00:00 2007 PST isdst=0 gmtoff=-28800
  409. America/Managua Thu Sep 24 04:59:59 1992 UTC = Wed Sep 23 23:59:59 1992 EST isdst=0 gmtoff=-18000
  410. America/Managua Thu Sep 24 05:00:00 1992 UTC = Wed Sep 23 23:00:00 1992 CST isdst=0 gmtoff=-21600
  411. America/Managua Fri Jan 1 05:59:59 1993 UTC = Thu Dec 31 23:59:59 1992 CST isdst=0 gmtoff=-21600
  412. America/Managua Fri Jan 1 06:00:00 1993 UTC = Fri Jan 1 01:00:00 1993 EST isdst=0 gmtoff=-18000
  413. America/Managua Wed Jan 1 04:59:59 1997 UTC = Tue Dec 31 23:59:59 1996 EST isdst=0 gmtoff=-18000
  414. America/Managua Wed Jan 1 05:00:00 1997 UTC = Tue Dec 31 23:00:00 1996 CST isdst=0 gmtoff=-21600
  415. Asia/Singapore Sun Aug 8 16:30:00 1965 UTC = Mon Aug 9 00:00:00 1965 SGT isdst=0 gmtoff=27000
  416. Asia/Singapore Thu Dec 31 16:29:59 1981 UTC = Thu Dec 31 23:59:59 1981 SGT isdst=0 gmtoff=27000
  417. Asia/Singapore Thu Dec 31 16:30:00 1981 UTC = Fri Jan 1 00:30:00 1982 SGT isdst=0 gmtoff=28800
  418. End
  419. gen_zdump_test CORRECT_TOKYO_DST_1951 ? <<'End' + (CORRECT_TOKYO_DST_1951 < "2018f" ? <<'2018e' : <<'2018f') : <<'End'
  420. Asia/Tokyo Sat May 5 14:59:59 1951 UTC = Sat May 5 23:59:59 1951 JST isdst=0 gmtoff=32400
  421. Asia/Tokyo Sat May 5 15:00:00 1951 UTC = Sun May 6 01:00:00 1951 JDT isdst=1 gmtoff=36000
  422. End
  423. Asia/Tokyo Sat Sep 8 13:59:59 1951 UTC = Sat Sep 8 23:59:59 1951 JDT isdst=1 gmtoff=36000
  424. Asia/Tokyo Sat Sep 8 14:00:00 1951 UTC = Sat Sep 8 23:00:00 1951 JST isdst=0 gmtoff=32400
  425. 2018e
  426. Asia/Tokyo Sat Sep 8 14:59:59 1951 UTC = Sun Sep 9 00:59:59 1951 JDT isdst=1 gmtoff=36000
  427. Asia/Tokyo Sat Sep 8 15:00:00 1951 UTC = Sun Sep 9 00:00:00 1951 JST isdst=0 gmtoff=32400
  428. 2018f
  429. Asia/Tokyo Sat May 5 16:59:59 1951 UTC = Sun May 6 01:59:59 1951 JST isdst=0 gmtoff=32400
  430. Asia/Tokyo Sat May 5 17:00:00 1951 UTC = Sun May 6 03:00:00 1951 JDT isdst=1 gmtoff=36000
  431. Asia/Tokyo Fri Sep 7 15:59:59 1951 UTC = Sat Sep 8 01:59:59 1951 JDT isdst=1 gmtoff=36000
  432. Asia/Tokyo Fri Sep 7 16:00:00 1951 UTC = Sat Sep 8 01:00:00 1951 JST isdst=0 gmtoff=32400
  433. End
  434. gen_zdump_test <<'End'
  435. America/St_Johns Sun Mar 11 03:30:59 2007 UTC = Sun Mar 11 00:00:59 2007 NST isdst=0 gmtoff=-12600
  436. America/St_Johns Sun Mar 11 03:31:00 2007 UTC = Sun Mar 11 01:01:00 2007 NDT isdst=1 gmtoff=-9000
  437. America/St_Johns Sun Nov 4 02:30:59 2007 UTC = Sun Nov 4 00:00:59 2007 NDT isdst=1 gmtoff=-9000
  438. America/St_Johns Sun Nov 4 02:31:00 2007 UTC = Sat Nov 3 23:01:00 2007 NST isdst=0 gmtoff=-12600
  439. Europe/Brussels Sun Apr 30 22:59:59 1916 UTC = Sun Apr 30 23:59:59 1916 CET isdst=0 gmtoff=3600
  440. Europe/Brussels Sun Apr 30 23:00:00 1916 UTC = Mon May 1 01:00:00 1916 CEST isdst=1 gmtoff=7200
  441. Europe/Brussels Sat Sep 30 22:59:59 1916 UTC = Sun Oct 1 00:59:59 1916 CEST isdst=1 gmtoff=7200
  442. Europe/Brussels Sat Sep 30 23:00:00 1916 UTC = Sun Oct 1 00:00:00 1916 CET isdst=0 gmtoff=3600
  443. Europe/London Sun Mar 16 01:59:59 1947 UTC = Sun Mar 16 01:59:59 1947 GMT isdst=0 gmtoff=0
  444. Europe/London Sun Mar 16 02:00:00 1947 UTC = Sun Mar 16 03:00:00 1947 BST isdst=1 gmtoff=3600
  445. Europe/London Sun Apr 13 00:59:59 1947 UTC = Sun Apr 13 01:59:59 1947 BST isdst=1 gmtoff=3600
  446. Europe/London Sun Apr 13 01:00:00 1947 UTC = Sun Apr 13 03:00:00 1947 BDST isdst=1 gmtoff=7200
  447. Europe/London Sun Aug 10 00:59:59 1947 UTC = Sun Aug 10 02:59:59 1947 BDST isdst=1 gmtoff=7200
  448. Europe/London Sun Aug 10 01:00:00 1947 UTC = Sun Aug 10 02:00:00 1947 BST isdst=1 gmtoff=3600
  449. Europe/London Sun Nov 2 01:59:59 1947 UTC = Sun Nov 2 02:59:59 1947 BST isdst=1 gmtoff=3600
  450. Europe/London Sun Nov 2 02:00:00 1947 UTC = Sun Nov 2 02:00:00 1947 GMT isdst=0 gmtoff=0
  451. End
  452. if CORRECT_KIRITIMATI_SKIP_1994
  453. gen_zdump_test <<'End'
  454. Pacific/Kiritimati Sat Dec 31 09:59:59 1994 UTC = Fri Dec 30 23:59:59 1994 LINT isdst=0 gmtoff=-36000
  455. Pacific/Kiritimati Sat Dec 31 10:00:00 1994 UTC = Sun Jan 1 00:00:00 1995 LINT isdst=0 gmtoff=50400
  456. End
  457. else
  458. gen_zdump_test <<'End'
  459. Pacific/Kiritimati Sun Jan 1 09:59:59 1995 UTC = Sat Dec 31 23:59:59 1994 LINT isdst=0 gmtoff=-36000
  460. Pacific/Kiritimati Sun Jan 1 10:00:00 1995 UTC = Mon Jan 2 00:00:00 1995 LINT isdst=0 gmtoff=50400
  461. End
  462. end
  463. gen_zdump_test <<'End' if has_right_tz
  464. right/America/Los_Angeles Fri Jun 30 23:59:60 1972 UTC = Fri Jun 30 16:59:60 1972 PDT isdst=1 gmtoff=-25200
  465. right/America/Los_Angeles Wed Dec 31 23:59:60 2008 UTC = Wed Dec 31 15:59:60 2008 PST isdst=0 gmtoff=-28800
  466. #right/Asia/Tokyo Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 08:59:60 1972 JST isdst=0 gmtoff=32400
  467. #right/Asia/Tokyo Sat Dec 31 23:59:60 2005 UTC = Sun Jan 1 08:59:60 2006 JST isdst=0 gmtoff=32400
  468. right/Europe/Paris Fri Jun 30 23:59:60 1972 UTC = Sat Jul 1 00:59:60 1972 CET isdst=0 gmtoff=3600
  469. right/Europe/Paris Wed Dec 31 23:59:60 2008 UTC = Thu Jan 1 00:59:60 2009 CET isdst=0 gmtoff=3600
  470. End
  471. def self.gen_variational_zdump_test(hint, data)
  472. sample = []
  473. data.each_line {|line|
  474. s = parse_zdump_line(line)
  475. sample << s if s
  476. }
  477. define_method(gen_test_name(hint)) {
  478. results = []
  479. sample.each {|tz, u, l, gmtoff|
  480. expected_utc = "%04d-%02d-%02d %02d:%02d:%02d UTC" % u
  481. expected = "%04d-%02d-%02d %02d:%02d:%02d %s" % (l+[format_gmtoff(gmtoff)])
  482. mesg_utc = "TZ=#{tz} Time.utc(#{u.map {|arg| arg.inspect }.join(', ')})"
  483. mesg = "#{mesg_utc}.localtime"
  484. with_tz(tz) {
  485. t = nil
  486. assert_nothing_raised(mesg) { t = Time.utc(*u) }
  487. assert_equal(expected_utc, time_to_s(t), mesg_utc)
  488. assert_nothing_raised(mesg) { t.localtime }
  489. results << [
  490. expected == time_to_s(t),
  491. gmtoff == t.gmtoff,
  492. format_gmtoff(gmtoff) == t.strftime("%z"),
  493. format_gmtoff(gmtoff, true) == t.strftime("%:z"),
  494. format_gmtoff2(gmtoff) == t.strftime("%::z")
  495. ]
  496. }
  497. }
  498. assert_include(results, [true, true, true, true, true])
  499. }
  500. end
  501. # tzdata-2014g fixed the offset for lisbon from -0:36:32 to -0:36:45.
  502. # [ruby-core:65058] [Bug #10245]
  503. gen_variational_zdump_test "lisbon", <<'End' if has_lisbon_tz
  504. Europe/Lisbon Mon Jan 1 00:36:31 1912 UTC = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2192
  505. Europe/Lisbon Mon Jan 1 00:36:44 1912 UT = Sun Dec 31 23:59:59 1911 LMT isdst=0 gmtoff=-2205
  506. Europe/Lisbon Sun Dec 31 23:59:59 1911 UT = Sun Dec 31 23:23:14 1911 LMT isdst=0 gmtoff=-2205
  507. End
  508. class TZ
  509. attr_reader :name
  510. def initialize(name, abbr, offset, abbr2 = nil, offset2 = nil)
  511. @name = name
  512. @abbr = abbr
  513. @offset = offset
  514. @abbr2 = abbr2
  515. @offset2 = offset2
  516. end
  517. def dst?(t)
  518. return false unless @offset2
  519. case t when Integer
  520. return nil
  521. end
  522. case t.mon
  523. when 4..9
  524. true
  525. else
  526. false
  527. end
  528. end
  529. def offset(t)
  530. (dst?(t) ? @offset2 : @offset)
  531. end
  532. def local_to_utc(t)
  533. t - offset(t)
  534. end
  535. def utc_to_local(t)
  536. t + offset(t)
  537. end
  538. def abbr(t)
  539. dst?(t) ? @abbr2 : @abbr
  540. end
  541. def ==(other)
  542. @name == other.name and abbr(0) == other.abbr(0) and offset(0) == other.offset(0)
  543. end
  544. def inspect
  545. "#<TZ: #@name #@abbr #@offset>"
  546. end
  547. end
  548. end
  549. module TestTimeTZ::WithTZ
  550. def subtest_new(time_class, tz, tzarg, tzname, abbr, utc_offset)
  551. abbr, abbr2 = *abbr
  552. utc_offset, utc_offset2 = *utc_offset
  553. t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
  554. utc_offset, abbr = utc_offset2, abbr2 if tz.dst?(t)
  555. assert_equal([2018, 9, 1, 12, 0, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
  556. h, m = (-utc_offset / 60).divmod(60)
  557. assert_equal(time_class.utc(2018, 9, 1, 12+h, m, 0).to_i, t.to_i)
  558. end
  559. def subtest_now(time_class, tz, tzarg, tzname, abbr, utc_offset)
  560. t = time_class.now(in: tzarg)
  561. assert_equal(tz, t.zone)
  562. end
  563. def subtest_getlocal(time_class, tz, tzarg, tzname, abbr, utc_offset)
  564. abbr, abbr2 = *abbr
  565. utc_offset, utc_offset2 = *utc_offset
  566. utc = time_class.utc(2018, 9, 1, 12, 0, 0)
  567. utc_offset, abbr = utc_offset2, abbr2 if tz.dst?(utc)
  568. t = utc.getlocal(tzarg)
  569. h, m = (utc_offset / 60).divmod(60)
  570. assert_equal([2018, 9, 1, 12+h, m, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
  571. assert_equal(time_class.utc(2018, 9, 1, 12, 0, 0), t)
  572. end
  573. def subtest_strftime(time_class, tz, tzarg, tzname, abbr, utc_offset)
  574. abbr, abbr2 = *abbr
  575. utc_offset, utc_offset2 = *utc_offset
  576. t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
  577. utc_offset, abbr = utc_offset2, abbr2 if tz.dst?(t)
  578. h, m = (utc_offset.abs / 60).divmod(60)
  579. h = -h if utc_offset < 0
  580. assert_equal("%+.2d%.2d %s" % [h, m, abbr], t.strftime("%z %Z"))
  581. end
  582. def subtest_plus(time_class, tz, tzarg, tzname, abbr, utc_offset)
  583. abbr, abbr2 = *abbr
  584. utc_offset, utc_offset2 = *utc_offset
  585. t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg) + 4000
  586. utc_offset, abbr = utc_offset2, abbr2 if tz.dst?(t)
  587. assert_equal([2018, 9, 1, 13, 6, 40, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
  588. m, s = (4000-utc_offset).divmod(60)
  589. h, m = m.divmod(60)
  590. assert_equal(time_class.utc(2018, 9, 1, 12+h, m, s), t)
  591. end
  592. def subtest_at(time_class, tz, tzarg, tzname, abbr, utc_offset)
  593. abbr, abbr2 = *abbr
  594. utc_offset, utc_offset2 = *utc_offset
  595. utc = time_class.utc(2018, 9, 1, 12, 0, 0)
  596. utc_offset, abbr = utc_offset2, abbr2 if tz.dst?(utc)
  597. h, m = (utc_offset / 60).divmod(60)
  598. t = time_class.at(utc, in: tzarg)
  599. assert_equal([2018, 9, 1, 12+h, m, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
  600. assert_equal(utc.to_i, t.to_i)
  601. utc = utc.to_i
  602. t = time_class.at(utc, in: tzarg)
  603. assert_equal([2018, 9, 1, 12+h, m, 0, tz], [t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.zone])
  604. assert_equal(utc, t.to_i)
  605. end
  606. def subtest_marshal(time_class, tz, tzarg, tzname, abbr, utc_offset)
  607. t = time_class.new(2018, 9, 1, 12, 0, 0, tzarg)
  608. t2 = Marshal.load(Marshal.dump(t))
  609. assert_equal(t, t2)
  610. assert_equal(t.utc_offset, t2.utc_offset)
  611. assert_equal(t.utc_offset, (t2+1).utc_offset)
  612. assert_instance_of(t.zone.class, t2.zone)
  613. assert_equal(t.dst?, t2.dst?)
  614. end
  615. def test_invalid_zone
  616. make_timezone("INVALID", "INV", 0)
  617. rescue => e
  618. assert_kind_of(StandardError, e)
  619. else
  620. assert false, "ArgumentError expected but nothing was raised."
  621. end
  622. def nametest_marshal_compatibility(time_class, tzname, abbr, utc_offset)
  623. data = [
  624. "\x04\x08Iu:".b, Marshal.dump(time_class)[3..-1],
  625. "\x0d""\xEF\xA7\x1D\x80\x00\x00\x00\x00".b,
  626. Marshal.dump({offset: utc_offset, zone: abbr})[3..-1],
  627. ].join('')
  628. t = Marshal.load(data)
  629. assert_equal(utc_offset, t.utc_offset)
  630. assert_equal(utc_offset, (t+1).utc_offset)
  631. # t.zone may be a mere String or timezone object.
  632. end
  633. ZONES = {
  634. "Asia/Tokyo" => ["JST", +9*3600],
  635. "America/Los_Angeles" => ["PST", -8*3600, "PDT", -7*3600],
  636. "Africa/Ndjamena" => ["WAT", +1*3600],
  637. }
  638. def make_timezone(tzname, abbr, utc_offset, abbr2 = nil, utc_offset2 = nil)
  639. self.class::TIME_CLASS.find_timezone(tzname)
  640. end
  641. def subtest_dst?(time_class, tz, tzarg, tzname, abbr, utc_offset)
  642. t = time_class.new(2018, 6, 22, 12, 0, 0, tzarg)
  643. return unless tz.dst?(t)
  644. assert_predicate t, :dst?
  645. t = time_class.new(2018, 12, 22, 12, 0, 0, tzarg)
  646. assert_not_predicate t, :dst?
  647. end
  648. instance_methods(false).grep(/\Asub(?=test_)/) do |subtest|
  649. test = $'
  650. ZONES.each_pair do |tzname, (abbr, utc_offset, abbr2, utc_offset2)|
  651. define_method("#{test}@#{tzname}") do
  652. tz = make_timezone(tzname, abbr, utc_offset, abbr2, utc_offset2)
  653. time_class = self.class::TIME_CLASS
  654. __send__(subtest, time_class, tz, tz, tzname, [abbr, abbr2], [utc_offset, utc_offset2])
  655. __send__(subtest, time_class, tz, tzname, tzname, [abbr, abbr2], [utc_offset, utc_offset2])
  656. end
  657. end
  658. end
  659. instance_methods(false).grep(/\Aname(?=test_)/) do |subtest|
  660. test = $'
  661. ZONES.each_pair do |tzname, (abbr, utc_offset)|
  662. define_method("#{test}@#{tzname}") do
  663. time_class = self.class::TIME_CLASS
  664. __send__(subtest, time_class, tzname, abbr, utc_offset)
  665. end
  666. end
  667. end
  668. end
  669. class TestTimeTZ::DummyTZ < Test::Unit::TestCase
  670. include TestTimeTZ::WithTZ
  671. class TIME_CLASS < ::Time
  672. ZONES = TestTimeTZ::WithTZ::ZONES
  673. def self.find_timezone(tzname)
  674. tz = ZONES[tzname] or raise ArgumentError, "Unknown timezone: #{name}"
  675. TestTimeTZ::TZ.new(tzname, *tz)
  676. end
  677. end
  678. def self.make_timezone(tzname, abbr, utc_offset, abbr2 = nil, utc_offset2 = nil)
  679. TestTimeTZ::TZ.new(tzname, abbr, utc_offset, abbr2, utc_offset2)
  680. end
  681. end
  682. begin
  683. require "tzinfo"
  684. rescue LoadError
  685. else
  686. class TestTimeTZ::GemTZInfo < Test::Unit::TestCase
  687. include TestTimeTZ::WithTZ
  688. class TIME_CLASS < ::Time
  689. def self.find_timezone(tzname)
  690. TZInfo::Timezone.get(tzname)
  691. end
  692. end
  693. def tz
  694. @tz ||= TZInfo::Timezone.get(tzname)
  695. end
  696. end
  697. end
  698. begin
  699. require "timezone"
  700. rescue LoadError
  701. else
  702. class TestTimeTZ::GemTimezone < Test::Unit::TestCase
  703. include TestTimeTZ::WithTZ
  704. class TIME_CLASS < ::Time
  705. def self.find_timezone(name)
  706. Timezone.fetch(name)
  707. end
  708. end
  709. def tz
  710. @tz ||= Timezone[tzname]
  711. end
  712. end
  713. end