"Yukihiro Matsumoto" <matz / zetabits.com> schrieb im Newsbeitrag news:985813012.022868.21589.nullmailer / ev.netlab.zetabits.com... > In message "[ruby-talk:13279] Re: Time Travel with Ruby" > on 01/03/29, Ernest Ellingson <erne / powernav.com> writes: > > |Well you can blame it on Windows but has anyone tried this on other systems. > |t=Time.local(2001, 4,1,2,0) > |puts t > > This prints "Sun Apr 01 03:00:00 EDT 2001" on my Linux box. > Since my timezone does not have DST, I tried on your timezone. > FYI, Ruby had a bug in DST boundary on versions prior to 2000-07-20. > First and most important: Thanks a lot for this very interesting programming language! Unfortunately Time.local also behaves strangely on my W95 notebook: Time.local on an unpatched ruby-1.6.2 is systematically 1 hour off during DST on my system. In Switzerland as in other european countries we switched to DST on 2000-03-25 02:00:00, so we lost the hour from 02:00 to 02:59. puts Time.local(2001, 3, 25, 1, 59, 59) ==> Sun Mar 25 00:59:59 GMT+1:00 2001 # wrong puts Time.local(2001, 3, 25, 2, 0, 0) ==> Sun Mar 25 03:00:00 GMT+1:00 2001 # dubious puts Time.local(2001, 3, 25, 3, 0, 0) ==> Sun Mar 25 04:00:00 GMT+1:00 2001 # wrong We will switch back from DST on 2000-10-28 02:00:00 puts Time.local(2001, 10, 28, 0, 0, 0) ==> Sun Oct 28 01:00:00 GMT+1:00 2001 # still wrong puts Time.local(2001, 10, 28, 1, 0, 0) ==> Sun Oct 28 01:00:00 GMT+1:00 2001 # strangely enough this is # correct the hour from # 01:00 to 02:00 on # 2001-10-28 is the only hour # where Ruby gets the correct # time during DST puts Time.local(2001, 10, 28, 2, 0, 0) ==> Sun Oct 28 02:00:00 GMT+1:00 2001 # correct the last sunday in march (when we will switch to DST again) in 2002 is 2002-03-31 puts Time.local(2002, 3, 31, 0, 59, 59) ==> Sun Mar 31 00:59:59 GMT+1:00 2002 # correct puts Time.local(2002, 3, 31, 1, 0, 0) ==> Sun Mar 31 00:00:00 GMT+1:00 2002 # wrong etc. (as you see Cygwin on W95 doesn't display correct TimeZone descriptions during DST, but i didn't check what would be needed to change Cygwin to use the TZ descriptions from Windows. The routine make_time_t from time.c displays the same strange behavior if it is compiled with VC6 which requires the replacement of gettimeofday by a simple call to time(NULL)) I applied the following patch to time.c to fix the strange behavior of ruby-1.6.2's Time.local on my W95 box. I have no idea if this patch is also working on other systems. --%<------------------------------------------------------ *** time.c Fri Dec 22 03:22:04 2000 --- time.c.new Thu Mar 29 22:35:54 2001 *************** make_time_t(tptr, utc_or_local) *** 357,365 **** } tm = localtime(&guess); if (!tm) goto error; ! if (lt.tm_isdst != tm->tm_isdst) { ! guess -= 3600; } #endif if (guess < 0) { goto out_of_range; --- 357,368 ---- } tm = localtime(&guess); if (!tm) goto error; ! if (tm->tm_isdst) { ! if (lt.tm_isdst == tm->tm_isdst || !lt.tm_isdst) { ! guess -= 3600; ! } } + #endif if (guess < 0) { goto out_of_range; --%<------------------------------------------------------ I used this script to check my patch. Store it as e.g. timelocal.rb and call it as ruby timelocal.rb year month day hours minutes seconds e.g. ruby timelocal.rb 2001 3 25 3 0 0 --%<------------------------------------------------------ def timegm(*args) args.push(1) mk_time(*args) end def timelocal(*args) mk_time(*args) end def mk_time(year, month, day, hours=0, minutes=0, seconds=0, gm_flag=0) below_secs = 0 above_secs = (2 ** 31 - 1).to_i secs = (below_secs + above_secs) / 2 inputs = [year, month, day, hours, minutes, seconds] tests = [] compare = 0 # counter = 0 while (below_secs <= above_secs) # counter += 1 secs = (below_secs + above_secs) / 2 if (gm_flag == 0) tests = ((Time.at(secs).to_a)[0..5]).reverse else tests = ((Time.at(secs).gmtime.to_a)[0..5]).reverse end compare = inputs <=> tests if (compare == 0) # puts "found after #{counter} iterations" return secs elsif (compare < 0) above_secs = secs - 1 elsif (compare > 0) below_secs = secs + 1 else raise "something terrible" end end raise "date non-existant #{inputs.join(', ')}" end if __FILE__ == $0 args = ARGV.map {|i| i.to_i} t = timelocal(*args) print "timelocal: " puts Time.at(t) t = timegm(*args) print "timegm: " puts Time.at(t).utc t = Time.local(*args).to_i print "Time.local: " puts Time.at(t) t = Time.gm(*args).to_i print "Time.gm: " puts Time.at(t).utc end --%<------------------------------------------------------