jetlag 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/LICENSE +18 -0
- data/README.md +83 -0
- data/Rakefile +8 -0
- data/jetlag.gemspec +28 -0
- data/lib/jetlag.rb +50 -0
- data/lib/jetlag/version.rb +3 -0
- data/rails/init.rb +2 -0
- data/spec/ar_timezone_spec.rb +198 -0
- data/spec/jetlag_spec.rb +121 -0
- data/spec/sanity_spec.rb +28 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +48 -0
- metadata +178 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@jetlag --create
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2011 Nathan Witmer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Jetlag
|
2
|
+
|
3
|
+
Patches for ActiveRecord 2.3.x timezone-handling code to allow for non-UTC
|
4
|
+
databases.
|
5
|
+
|
6
|
+
Rails 3 mostly works, see discussion below.
|
7
|
+
|
8
|
+
## Synopsis
|
9
|
+
|
10
|
+
This rails plugin patches ActiveRecord to fix the time quoting when timezones
|
11
|
+
are involved, especially when using a non-UTC database.
|
12
|
+
|
13
|
+
This started as a set of specs to explore the various combinations of
|
14
|
+
ActiveRecord and related time zone settings and their effect on timestamp values
|
15
|
+
as written and retrieved from a non-timezone-aware database.
|
16
|
+
|
17
|
+
The underlying motivation was to figure out the edge cases that exist when a
|
18
|
+
database is not running in UTC, and find where the ActiveRecord code fails to
|
19
|
+
handle this correctly. Eventually it ended up becoming a patch to correct the
|
20
|
+
invalid behavior.
|
21
|
+
|
22
|
+
## Rails 3
|
23
|
+
|
24
|
+
Rails 3 timezone handling is correct, especially with the default settings. If
|
25
|
+
your database is not in UTC, make sure `ENV["TZ"]` for your rails app is set
|
26
|
+
appropriately, and set `ActiveRecord::Base.default_timezone = :local`. For more
|
27
|
+
details, see the rails3 branch -- there are specs there showing that the
|
28
|
+
behavior is correct, even when changing Time.zone "per request".
|
29
|
+
|
30
|
+
## Discussion
|
31
|
+
|
32
|
+
The rails convention is to keep all data in UTC. If, however, due to legacy
|
33
|
+
reasons, your database is *not* UTC, Rails is unable to write (and thus read)
|
34
|
+
dates with the correct timezone. This can lead to subtle bugs and, essentially,
|
35
|
+
corrupted data.
|
36
|
+
|
37
|
+
ActiveRecord does the incorrect thing in the following cases (copied from spec
|
38
|
+
output):
|
39
|
+
|
40
|
+
with Time.zone_default set (i.e. config.time_zone=) and default_timezone = :local and time_zone_aware_attributes = true (default)
|
41
|
+
- writes local Time objects to the database in UTC (invalid storage)
|
42
|
+
- writes local UTC Time objects as UTC (invalid storage)
|
43
|
+
- writes TimeWithZone objects using UTC (invalid storage)
|
44
|
+
- reads the timestamp as local but with the UTC offset (invalid round-trip)
|
45
|
+
|
46
|
+
with Time.zone_default set (i.e. config.time_zone=) and default_timezone = :local and time_zone_aware_attributes = false
|
47
|
+
- writes bare UTC timestamps as UTC (invalid storage)
|
48
|
+
- writes TimeWithZone objects as UTC (invalid storage)
|
49
|
+
|
50
|
+
with Time.zone_default set (i.e. config.time_zone=) and AR::Base.default_timezone = :utc (default) and time_zone_aware_attributes = false
|
51
|
+
- does not write bare timestamps as UTC (invalid storage)
|
52
|
+
- reads the timestamp as UTC (invalid round trip)
|
53
|
+
|
54
|
+
with Time.zone_default not set (i.e. config.time_zone is nil) with default_timezone as :local (default)
|
55
|
+
- writes bare UTC timestamps as UTC (invalid storage)
|
56
|
+
|
57
|
+
with Time.zone_default not set (i.e. config.time_zone is nil) with default_timezone as :utc
|
58
|
+
- does not write local timestamps as UTC (invalid storage)
|
59
|
+
|
60
|
+
Jetlag patches AR's column quoting to handle timezones correctly.
|
61
|
+
|
62
|
+
## Installation
|
63
|
+
|
64
|
+
To use in your Rails 2.3.x application (as a plugin):
|
65
|
+
|
66
|
+
script/plugin install https://github.com/aniero/jetlag.git
|
67
|
+
|
68
|
+
If your database is not in UTC, set `ENV["TZ"]` explicitly in your
|
69
|
+
`config/environment.rb` to match the database's timezone, and also add the
|
70
|
+
following line after `config.time_zone = 'UTC'`:
|
71
|
+
|
72
|
+
config.active_record.default_timezone = :local
|
73
|
+
|
74
|
+
To run manually, e.g. non-rails use of ActiveRecord:
|
75
|
+
|
76
|
+
require "jetlag"
|
77
|
+
Jetlag.enable
|
78
|
+
|
79
|
+
To run the specs:
|
80
|
+
|
81
|
+
bundle
|
82
|
+
rake
|
83
|
+
|
data/Rakefile
ADDED
data/jetlag.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "jetlag/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "jetlag"
|
7
|
+
s.version = Jetlag::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Nathan Witmer"]
|
10
|
+
s.email = ["nwitmer@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/aniero/jetlag"
|
12
|
+
s.summary = %q{ActiveRecord timezone fixes for non-UTC databases}
|
13
|
+
s.description = %q{Patches ActiveRecord to fix timezone issues for non-UTC databases and/or non-UTC default timezones}
|
14
|
+
|
15
|
+
s.add_dependency "activerecord", "~> 2.3.8"
|
16
|
+
|
17
|
+
s.add_development_dependency "sqlite3-ruby"
|
18
|
+
s.add_development_dependency "rspec", "~> 1.3.0"
|
19
|
+
s.add_development_dependency "rspec-rails", "~> 1.3.0"
|
20
|
+
s.add_development_dependency "ZenTest"
|
21
|
+
s.add_development_dependency "autotest-growl"
|
22
|
+
s.add_development_dependency "autotest-fsevent"
|
23
|
+
|
24
|
+
s.files = `git ls-files`.split("\n")
|
25
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
end
|
data/lib/jetlag.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
module Jetlag
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :enabled
|
7
|
+
@enabled = false
|
8
|
+
end
|
9
|
+
|
10
|
+
module TimezoneAwareColumnQuoting
|
11
|
+
# calling #getutc or #getlocal on a TimeWithZone will return the
|
12
|
+
# underlying Time. This is desirable because Time#to_s(:db) does
|
13
|
+
# *not* convert to UTC first, unlike TimeWithZone.
|
14
|
+
# The same methods on a Time only change the timezone.
|
15
|
+
#
|
16
|
+
# This method is backported from Rails 3.
|
17
|
+
def quoted_date(value)
|
18
|
+
if ::Jetlag.enabled?
|
19
|
+
if value.acts_like?(:time)
|
20
|
+
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
21
|
+
value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
|
22
|
+
else
|
23
|
+
value
|
24
|
+
end.to_s(:db)
|
25
|
+
else
|
26
|
+
value.to_s(:db)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.enable
|
32
|
+
unless ::ActiveRecord::ConnectionAdapters::AbstractAdapter.ancestors.include?(TimezoneAwareColumnQuoting)
|
33
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
|
34
|
+
include TimezoneAwareColumnQuoting
|
35
|
+
end
|
36
|
+
::ActiveRecord::Base.default_timezone = :local
|
37
|
+
end
|
38
|
+
|
39
|
+
@enabled = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.disable
|
43
|
+
@enabled = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.enabled?
|
47
|
+
@enabled
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
context "with Time.zone_default set (i.e. config.time_zone=)" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
# simulate the initialize_time_zone rails initializer
|
7
|
+
Time.zone_default = Time.__send__(:get_zone, "Mountain Time (US & Canada)")
|
8
|
+
ActiveRecord::Base.default_timezone = :utc
|
9
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
10
|
+
|
11
|
+
Jetlag.disable
|
12
|
+
end
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@time = Time.parse("2011-04-12 11:30:00 -0600")
|
16
|
+
end
|
17
|
+
|
18
|
+
context "and default_timezone = :local" do
|
19
|
+
before :all do
|
20
|
+
ActiveRecord::Base.default_timezone = :local
|
21
|
+
end
|
22
|
+
|
23
|
+
context "and time_zone_aware_attributes = true (default)" do
|
24
|
+
before :all do
|
25
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
26
|
+
connect_and_define_model
|
27
|
+
end
|
28
|
+
|
29
|
+
it "writes local Time objects to the database in UTC (invalid storage)" do
|
30
|
+
item = @items.create :ts => @time
|
31
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "writes local UTC Time objects as UTC (invalid storage)" do
|
35
|
+
item = @items.create :ts => @time.utc
|
36
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "writes TimeWithZone objects using UTC (invalid storage)" do
|
40
|
+
item = @items.create :ts => @time.in_time_zone
|
41
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "reads the timestamp as local but with the UTC offset (invalid round-trip)" do
|
45
|
+
item = @items.create :ts => @time
|
46
|
+
ts = item.reload.ts
|
47
|
+
ts.inspect.should == "Tue, 12 Apr 2011 17:30:00 MDT -06:00"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "and time_zone_aware_attributes = false" do
|
52
|
+
before :all do
|
53
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
54
|
+
connect_and_define_model
|
55
|
+
end
|
56
|
+
|
57
|
+
it "does not write bare timestamps as UTC (ok)" do
|
58
|
+
item = @items.create :ts => @time
|
59
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "writes bare UTC timestamps as UTC (invalid storage)" do
|
63
|
+
item = @items.create :ts => @time.utc
|
64
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "writes TimeWithZone objects as UTC (invalid storage)" do
|
68
|
+
item = @items.create :ts => @time.in_time_zone
|
69
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "reads the timestamp as local with the correct offset (ok)" do
|
73
|
+
item = @items.create :ts => @time
|
74
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 -0600"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context "and AR::Base.default_timezone = :utc (default)" do
|
81
|
+
before :all do
|
82
|
+
ActiveRecord::Base.default_timezone = :utc
|
83
|
+
end
|
84
|
+
|
85
|
+
context "and time_zone_aware_attributes = true (default)" do
|
86
|
+
before :all do
|
87
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
88
|
+
connect_and_define_model
|
89
|
+
end
|
90
|
+
|
91
|
+
it "writes bare Time objects to the database in UTC (ok)" do
|
92
|
+
item = @items.create :ts => @time
|
93
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "writes bare UTC timestamps as UTC (ok)" do
|
97
|
+
item = @items.create :ts => @time.utc
|
98
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
99
|
+
end
|
100
|
+
|
101
|
+
it "writes TimeWithZone objects in UTC (ok)" do
|
102
|
+
item = @items.create :ts => @time.in_time_zone
|
103
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "reads the timestamp as UTC but keeps it in the local timezone (ok)" do
|
107
|
+
item = @items.create :ts => @time
|
108
|
+
item.reload.ts.inspect.should == "Tue, 12 Apr 2011 11:30:00 MDT -06:00"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
context "and time_zone_aware_attributes = false" do
|
114
|
+
before :all do
|
115
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
116
|
+
connect_and_define_model
|
117
|
+
end
|
118
|
+
|
119
|
+
it "does not write bare timestamps as UTC (invalid storage)" do
|
120
|
+
item = @items.create :ts => @time
|
121
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "writes bare UTC timestamps as UTC (ok)" do
|
125
|
+
item = @items.create :ts => @time.utc
|
126
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "writes TimeWithZone objects as UTC (ok)" do
|
130
|
+
item = @items.create :ts => @time
|
131
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
132
|
+
end
|
133
|
+
|
134
|
+
it "reads the timestamp as UTC (invalid round trip)" do
|
135
|
+
item = @items.create :ts => @time
|
136
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 UTC"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
context "with Time.zone_default not set (i.e. config.time_zone is nil)" do
|
145
|
+
before :all do
|
146
|
+
Time.zone_default = nil
|
147
|
+
ActiveRecord::Base.default_timezone = :local
|
148
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
149
|
+
|
150
|
+
connect_and_define_model
|
151
|
+
end
|
152
|
+
|
153
|
+
before :each do
|
154
|
+
@time = Time.parse("2011-04-12 11:30:00 -0600")
|
155
|
+
end
|
156
|
+
|
157
|
+
context "with default_timezone as :local (default)" do
|
158
|
+
|
159
|
+
it "does not write local timestamps as UTC (ok)" do
|
160
|
+
item = @items.create :ts => @time
|
161
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "writes bare UTC timestamps as UTC (invalid storage)" do
|
165
|
+
item = @items.create :ts => @time.utc
|
166
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
167
|
+
end
|
168
|
+
|
169
|
+
it "reads the timestamp as local with the correct offset (ok)" do
|
170
|
+
item = @items.create :ts => @time
|
171
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 -0600"
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
context "with default_timezone as :utc" do
|
177
|
+
before :all do
|
178
|
+
ActiveRecord::Base.default_timezone = :utc
|
179
|
+
end
|
180
|
+
|
181
|
+
it "does not write local timestamps as UTC (invalid storage)" do
|
182
|
+
item = @items.create :ts => @time
|
183
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
184
|
+
end
|
185
|
+
|
186
|
+
it "writes bare UTC timestamps as UTC (ok)" do
|
187
|
+
item = @items.create :ts => @time.utc
|
188
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "reads the timestamp as UTC with the correct offset (ok)" do
|
192
|
+
item = @items.create :ts => @time
|
193
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 UTC"
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
data/spec/jetlag_spec.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Jetlag do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
Jetlag.enable
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@time = Time.parse("2011-04-12 11:30:00 -0600")
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with config.time_zone" do
|
14
|
+
|
15
|
+
before :all do
|
16
|
+
Time.zone_default = Time.__send__(:get_zone, "Mountain Time (US & Canada)")
|
17
|
+
ActiveRecord::Base.default_timezone = :local
|
18
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with timezone aware attributes" do
|
22
|
+
before :all do
|
23
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
24
|
+
connect_and_define_model
|
25
|
+
end
|
26
|
+
|
27
|
+
it "writes local Time to the database in local time" do
|
28
|
+
item = @items.create :ts => @time
|
29
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "writes utc Time to the database in local time" do
|
33
|
+
item = @items.create :ts => @time.utc
|
34
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "writes TimeWithZone to the database in local time" do
|
38
|
+
item = @items.create :ts => @time.in_time_zone
|
39
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "reads a timestamp as a valid TimeWithZone" do
|
43
|
+
item = @items.create :ts => @time
|
44
|
+
item.reload.ts.inspect.should == "Tue, 12 Apr 2011 11:30:00 MDT -06:00"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context "without timezone aware attributes" do
|
50
|
+
|
51
|
+
before :all do
|
52
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
53
|
+
connect_and_define_model
|
54
|
+
end
|
55
|
+
|
56
|
+
it "writes local Time to the database in local time" do
|
57
|
+
item = @items.create :ts => @time
|
58
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "writes utc Time to the database in local time" do
|
62
|
+
item = @items.create :ts => @time.utc
|
63
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "writes TimeWithZone to the database in local time" do
|
67
|
+
item = @items.create :ts => @time.in_time_zone
|
68
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
69
|
+
end
|
70
|
+
|
71
|
+
it "reads a timestamp as a valid Time" do
|
72
|
+
item = @items.create :ts => @time
|
73
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 -0600"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end # configured timezone
|
79
|
+
|
80
|
+
context "without config.timezone" do
|
81
|
+
|
82
|
+
before :all do
|
83
|
+
Time.zone_default = nil
|
84
|
+
ActiveRecord::Base.default_timezone = :local
|
85
|
+
ActiveRecord::Base.time_zone_aware_attributes = false
|
86
|
+
|
87
|
+
connect_and_define_model
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
context "with default_timezone as :local (default)" do
|
92
|
+
it "writes UTC time as local" do
|
93
|
+
item = @items.create :ts => @time.utc
|
94
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 11:30:00"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "reads time as local" do
|
98
|
+
item = @items.create :ts => @time.utc
|
99
|
+
item.reload.ts.inspect.should == "2011-04-12 11:30:00 -0600"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "with default_timezone as :utc" do
|
104
|
+
before :all do
|
105
|
+
ActiveRecord::Base.default_timezone = :utc
|
106
|
+
end
|
107
|
+
|
108
|
+
it "writes local Time as utc (wrong, but expected)" do
|
109
|
+
item = @items.create :ts => @time
|
110
|
+
item.reload.ts_before_type_cast.should == "2011-04-12 17:30:00"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "reads time as UTC" do
|
114
|
+
item = @items.create :ts => @time
|
115
|
+
item.reload.ts.inspect.should == "2011-04-12 17:30:00 UTC"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/spec/sanity_spec.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "basic sanity checks" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
connect_and_define_model
|
7
|
+
end
|
8
|
+
|
9
|
+
it "can load the columns from the test database" do
|
10
|
+
@items.should have(2).columns
|
11
|
+
end
|
12
|
+
|
13
|
+
it "has the timezone set to US/Mountain" do
|
14
|
+
ENV["TZ"].should == "US/Mountain"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has a sane representation for Time" do
|
18
|
+
Time.parse("2011-04-12 11:30:00 -0600").inspect.should == "2011-04-12 11:30:00 -0600"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has a sane resentation for TimeWithZone" do
|
22
|
+
Time.zone_default = Time.__send__(:get_zone, "Mountain Time (US & Canada)")
|
23
|
+
Time.parse("2011-04-12 11:30:00 -0600").in_time_zone.inspect.should ==
|
24
|
+
"Tue, 12 Apr 2011 11:30:00 MDT -06:00"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.require :default, :development
|
3
|
+
|
4
|
+
require "time" # for parse
|
5
|
+
|
6
|
+
Jetlag.enable
|
7
|
+
|
8
|
+
Spec::Runner.configure do |config|
|
9
|
+
|
10
|
+
config.before :all do
|
11
|
+
ENV["TZ"] = "US/Mountain"
|
12
|
+
|
13
|
+
@dbfile = "/tmp/jetlag_test.db"
|
14
|
+
FileUtils.rm @dbfile if File.exist?(@dbfile)
|
15
|
+
ActiveRecord::Base.establish_connection(
|
16
|
+
:adapter => "sqlite3",
|
17
|
+
:database => @dbfile
|
18
|
+
)
|
19
|
+
|
20
|
+
ActiveRecord::Migration.class_eval do
|
21
|
+
suppress_messages do
|
22
|
+
create_table :items do |t|
|
23
|
+
t.timestamp :ts, :null => false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActiveRecord::Base.remove_connection
|
29
|
+
end
|
30
|
+
|
31
|
+
config.after :all do
|
32
|
+
ActiveRecord::Base.remove_connection
|
33
|
+
FileUtils.rm @dbfile
|
34
|
+
end
|
35
|
+
|
36
|
+
def connect_and_define_model
|
37
|
+
ActiveRecord::Base.establish_connection(
|
38
|
+
:adapter => "sqlite3",
|
39
|
+
:database => @dbfile
|
40
|
+
)
|
41
|
+
# the model is defined dynamically on request since the
|
42
|
+
# AR::Base.time_zone_aware_attributes setting determines how
|
43
|
+
# attribute writers are defined.
|
44
|
+
@items = Class.new(ActiveRecord::Base) { set_table_name "items"}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
metadata
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jetlag
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Witmer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.3.8
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.3.8
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sqlite3-ruby
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.0
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.3.0
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec-rails
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.3.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.3.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: ZenTest
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: autotest-growl
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: autotest-fsevent
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: Patches ActiveRecord to fix timezone issues for non-UTC databases and/or
|
127
|
+
non-UTC default timezones
|
128
|
+
email:
|
129
|
+
- nwitmer@gmail.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- .gitignore
|
135
|
+
- .rvmrc
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- jetlag.gemspec
|
141
|
+
- lib/jetlag.rb
|
142
|
+
- lib/jetlag/version.rb
|
143
|
+
- rails/init.rb
|
144
|
+
- spec/ar_timezone_spec.rb
|
145
|
+
- spec/jetlag_spec.rb
|
146
|
+
- spec/sanity_spec.rb
|
147
|
+
- spec/spec.opts
|
148
|
+
- spec/spec_helper.rb
|
149
|
+
homepage: https://github.com/aniero/jetlag
|
150
|
+
licenses: []
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ! '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
requirements: []
|
168
|
+
rubyforge_project:
|
169
|
+
rubygems_version: 1.8.24
|
170
|
+
signing_key:
|
171
|
+
specification_version: 3
|
172
|
+
summary: ActiveRecord timezone fixes for non-UTC databases
|
173
|
+
test_files:
|
174
|
+
- spec/ar_timezone_spec.rb
|
175
|
+
- spec/jetlag_spec.rb
|
176
|
+
- spec/sanity_spec.rb
|
177
|
+
- spec/spec.opts
|
178
|
+
- spec/spec_helper.rb
|