Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

timezone problem #3

Closed
sigmike opened this issue Oct 10, 2009 · 20 comments
Closed

timezone problem #3

sigmike opened this issue Oct 10, 2009 · 20 comments

Comments

@sigmike
Copy link
Contributor

sigmike commented Oct 10, 2009

There are a few issues with time zones.

  1. DateTime offset is not kept when I use a DateTime object as reference
  2. Using a utc Time object as reference changes the time

There's an easy workaround for 2., but 1. is a problem.

I added tests to illustrate this : http://github.com/piglop/timecop/tree/timezone_tests

@jtrupiano
Copy link
Collaborator

@piglop,

I can confirm that the test cases you have supplied do in fact fail. I am not certain yet whether or not I think they are valid test cases though. I'll be taking a deeper look into these issues later this week.

-John

@sigmike
Copy link
Contributor Author

sigmike commented Oct 12, 2009

The problem is when I freeze or travel, DateTime.now always returns an UTC time (offset is 0) with local values in individual fields (year, hour, etc.). Whereas standard DateTime.now returns a true local time (local values in individual fields and local offset).
The problem arises when you convert DateTime.now to another timezone (or even the local timezone). The individual fields are changed according to the new timezone. But since the individual values were already local, the converted time is wrong.
I've added another test in the branch to illustrate this.

@jtrupiano
Copy link
Collaborator

@piglop thanks for following up with more information. This will be helpful.

@sigmike
Copy link
Contributor Author

sigmike commented Oct 12, 2009

I found a solution and made a single commit from master here : http://github.com/piglop/timecop/commit/7478f7ff28f2b5ea4b5476622c5de36bf7edca9f
I also added a fix for the problem with Time.utc here : http://github.com/piglop/timecop/commit/550183c5fb9fca7ac4351e16dc1cae4469c292cb

@jtrupiano
Copy link
Collaborator

@piglop it's taken me a couple of extra days to get around to this. I'll be able to review these patches this weekend and hopefully get them merged in.

Thanks again.

-John

@sigmike
Copy link
Contributor Author

sigmike commented Oct 18, 2009

@sigmike
Copy link
Contributor Author

sigmike commented Oct 25, 2009

@jtrupiano
Copy link
Collaborator

Included in 0.3.2 release

@chris
Copy link

chris commented Oct 26, 2009

I haven't studied the code changes, but timecop 0.3.2 has definitely broken in terms of how Time.now works when freezing. For example, here's a tiny "test" to illustrate:

it "should behave" do
  puts "Time (local) at start is: #{Time.now}"
  puts "Time (UTC) at start is  : #{Time.now.utc}"
  Timecop.freeze(3.hours.from_now) do
    puts "Time (local) after timecop added 3 hours: #{Time.now.utc}"
    puts "Time (UTC) after timecop added 3 hours  : #{Time.now.utc}"
  end
end

If I run that with Timecop 0.3.1, I get:

Time (local) at start is: Mon Oct 26 13:40:39 -0700 2009
Time (UTC) at start is : Mon Oct 26 20:40:39 UTC 2009
Time (local) after timecop added 3 hours: Mon Oct 26 23:40:39 UTC 2009
Time (UTC) after timecop added 3 hours : Mon Oct 26 23:40:39 UTC 2009

But, if I run that with Timecop 0.3.2, I get:
Time (local) at start is: Mon Oct 26 13:41:30 -0700 2009
Time (UTC) at start is : Mon Oct 26 20:41:30 UTC 2009
Time (local) after timecop added 3 hours: Mon Oct 26 16:41:30 UTC 2009
Time (UTC) after timecop added 3 hours : Mon Oct 26 16:41:30 UTC 2009

So, now, time has gone backwards. In both cases my local timezone has been changed to UTC. What it's doing in 0.3.2 appears to be that it's adding 3 hours to the "Time.now" result, and not taking into account the Time zone.

@jtrupiano
Copy link
Collaborator

@chris thanks for the report. If you have a free moment and can add a failing test to the test suite, I'd really appreciate it.

In the meantime, I suspect you'll get away with 0.3.1. It will probably be several days before I can get around to this.

@sigmike
Copy link
Contributor Author

sigmike commented Oct 27, 2009

While I was trying to write a test case for this problem, I discovered the current test suite fails since DST shift.
Indeed, in the new tests, we check that DateTime.now returns a local time, i.e. a DateTime with the current local offset. But when we create a DateTime in summer while we're in winter, the local offset should not be the same.
And I couldn't find a way to get the local offset at a specific time with the DateTime class. It may be possible with the Time class.

I couldn't write a test case for chris's problem, but I could reproduce it in a Rails environment.

I won't have a lot of time to check these problems this week.

@chris
Copy link

chris commented Oct 28, 2009

I'm looking into it. I'm starting to think it's a conflict with Rails though. I forked the code, added a test case and it behaves properly when using simple math to add 3 hours to the time. So, I'm going to look into whether it's Rails' extensions for doing things like "3.hours.from_now" and if that messes with it. Like you guys, I'm pretty busy, and Timecop 0.3.1 works for me, so I'm not sure when I'll resolve this.

@jtrupiano
Copy link
Collaborator

So I've had some time to really dig into this.

@chris, I think I have your issues worked out. I'll be releasing a prerelease version of timecop in a couple of days that I'll want you to try out for me. If you care to try my latest release candidate before I get the prerelease version sorted out, you can pull it down from a new branch named 'rewind'.

@piglop, there is a separate problem related to the patch you originally submitted. You had noticed behavior where traveling to times/datetimes in a different timezone were losing the timezone information, causing that time to be represented as UTC. Your patch corrected this, but at the same time underscored a new issue that I don't think we can solve.

The problem lies in the fact that a DateTime is incapable of representing DST properly. A DateTime only carries an offset (e.g. +0200), but this is not enough information for us to know if this particular DateTime instance should be subject to DST. Different timezones exist within the same offset, and some observe DST while others do not.

Due to this limitation, you can end up with the following test case failing:

t = DateTime.parse("2009-10-11 00:38:00 +0200")
  assert_equal "+02:00", t.zone
  Timecop.freeze(t) do
    assert_equal t, DateTime.now.new_offset(t.offset)
  end

I have pushed a new branch "rewind" to GitHub where you can see this test currently failing.

As a result of this finding, I am seriously considering removing the ability to pass a DateTime instance to Timecop calls. My concern is that this is simply too little known (that DateTime's cannot represent DST) and will cause many people headaches if we allow them to do so.

I'm curious what your thoughts are.

@jtrupiano
Copy link
Collaborator

The gemspec in the 'rewind' branch now specifies a prerelease version (0.3.3.rc1). I'd really appreciate it if you guys (@chris and @piglop) could give it a try with your respective problems and report back to me.

@jtrupiano
Copy link
Collaborator

Note that if you had previously installed 0.3.3 that it will take precedence over 0.3.3.rc1. I'm still getting the hang of this prerelease workflow...

@jtrupiano
Copy link
Collaborator

I have released 0.3.4.rc1 as a prerelease gem. You can install it via: gem install/update --prerelease timecop

@jtrupiano
Copy link
Collaborator

Hey guys,

I found some other problems with 0.3.4.rc1 that I think I've fixed.

Can you take a moment to try upgrading to timecop 0.3.4.rc2 on your respective projects and let me know if I've introduced any regressions? It is a prerelease gem so you'll need to specify that when installing the gem: gem install timecop --pre -v0.3.4.rc2

This is just for verification purposes. Your projects should not depend on this version of the gem. If no regressions are found I will then officially release version 0.3.4 at which point you should upgrade your projects' dependencies.

Thanks for your help.

-John

@richievos
Copy link

@jtrupiano not sure this is exactly the same bug, but you've fixed mine in your prerelease gem.

I have a rails app with the timezone set to Eastern. My box is running Central

In 0.3.2:
require 'timecop'
>> time = Time.local(2000, 1, 1)
=> Sat Jan 01 00:00:00 -0600 2000
>> Timecop.freeze(time)
=> Sat, 01 Jan 2000 00:00:00 EST -05:00
>> Time.now
=> Sat, 01 Jan 2000 00:00:00 EST -05:00

Note it's an hour off. In 0.3.4.rc2 it is correct.

@chris
Copy link

chris commented Dec 2, 2009

0.3.4.rc2 is working in all my current tests. It does still change the local time zone to be UTC (from whatever it previously was) though. e.g. (output from my same example above):

Time (local) at start is: Tue Dec 01 21:13:45 -0800 2009
Time (UTC) at start is  : Wed Dec 02 05:13:45 UTC 2009
Time (local) after timecop added 3 hours: Wed Dec 02 08:13:45 UTC 2009
Time (UTC) after timecop added 3 hours  : Wed Dec 02 08:13:45 UTC 2009

@jtrupiano
Copy link
Collaborator

@JerryVos excellent. Your issue is one of the issues I have been trying to solve since 0.3.1.

@chris can you show me a sample session from either irb or script/console? Specifically I want to know which set of arguments you're passing to Timecop.freeze or Timecop.travel.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants