Is this a bug in Time.local?

Hi,

I've tried this for ruby 1.8.1 and 1.6.8.

irb(main):001:0> Time.local(30, 15, 11, nil, nil, 2004, nil, 203, nil, nil)
=> Thu Jan 01 11:15:30 GMT 2004

For the 203rd day of the year, it does not seem I should be getting Jan 1.
Is this a bug?

Thank you,
Richard Ryan

"Richard A. Ryan" <Richard.A.Ryan@noaa.gov> writes:

Hi,

I've tried this for ruby 1.8.1 and 1.6.8.

irb(main):001:0> Time.local(30, 15, 11, nil, nil, 2004, nil, 203, nil, nil)
=> Thu Jan 01 11:15:30 GMT 2004

For the 203rd day of the year, it does not seem I should be getting Jan 1.
Is this a bug?

No, it's a feature. That method call ultimately results in a call to the
system library function mktime(3), which ignores that field:

        The function ignores the specified contents of
        the structure members tm_wday and tm_yday and recomputes
        them from the other information in the broken‐down time
        structure.

Unfortunately, Ruby interferes with the autonormalization feature mktime(3)
provides: when calling mktime(3) directly, you can ask for, e.g. "January
203rd" and it will return the date of the 203rd day of the year. The Ruby
Time module won't let you do that, because it does a bounds check on the
arguments, so you have to do something else. One alternative is to use the
fact that you can do math on Time objects, which when treated as numbers
become a count of seconds (since January 1, 1970 at midnight UTC). So
to get the date of the 203rd day of 2004, you could do this:

        irb(main):001:0> Time.local(30, 15, 11, 31, 12, 2003, nil, nil, nil, nil) + 203 * 86400
        => Wed Jul 21 12:15:30 EDT 2004

86400 is the number of seconds in a day, 24 x 60 x 60. To get the 203rd day of
2004, I asked for the last day of 2003 (Dec 31st) plus 203 days.

Oh, and the time came out 12:15 instead of 11:15 because of the switch to
daylight savings time; 24 hours after 11:15 on the day of the change to
EDT, it's 12:15. If you don't care about the time, you can use the 3-argument form of
Time.local, which uses the ISO order of year, month, day:

       irb(main):002:0> Time.local(2003, 12, 31) + 203 * 86400
       => Wed Jul 21 01:00:00 EDT 2004

-Mark

Hi,

Thanks for the reply. If the consistency of the treatment of yday
with mktime means it's not a bug, then why wouldn't the inconsistency
with mktime's autonormalization feature be a bug? And if Time.local
and Time.gmtime are to differ with the operation of mktime and gmtime,
why not differ on the side of convenience?

Thairr eess no porrpooss to theess...

Thanks again,
R

Mark J. Reed wrote:

···

"Richard A. Ryan" <Richard.A.Ryan@noaa.gov> writes:

Hi,

I've tried this for ruby 1.8.1 and 1.6.8.

irb(main):001:0> Time.local(30, 15, 11, nil, nil, 2004, nil, 203, nil, nil)
=> Thu Jan 01 11:15:30 GMT 2004

For the 203rd day of the year, it does not seem I should be getting Jan 1.
Is this a bug?

No, it's a feature. That method call ultimately results in a call to the
system library function mktime(3), which ignores that field:

        The function ignores the specified contents of
        the structure members tm_wday and tm_yday and recomputes
        them from the other information in the broken‐down time
        structure.

Unfortunately, Ruby interferes with the autonormalization feature mktime(3)
provides: when calling mktime(3) directly, you can ask for, e.g. "January
203rd" and it will return the date of the 203rd day of the year. The Ruby
Time module won't let you do that, because it does a bounds check on the
arguments, so you have to do something else. One alternative is to use the
fact that you can do math on Time objects, which when treated as numbers
become a count of seconds (since January 1, 1970 at midnight UTC). So
to get the date of the 203rd day of 2004, you could do this:

        irb(main):001:0> Time.local(30, 15, 11, 31, 12, 2003, nil, nil, nil, nil) + 203 * 86400
        => Wed Jul 21 12:15:30 EDT 2004

86400 is the number of seconds in a day, 24 x 60 x 60. To get the 203rd day of
2004, I asked for the last day of 2003 (Dec 31st) plus 203 days.

Oh, and the time came out 12:15 instead of 11:15 because of the switch to daylight savings time; 24 hours after 11:15 on the day of the change to
EDT, it's 12:15. If you don't care about the time, you can use the 3-argument form of
Time.local, which uses the ISO order of year, month, day:

       irb(main):002:0> Time.local(2003, 12, 31) + 203 * 86400
       => Wed Jul 21 01:00:00 EDT 2004

-Mark

"Richard A. Ryan" <Richard.A.Ryan@noaa.gov> writes:

Hi,

Thanks for the reply. If the consistency of the treatment of yday
with mktime means it's not a bug

Well, the fact that it's documented means it's not a bug . .

, then why wouldn't the inconsistency with mktime's autonormalization feature
be a bug?

I didn't say it wasn't. :slight_smile:

Actually, I think that the 10-argument form of Time.local/mktime is deprecated.
You should really be using the 1-to-8 argument forms, which have no wday or
yday fields at all:

        Time.mktime(year[, month[, day[, hour[, min[, sec[, msec[, zone]]]]]]])

I agree that there ought to be a normalizing form of these methods. For
instance, the Perl Time::Local module includes timelocal_nocheck and
timegm_nocheck to serve that purpose.

-Mark

Hi,

Actually, I think that the 10-argument form of Time.local/mktime is deprecated.
You should really be using the 1-to-8 argument forms, which have no wday or
yday fields at all:

        Time.mktime(year[, month[, day[, hour[, min[, sec[, msec[, zone]]]]]]])

The reason why I was trying to do it the way I was doing it was because the
data I was looking at had the day of the year and not the day of the month.
I really would be using this if I had the day of the month readily
available---the question wouldn't even have come up in the first place if it
weren't for that. I've used the `date' library together with Time as a
workaround, but it's not the way I would prefer to do it.

R

"Richard A. Ryan" <Richard.A.Ryan@noaa.gov> writes:

The reason why I was trying to do it the way I was doing it was because the
data I was looking at had the day of the year and not the day of the month.

Yeah, I gathered. If the normalization functionality were to be exposed via
Time, though, I would prefer that it be by letting you do, e.g.
Time.local(2004, 1, 203) rather than dredging up the not-quite-Perl-compatible
interface. :slight_smile:

-Mark