Bug in Marshal?

M

matt

With the usual deep_copy:

# Deep copy
class Object
def deep_copy
Marshal.load(Marshal.dump(self))
end
end

I get the following (irb 0.9(02/07/03))

irb(main):001:0> fmt = "%m-%d-%Y %H:%M"
=> "%m-%d-%Y %H:%M"
irb> original = Time.gm(2004, 04, 25, 22, 56)
=> Sun Apr 25 22:56:00 UTC 2004
irb> copy = original.deep_copy
=> Sun Apr 25 18:56:00 Eastern Daylight Time 2004
irb> [original, copy].map {|t| t.strftime(fmt)}
=> ["04-25-2004 22:56", "04-25-2004 18:56"]
irb> original.hour
=> 22
irb> copy.hour
=> 18
irb> original.hour <=> copy.hour
=> 1
irb> original <=> copy
=> 0

Ruh Roh!
 
A

Ara.T.Howard

With the usual deep_copy:

# Deep copy
class Object
def deep_copy
Marshal.load(Marshal.dump(self))
end
end

I get the following (irb 0.9(02/07/03))

irb(main):001:0> fmt = "%m-%d-%Y %H:%M"
=> "%m-%d-%Y %H:%M"
irb> original = Time.gm(2004, 04, 25, 22, 56)
=> Sun Apr 25 22:56:00 UTC 2004
irb> copy = original.deep_copy
=> Sun Apr 25 18:56:00 Eastern Daylight Time 2004
irb> [original, copy].map {|t| t.strftime(fmt)}
=> ["04-25-2004 22:56", "04-25-2004 18:56"]
irb> original.hour
=> 22
irb> copy.hour
=> 18
irb> original.hour <=> copy.hour
=> 1
irb> original <=> copy
=> 0

Ruh Roh!

i think this actually makes sense if you consider that a Time object is only
storing the seconds since 1970 and the environment (TZ) affect how it's
interpreted:

~ > TZ=America/Boston ruby -e 'p Time.now'
Fri May 14 03:25:38 America/Boston 2004

~ > TZ=America/Denver ruby -e 'p Time.now'
Thu May 13 21:25:44 MDT 2004

consider that you might Marshal a Time object into some file, and that file
gets shipped to africa - you definitely want some sort of 'absolute' time in
there. however, there's no problem if, when the file is loaded back in, the
Time object respects the locale settings - under the hood the time is still
the same:

irb(main):001:0> original = Time.gm(2004, 04, 25, 22, 56)
=> Sun Apr 25 22:56:00 UTC 2004

irb(main):002:0> copy = Marshal.load(Marshal.dump(original))
=> Sun Apr 25 16:56:00 MDT 2004

irb(main):003:0> original.to_f
=> 1082933760.0

irb(main):004:0> copy.to_f
=> 1082933760.0


if we compare hours we are comparing ints, if we compare seconds since 1970 in
either int or float we get and accurate comparison - which Time#<=> shows with
the 0 result.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
===============================================================================
 
Y

Yukihiro Matsumoto

Hi,

In message "Bug in Marshal?"

|With the usual deep_copy:
|
|# Deep copy
|class Object
| def deep_copy
| Marshal.load(Marshal.dump(self))
| end
|end

Marshal did not preserve gmt information. They are same time, same
seconds after the Epoch. Just representation time zone is different.

1.9 will preserve this information in the near future.

matz.
--- time.c 30 Apr 2004 11:10:02 -0000 1.100
+++ time.c 14 May 2004 04:38:36 -0000
@@ -1904,3 +1904,4 @@ time_mdump(time)
p = 0x1 << 31 | /* 1 */
- tm->tm_year << 14 | /* 17 */
+ tobj->gmt << 30 | /* 1 */
+ tm->tm_year << 14 | /* 16 */
tm->tm_mon << 10 | /* 4 */
@@ -1962,3 +1960,3 @@ time_mload(time, str)
struct tm tm;
- int i;
+ int i, gmt;

@@ -1985,3 +1983,4 @@ time_mload(time, str)
p &= ~(1<<31);
- tm.tm_year = (p >> 14) & 0x1ffff;
+ gmt = (p >> 30) & 0x1;
+ tm.tm_year = (p >> 14) & 0xffff;
tm.tm_mon = (p >> 10) & 0xf;
@@ -2000,2 +1999,3 @@ time_mload(time, str)
tobj->tm_got = 0;
+ tobj->gmt = gmt;
tobj->tv.tv_sec = sec;
 
T

Tanaka Akira

1.9 will preserve this information in the near future.

matz.
--- time.c 30 Apr 2004 11:10:02 -0000 1.100
+++ time.c 14 May 2004 04:38:36 -0000
@@ -1904,3 +1904,4 @@ time_mdump(time)
p = 0x1 << 31 | /* 1 */
- tm->tm_year << 14 | /* 17 */
+ tobj->gmt << 30 | /* 1 */
+ tm->tm_year << 14 | /* 16 */
tm->tm_mon << 10 | /* 4 */

I found that this change causes Marshal.load error if GMT time is sent
from 1.9 to 1.8.1.

% ruby -e 'Marshal.dump(Time.new.getgm, STDOUT)'|ruby-1.8.1 -e 'p Marshal.load(STDIN)'
-e:1:in `_load': time out of range (ArgumentError)
from -e:1:in `load'
from -e:1

% ruby -v
ruby 1.9.0 (2004-05-15) [i686-linux]
% ruby-1.8.1 -v
ruby 1.8.1 (2003-12-25) [i686-linux]

Why don't you use the bit 31, which is previously filled by 1 ?
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Bug in Marshal?"

|In article <[email protected]>,
| (e-mail address removed) (Yukihiro Matsumoto) writes:
|
|> 1.9 will preserve this information in the near future.
|>
|> matz.
|> --- time.c 30 Apr 2004 11:10:02 -0000 1.100
|> +++ time.c 14 May 2004 04:38:36 -0000
|> @@ -1904,3 +1904,4 @@ time_mdump(time)
|> p = 0x1 << 31 | /* 1 */
|> - tm->tm_year << 14 | /* 17 */
|> + tobj->gmt << 30 | /* 1 */
|> + tm->tm_year << 14 | /* 16 */
|> tm->tm_mon << 10 | /* 4 */
|
|I found that this change causes Marshal.load error if GMT time is sent
|from 1.9 to 1.8.1.

1.8.2 has fix to ignore this bit.

|Why don't you use the bit 31, which is previously filled by 1 ?

In that case, we would loose 1.6 compatibility.

matz.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,373
Latest member
Desiree036

Latest Threads

Top