public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Fix Ruby's Time marshaling bug in pre-1.9 versions of Ruby: utc instances are 
now correctly unmarshaled with a utc zone instead of the system local zone [#900 
state:resolved]
jodosha (author)
Wed Aug 27 02:25:20 -0700 2008
gbuesing (committer)
Wed Aug 27 06:57:36 -0700 2008
commit  ce65a05c5b027175c3c541055081f82c8bfc36bf
tree    007ffc3c93c7f7a0ed8f273f7980539397b2145e
parent  b7cd4ded9350fff5edee2298dc04a55e6b285233
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *Edge*
0
 
0
+* Fix Ruby's Time marshaling bug in pre-1.9 versions of Ruby: utc instances are now correctly unmarshaled with a utc zone instead of the system local zone [#900 state:resolved] [Luca Guidi, Geoff Buesing]
0
+
0
 * Add Array#in_groups which splits or iterates over the array in specified number of groups. #579. [Adrian Mugnolo] Example:
0
   
0
   a = (1..10).to_a
...
1
2
3
4
5
 
6
7
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
10
11
...
1
2
3
 
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
0
@@ -1,11 +1,32 @@
0
 require 'date'
0
 require 'time'
0
 
0
-# Ruby 1.8-cvs and 1.9 define private Time#to_date
0
 class Time
0
+  # Ruby 1.8-cvs and 1.9 define private Time#to_date
0
   %w(to_date to_datetime).each do |method|
0
     public method if private_instance_methods.include?(method)
0
   end
0
+
0
+  # Pre-1.9 versions of Ruby have a bug with marshaling Time instances, where utc instances are
0
+  # unmarshaled in the local zone, instead of utc. We're layering behavior on the _dump and _load
0
+  # methods so that utc instances can be flagged on dump, and coerced back to utc on load.
0
+  if RUBY_VERSION < '1.9'
0
+    class << self
0
+      alias_method :_original_load, :_load
0
+      def _load(marshaled_time)
0
+        time = _original_load(marshaled_time)
0
+        utc = time.send(:remove_instance_variable, '@marshal_with_utc_coercion')
0
+        utc ? time.utc : time
0
+      end
0
+    end
0
+    
0
+    alias_method :_original_dump, :_dump
0
+    def _dump(*args)
0
+      obj = self.frozen? ? self.dup : self
0
+      obj.instance_variable_set('@marshal_with_utc_coercion', utc?)
0
+      obj._original_dump(*args)
0
+    end
0
+  end
0
 end
0
 
0
 require 'active_support/core_ext/time/behavior'
...
625
626
627
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
0
@@ -625,3 +625,37 @@ class TimeExtCalculationsTest < Test::Unit::TestCase
0
       old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
0
     end
0
 end
0
+
0
+class TimeExtMarshalingTest < Test::Unit::TestCase
0
+  def test_marshaling_with_utc_instance
0
+    t = Time.utc(2000)
0
+    marshaled = Marshal.dump t
0
+    unmarshaled = Marshal.load marshaled
0
+    assert_equal t, unmarshaled
0
+    assert_equal t.zone, unmarshaled.zone
0
+  end
0
+  
0
+  def test_marshaling_with_local_instance  
0
+    t = Time.local(2000)
0
+    marshaled = Marshal.dump t
0
+    unmarshaled = Marshal.load marshaled
0
+    assert_equal t, unmarshaled
0
+    assert_equal t.zone, unmarshaled.zone
0
+  end
0
+    
0
+  def test_marshaling_with_frozen_utc_instance  
0
+    t = Time.utc(2000).freeze
0
+    marshaled = Marshal.dump t
0
+    unmarshaled = Marshal.load marshaled
0
+    assert_equal t, unmarshaled
0
+    assert_equal t.zone, unmarshaled.zone
0
+  end
0
+  
0
+  def test_marshaling_with_frozen_local_instance  
0
+    t = Time.local(2000).freeze
0
+    marshaled = Marshal.dump t
0
+    unmarshaled = Marshal.load marshaled
0
+    assert_equal t, unmarshaled
0
+    assert_equal t.zone, unmarshaled.zone
0
+  end
0
+end

Comments