Project

General

Profile

Actions

Bug #11994

closed

Incorrect result for yday in vtm_add_offset with negative UTC offset on last day of the year

Added by pixeltrix (Andrew White) almost 9 years ago. Updated about 8 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.4.0dev (2016-01-15 trunk 53543) [x86_64-darwin14]
[ruby-core:72878]

Description

When you have a UTC time value that's the first day of the year and then convert it to a time value with a negative UTC offset so that it's the 31st December then the year day is calculated incorrectly, e.g:

>> t = Time.utc(2015, 1, 1, 1, 0, 0).getlocal("-05:00")
=> 2014-12-31 20:00:00 -0500 
>> t.yday
=> 364 
>> t.strftime('%j')
=> "364"

I had a root around and it seems as though the problem is in vtm_add_offset in time.c at line 2032:

    if (day) {
        if (day < 0) {
            if (vtm->mon == 1 && vtm->mday == 1) {
                vtm->mday = 31;
                vtm->mon = 12; /* December */
                vtm->year = sub(vtm->year, INT2FIX(1));
                vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
            }

As far as I can tell the code appears to be making the assumption that year day is zero indexed but it's hard to determine the exact intent. I created a failing test case:

  def test_strftime_yearday_on_last_day_of_year
    t = Time.utc(2015, 12, 31, 0, 0, 0)
    assert_equal("365", t.strftime("%j"))
    t = Time.utc(2016, 12, 31, 0, 0, 0)
    assert_equal("366", t.strftime("%j"))

    t = Time.utc(2015, 12, 30, 20, 0, 0).getlocal("+05:00")
    assert_equal("365", t.strftime("%j"))
    t = Time.utc(2016, 12, 30, 20, 0, 0).getlocal("+05:00")
    assert_equal("366", t.strftime("%j"))

    t = Time.utc(2016, 1, 1, 1, 0, 0).getlocal("-05:00")
    assert_equal("365", t.strftime("%j"))
    t = Time.utc(2017, 1, 1, 1, 0, 0).getlocal("-05:00")
    assert_equal("366", t.strftime("%j"))
  end

When I changed the ternary to the following:

vtm->yday = leap_year_v_p(vtm->year) ? 366 : 365;

then the test passes and no other tests fail.

The original report came via the Rails bug tracker: https://github.com/rails/rails/issues/23033

There are a couple of other places in time.c with similar ternaries (in gmtime_with_leapsecond) but they appear to only affect 4.4BSD so I was unable to test them.

Actions

Also available in: Atom PDF

Like0
Like0