greenwich 0.0.5 → 1.0.0
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 +9 -1
- data/.rvmrc +1 -1
- data/Gemfile +3 -1
- data/README.md +46 -41
- data/Rakefile +1 -0
- data/greenwich.gemspec +8 -4
- data/lib/greenwich.rb +7 -5
- data/lib/greenwich/conversion.rb +82 -0
- data/lib/greenwich/time_zone.rb +7 -0
- data/lib/greenwich/utilities.rb +23 -11
- data/lib/greenwich/version.rb +1 -1
- data/spec/greenwich/conversion_spec.rb +313 -0
- data/spec/greenwich/utilities_spec.rb +143 -49
- data/spec/spec_helper.rb +0 -6
- data/spec/support/focused.rb +7 -0
- data/spec/support/pending.rb +4 -0
- metadata +153 -62
- data/lib/greenwich/rails.rb +0 -85
- data/lib/greenwich/time_with_zone.rb +0 -30
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use --create ruby-1.9.
|
1
|
+
rvm use --create ruby-1.9.3-p125@greenwich
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -29,90 +29,95 @@ Initialization
|
|
29
29
|
|
30
30
|
You add Greenwich to your models like so:
|
31
31
|
|
32
|
-
|
32
|
+
time_with_time_zone :your_column_name_utc
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
By default, Greenwich removes the `_utc` from the column name and uses
|
35
|
+
the resulting string as the composed field.
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
For example, the above call would result in a composed field called
|
38
|
+
`your_column_name`.
|
39
39
|
|
40
|
-
|
40
|
+
### Time Zones ###
|
41
41
|
|
42
|
-
Greenwich will
|
42
|
+
Greenwich will try to use convention to choose a time zone column name
|
43
|
+
based on the time field you choose.
|
43
44
|
|
44
|
-
|
45
|
-
* `_datetime`
|
45
|
+
time_with_time_zone :started_at_utc
|
46
46
|
|
47
|
-
|
47
|
+
Will look for a column called `started_at_time_zone` which contains the
|
48
|
+
time zone for the time field.
|
48
49
|
|
49
|
-
|
50
|
+
#### Custom Time Zone ####
|
50
51
|
|
51
|
-
|
52
|
+
If you want to use the same time zone for multiple time fields or just
|
53
|
+
don't like the custom one we choose for you, you can pass a `:time_zone`
|
54
|
+
option which will override our default.
|
52
55
|
|
53
|
-
|
56
|
+
time_with_time_zone :started_at_utc, :time_zone => :started_at_zone
|
54
57
|
|
55
|
-
|
58
|
+
Will tell Greenwich that when the user accesses the `started_at` method,
|
59
|
+
it will use the information from the `started_at_zone` column for its
|
60
|
+
time zone.
|
56
61
|
|
57
|
-
|
62
|
+
### Convention... but missing a little configuration ###
|
58
63
|
|
59
|
-
|
60
|
-
|
64
|
+
We're on `v1.0.0` and have more features planned in the future, however
|
65
|
+
for now, all columns passed to `time_with_time_zone` _must_ end in `_utc`.
|
61
66
|
|
62
67
|
Usage
|
63
68
|
--------------------------------
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
**Note:** _These examples assume the application's default time zone is set to UTC.
|
70
|
+
If you have modified the default time zone, directly accessing your DateTime field
|
71
|
+
will render it in **that** time zone and not UTC._
|
67
72
|
|
68
73
|
When working with your instances, Greenwich will convert to the proper time zone when
|
69
|
-
you access it. So if you've
|
74
|
+
you access it. So if you've defined a Greenwich time field like this:
|
75
|
+
|
76
|
+
time_with_time_zone :started_at_utc
|
70
77
|
|
71
|
-
|
78
|
+
And if you've previously saved a DateTime like this:
|
79
|
+
|
80
|
+
my_model.started_at_utc = Time.utc(2011, 7, 4, 13, 0, 0)
|
81
|
+
my_model.started_at_time_zone = 'Alaska'
|
72
82
|
|
73
83
|
Then that will result in your model returning the following values (assuming these
|
74
84
|
particular columns exist in the database):
|
75
85
|
|
76
|
-
my_model.
|
77
|
-
my_model.
|
78
|
-
my_model.start_time_zone # => 'Central Standard Time'
|
79
|
-
my_model.time_zone # => 'Central Standard Time'
|
86
|
+
my_model.started_at_utc # => ActiveSupport::TimeWithZone 2011-07-04 13:00:00 UTC
|
87
|
+
my_model.started_at_time_zone # => ActiveSupport::TimeZone 'Alaska'
|
80
88
|
|
81
|
-
Whereas asking Greenwich for the value of `
|
89
|
+
Whereas asking Greenwich for the value of `started_at` will result in:
|
82
90
|
|
83
|
-
my_model.
|
91
|
+
my_model.started_at # => ActiveSupport::TimeWithZone 2011-07-04 04:00:00 AKDT
|
84
92
|
|
85
93
|
If you then change your time zone:
|
86
94
|
|
87
|
-
my_model.
|
95
|
+
my_model.started_at_time_zone = 'Hawaii'
|
88
96
|
|
89
97
|
Then calling the attributes on your model will result in the following:
|
90
98
|
|
91
|
-
my_model.
|
92
|
-
my_model.
|
93
|
-
my_model.start_time_zone # => 'Eastern Standard Time'
|
94
|
-
my_model.time_zone # => 'Eastern Standard Time'
|
99
|
+
my_model.started_at_utc # => ActiveSupport::TimeWithZone 2011-07-04 13:00:00 UTC
|
100
|
+
my_model.started_at_time_zone # => ActiveSupport::TimeZone 'Hawaii'
|
95
101
|
|
96
|
-
And again, asking Greenwich for the value of `
|
102
|
+
And again, asking Greenwich for the value of `started_at` will result in:
|
97
103
|
|
98
|
-
my_model.
|
104
|
+
my_model.started_at # => ActiveSupport::TimeWithZone 2011-07-04 03:00:00 HADT
|
99
105
|
|
100
106
|
Issues
|
101
107
|
------
|
102
108
|
|
103
|
-
If you have problems, please create a [Github issue](
|
109
|
+
If you have problems, please create a [Github issue](issues).
|
104
110
|
|
105
111
|
Credits
|
106
112
|
-------
|
107
113
|
|
108
|
-

|
109
115
|
|
110
|
-
greenwich is maintained by [
|
116
|
+
greenwich is maintained by [Chrrpy, LLC](http://chirrpy.com)
|
111
117
|
|
112
|
-
The names and logos for
|
118
|
+
The names and logos for Chirrpy are trademarks of Chrrpy, LLC
|
113
119
|
|
114
120
|
License
|
115
121
|
-------
|
116
122
|
|
117
|
-
greenwich is Copyright © 2011
|
118
|
-
|
123
|
+
greenwich is Copyright © 2011 Chirrpy. It is free software, and may be redistributed under the terms specified in the LICENSE file.
|
data/Rakefile
CHANGED
data/greenwich.gemspec
CHANGED
@@ -11,9 +11,9 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.version = Greenwich::VERSION
|
12
12
|
s.platform = Gem::Platform::RUBY
|
13
13
|
|
14
|
-
s.authors = ["
|
15
|
-
s.email = ["
|
16
|
-
s.homepage = "http://github.com/
|
14
|
+
s.authors = ["jfelchner", "m5rk"]
|
15
|
+
s.email = ["jeff+greenwich@chirrpy.com"]
|
16
|
+
s.homepage = "http://github.com/chirrpy/greenwich"
|
17
17
|
|
18
18
|
s.summary = %q{Allowing users to select dates with custom time zones since 2011.}
|
19
19
|
s.description = %q{Store all of your times in the database as UTC but want to give your users the ability to choose a custom time zone for each instance of a DateTime field?}
|
@@ -28,9 +28,13 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.require_paths = ["lib"]
|
29
29
|
#= Manifest =#
|
30
30
|
|
31
|
-
s.add_dependency('activerecord',
|
31
|
+
s.add_dependency('activerecord', '~> 3.0')
|
32
|
+
s.add_dependency('activesupport', '~> 3.0')
|
33
|
+
s.add_dependency('tzinfo', '~> 0.3')
|
32
34
|
|
33
35
|
s.add_development_dependency('bundler', '~> 1.0')
|
34
36
|
s.add_development_dependency('rspec', '~> 2.6')
|
35
37
|
s.add_development_dependency('yard', '~> 0.7')
|
38
|
+
s.add_development_dependency('sqlite3', '~> 1.3')
|
39
|
+
s.add_development_dependency('pry')
|
36
40
|
end
|
data/lib/greenwich.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
1
|
+
require 'tzinfo'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'greenwich/conversion'
|
5
|
+
require 'greenwich/time_zone'
|
6
|
+
require 'greenwich/utilities'
|
7
|
+
require 'greenwich/version'
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Greenwich
|
2
|
+
module Conversion
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def time_with_time_zone(utc_time_field, options = {})
|
7
|
+
time_field = utc_time_field.to_s.gsub /_utc$/, ''
|
8
|
+
time_zone_field = options[:time_zone] || "#{time_field}_time_zone"
|
9
|
+
|
10
|
+
class_eval do
|
11
|
+
columns_hash[time_field] = ActiveRecord::ConnectionAdapters::Column.new(time_field, nil, "datetime")
|
12
|
+
end
|
13
|
+
|
14
|
+
define_method "#{time_field}_utc=" do |value|
|
15
|
+
greenwich_time_fields_converted["#{time_field}_utc"] = true
|
16
|
+
|
17
|
+
super(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
define_method time_field do
|
21
|
+
time_zone = Greenwich::Utilities.get_time_zone(self, time_zone_field)
|
22
|
+
time = read_attribute(utc_time_field)
|
23
|
+
time = time.in_time_zone(time_zone) if time && time_zone
|
24
|
+
|
25
|
+
time
|
26
|
+
end
|
27
|
+
|
28
|
+
define_method "#{time_field}=" do |value|
|
29
|
+
time_zone = Greenwich::Utilities.get_time_zone(self, time_zone_field)
|
30
|
+
time = Greenwich::Utilities.coerce_to_time_without_zone(value)
|
31
|
+
time = ActiveSupport::TimeWithZone.new(nil, time_zone, time) if time && time_zone
|
32
|
+
|
33
|
+
greenwich_time_fields_converted["#{time_field}_utc"] = true unless time_zone.nil?
|
34
|
+
|
35
|
+
write_attribute(utc_time_field, time)
|
36
|
+
end
|
37
|
+
|
38
|
+
time_zone time_zone_field.to_sym, :for => utc_time_field.to_sym
|
39
|
+
end
|
40
|
+
|
41
|
+
def time_zone(name, options = {})
|
42
|
+
associated_time_fields = Array.wrap(options[:for]).map {|f| f.to_s.gsub /_utc$/, ''}
|
43
|
+
|
44
|
+
define_method name do
|
45
|
+
time_zone_name = read_attribute(name)
|
46
|
+
|
47
|
+
Greenwich::Utilities.coerce_to_time_zone(time_zone_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
define_method "#{name}=" do |value|
|
51
|
+
time_zone = Greenwich::Utilities.coerce_to_time_zone_name(value)
|
52
|
+
write_attribute(name, time_zone)
|
53
|
+
|
54
|
+
associated_time_fields.each do |time_field|
|
55
|
+
if greenwich_time_field_needs_conversion?(time_field, name)
|
56
|
+
send("#{time_field}=".to_sym, read_attribute("#{time_field}_utc"))
|
57
|
+
|
58
|
+
greenwich_time_fields_converted["#{time_field}_utc"] = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def greenwich_time_fields_converted
|
66
|
+
@greenwich_time_fields_converted ||= {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def greenwich_time_fields_converted=(value)
|
70
|
+
@greenwich_time_fields_converted = value
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def greenwich_time_field_needs_conversion?(time_field, time_zone_field)
|
75
|
+
(send("#{time_zone_field}_was".to_sym).nil? || send("#{time_field}_utc_was").nil?) &&
|
76
|
+
read_attribute("#{time_field}_utc").present? &&
|
77
|
+
self.greenwich_time_fields_converted["#{time_field}_utc"].nil?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
ActiveRecord::Base.send :include, Greenwich::Conversion
|
data/lib/greenwich/utilities.rb
CHANGED
@@ -6,22 +6,34 @@ module Greenwich
|
|
6
6
|
get_target_column(target_columns, columns)
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.
|
10
|
-
|
9
|
+
def self.get_time_zone(object, time_zone_field_name)
|
10
|
+
begin
|
11
|
+
time_zone_name = object.send(time_zone_field_name.to_sym)
|
12
|
+
rescue
|
13
|
+
time_zone_name = ''
|
14
|
+
end
|
11
15
|
|
12
|
-
|
16
|
+
Greenwich::Utilities.coerce_to_time_zone(time_zone_name)
|
13
17
|
end
|
14
18
|
|
15
|
-
def self.
|
16
|
-
return nil
|
19
|
+
def self.coerce_to_time_zone(value)
|
20
|
+
return nil if value.nil?
|
21
|
+
return value if value.is_a? ActiveSupport::TimeZone
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
ActiveSupport::TimeZone.new(value)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.coerce_to_time_zone_name(value)
|
27
|
+
coerce_to_time_zone(value).try(:name)
|
28
|
+
end
|
23
29
|
|
24
|
-
|
30
|
+
def self.coerce_to_time_without_zone(value)
|
31
|
+
return value if value.is_a?(Time)
|
32
|
+
|
33
|
+
value.gsub! /\s[-+]\d{4}$/, '' if value.respond_to? :gsub!
|
34
|
+
value.to_time if value.respond_to? :to_time
|
35
|
+
rescue ArgumentError
|
36
|
+
nil
|
25
37
|
end
|
26
38
|
|
27
39
|
private
|
data/lib/greenwich/version.rb
CHANGED
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
root = File.expand_path(File.join(File.dirname(__FILE__), '../..'))
|
5
|
+
db_root = File.join(root, 'db')
|
6
|
+
|
7
|
+
Dir.mkdir(db_root) unless File.exists?(db_root)
|
8
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
|
9
|
+
:database => "#{db_root}/conversion.db")
|
10
|
+
|
11
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'model_with_time_zones'")
|
12
|
+
ActiveRecord::Base.connection.create_table(:model_with_time_zones) do |t|
|
13
|
+
t.datetime :started_at_utc
|
14
|
+
t.datetime :ended_at_utc
|
15
|
+
t.string :time_zone
|
16
|
+
end
|
17
|
+
|
18
|
+
class ModelWithTimeZone < ActiveRecord::Base
|
19
|
+
include Greenwich::Conversion
|
20
|
+
|
21
|
+
attr_accessible :started_at_utc,
|
22
|
+
:ended_at_utc,
|
23
|
+
:time_zone
|
24
|
+
|
25
|
+
time_with_time_zone :started_at_utc, :time_zone => :time_zone
|
26
|
+
time_with_time_zone :ended_at_utc, :time_zone => :time_zone
|
27
|
+
|
28
|
+
time_zone :time_zone, :for => [:started_at_utc, :ended_at_utc]
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Greenwich::Conversion do
|
32
|
+
describe '.time_with_time_zone' do
|
33
|
+
let(:model) { ModelWithTimeZone.new }
|
34
|
+
let(:alaskan_time_zone) { ActiveSupport::TimeZone.new('Alaska') }
|
35
|
+
|
36
|
+
describe '.columns_hash' do
|
37
|
+
it 'adds the virtual column to the columns_hash for the time field' do
|
38
|
+
ModelWithTimeZone.columns_hash.keys.should include 'started_at'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'adds the virtual column with a `datetime` type' do
|
42
|
+
ModelWithTimeZone.columns_hash['started_at'].type.should eql :datetime
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#time_field_utc=' do
|
47
|
+
let(:model) { ModelWithTimeZone.new }
|
48
|
+
let(:alaskan_time_zone) { ActiveSupport::TimeZone.new('Alaska') }
|
49
|
+
let(:raw_time_field) { model.send(:read_attribute, :started_at_utc) }
|
50
|
+
|
51
|
+
context 'when the time field is set via the writer' do
|
52
|
+
before { model.started_at_utc = Time.utc(2012, 1, 2, 12, 59, 1) }
|
53
|
+
|
54
|
+
it 'is not changed' do
|
55
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 12, 59, 1)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'is not eligible for conversion' do
|
59
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'and the time zone is subsequently set' do
|
63
|
+
before { model.time_zone = alaskan_time_zone }
|
64
|
+
|
65
|
+
it 'is not changed' do
|
66
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 12, 59, 1)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#time_field' do
|
73
|
+
context 'when it is nil' do
|
74
|
+
before { model.send :write_attribute, :started_at_utc, nil }
|
75
|
+
|
76
|
+
it 'is nil' do
|
77
|
+
model.started_at.should be_nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when there is no time zone' do
|
82
|
+
let(:raw_time_value) { Time.utc(2012, 1, 1, 12, 0, 0) }
|
83
|
+
|
84
|
+
before do
|
85
|
+
model.send :write_attribute, :started_at_utc, raw_time_value
|
86
|
+
model.stub(:time_zone).and_return nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns the raw time field' do
|
90
|
+
model.started_at.should eql raw_time_value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when it is something other than a Time' do
|
95
|
+
before { model.send :write_attribute, :started_at_utc, 5 }
|
96
|
+
|
97
|
+
it 'returns the raw value' do
|
98
|
+
model.started_at.should eql 5
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when the time zone is set properly' do
|
103
|
+
before { model.stub(:time_zone).and_return 'Alaska' }
|
104
|
+
|
105
|
+
context 'when it is a time' do
|
106
|
+
before { model.send :write_attribute, :started_at_utc, Time.utc(2012, 1, 2, 12, 59, 1) }
|
107
|
+
|
108
|
+
it 'returns the time in the time zone' do
|
109
|
+
model.started_at.should eql alaskan_time_zone.parse('2012-01-02 3:59:01')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#time_field=' do
|
116
|
+
let(:raw_time_field) { model.started_at_utc }
|
117
|
+
|
118
|
+
context 'when the time zone is set' do
|
119
|
+
before { model.time_zone = alaskan_time_zone.name }
|
120
|
+
|
121
|
+
context 'and the field is set to nil' do
|
122
|
+
before { model.started_at = nil }
|
123
|
+
|
124
|
+
it 'the time field is nil' do
|
125
|
+
raw_time_field.should be_nil
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'does not need to be converted' do
|
129
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'and the field is set to something which cannot be converted to a time' do
|
134
|
+
before { model.started_at = 'foo' }
|
135
|
+
|
136
|
+
it 'the time field is nil' do
|
137
|
+
raw_time_field.should be_nil
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'does not need to be converted' do
|
141
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_false
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'and the field is set with UTC time' do
|
146
|
+
before { model.started_at = Time.utc(2012, 1, 2, 12, 59, 1) }
|
147
|
+
|
148
|
+
it 'the time field is adjusted for the time zone' do
|
149
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 21, 59, 1)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'does not need to be converted' do
|
153
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_false
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when the time zone is not set' do
|
159
|
+
before { model.time_zone = nil }
|
160
|
+
|
161
|
+
context 'and the time field is set' do
|
162
|
+
before { model.started_at = Time.utc(2012, 1, 2, 12, 59, 1) }
|
163
|
+
|
164
|
+
it 'the time field is not adjusted' do
|
165
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 12, 59, 1)
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'needs to be converted' do
|
169
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'and the time field is not set' do
|
174
|
+
before { model.started_at = nil }
|
175
|
+
|
176
|
+
it 'the time field is nil' do
|
177
|
+
raw_time_field.should be_nil
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'does not need to be converted' do
|
181
|
+
model.send(:greenwich_time_field_needs_conversion?, 'started_at', 'time_zone').should be_false
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when it is saved to the database and reloaded' do
|
188
|
+
before do
|
189
|
+
model.started_at_utc = Time.utc(2012, 1, 2, 21, 59, 1)
|
190
|
+
model.time_zone = 'Alaska'
|
191
|
+
model.save!
|
192
|
+
|
193
|
+
model.reload
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'and the time zone is set' do
|
197
|
+
before { model.time_zone = 'Hawaii' }
|
198
|
+
|
199
|
+
it 'does not modify the UTC time' do
|
200
|
+
model.started_at_utc.should eql Time.utc(2012, 1, 2, 21, 59, 1)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'converts the time field to the local time' do
|
205
|
+
model.started_at.should_not be_utc
|
206
|
+
model.started_at.should eql alaskan_time_zone.parse('2012-01-02 12:59:01')
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'converts the time field to a TimeWithZone' do
|
210
|
+
model.started_at.should be_a ActiveSupport::TimeWithZone
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe '.time_zone' do
|
216
|
+
let(:model) { ModelWithTimeZone.new }
|
217
|
+
let(:alaskan_time_zone) { ActiveSupport::TimeZone.new('Alaska') }
|
218
|
+
|
219
|
+
context '#time_zone' do
|
220
|
+
context 'when the object does have a time zone' do
|
221
|
+
before { model.send(:write_attribute, :time_zone, alaskan_time_zone.name) }
|
222
|
+
|
223
|
+
it 'is the time zone' do
|
224
|
+
model.time_zone.should eql alaskan_time_zone
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'when the object does not have a time zone' do
|
229
|
+
before { model.send(:write_attribute, :time_zone, nil) }
|
230
|
+
|
231
|
+
it 'is nil' do
|
232
|
+
model.time_zone.should be_nil
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe '#time_zone=' do
|
238
|
+
let(:model) { ModelWithTimeZone.new }
|
239
|
+
let(:alaskan_time_zone) { ActiveSupport::TimeZone.new('Alaska') }
|
240
|
+
let(:hawaii_time_zone) { ActiveSupport::TimeZone.new('Hawaii') }
|
241
|
+
let(:raw_time_field) { model.started_at_utc }
|
242
|
+
let(:raw_time_zone) { model.read_attribute(:time_zone) }
|
243
|
+
|
244
|
+
context 'when it is set after the time field is set' do
|
245
|
+
before do
|
246
|
+
model.send :write_attribute, :started_at_utc, Time.utc(2012, 1, 2, 12, 59, 1)
|
247
|
+
model.time_zone = alaskan_time_zone
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'triggers the time field to be converted' do
|
251
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 21, 59, 1)
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'but when it is set subsequently' do
|
255
|
+
before do
|
256
|
+
model.time_zone.should_not be_nil
|
257
|
+
model.started_at_utc.should_not be_nil
|
258
|
+
model.time_zone = hawaii_time_zone
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'does not convert the time field' do
|
262
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 21, 59, 1)
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'if some other time field is then set' do
|
266
|
+
before do
|
267
|
+
model.send :write_attribute, :ended_at_utc, Time.utc(2012, 1, 2, 13, 59, 1)
|
268
|
+
model.time_zone = alaskan_time_zone
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'converts only the time fields that have not already been converted' do
|
272
|
+
raw_time_field.should eql Time.utc(2012, 1, 2, 21, 59, 1)
|
273
|
+
model.ended_at_utc.should eql Time.utc(2012, 1, 2, 22, 59, 1)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'when it is set before the time field is set' do
|
280
|
+
before { model.time_zone = alaskan_time_zone }
|
281
|
+
|
282
|
+
it 'sets the time zone but does not touch the time' do
|
283
|
+
raw_time_field.should be_nil
|
284
|
+
raw_time_zone.should eql 'Alaska'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'when it is set to an ActiveSupport::TimeZone' do
|
289
|
+
before { model.time_zone = alaskan_time_zone }
|
290
|
+
|
291
|
+
it 'is set properly' do
|
292
|
+
raw_time_zone.should eql 'Alaska'
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'when it is set to a time zone name' do
|
297
|
+
before { model.time_zone = 'Alaska' }
|
298
|
+
|
299
|
+
it 'is set properly' do
|
300
|
+
raw_time_zone.should eql 'Alaska'
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'when it is set to an invalid time zone' do
|
305
|
+
before { model.time_zone = 'I am not a time zone' }
|
306
|
+
|
307
|
+
it 'is nil' do
|
308
|
+
raw_time_zone.should be_nil
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|