greenwich 0.0.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![
|
114
|
+
![chirrpy](https://dl.dropbox.com/s/f9s2qd0kmbc8nwl/github_logo.png?dl=1)
|
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
|