ruby/ruby · error · ArgumentError

yday #{yday} out of range

Error message

yday #{yday} out of range

What it means

When Date._parse recognizes an ordinal-date component (:yday), make_time validates it against 1..366 before doing any calendar math. A day-of-year outside that window (0, negative, or >366) raises ArgumentError 'yday N out of range' immediately.

Source

Thrown at lib/time.rb:214

      end
      return year, mon, day, hour, min, sec
    end
    private :apply_offset

    def make_time(date, year, yday, mon, day, hour, min, sec, sec_fraction, zone, now)
      if !year && !yday && !mon && !day && !hour && !min && !sec && !sec_fraction
        raise ArgumentError, "no time information in #{date.inspect}"
      end

      off = nil
      if year || now
        off_year = year || now.year
        off = zone_offset(zone, off_year) if zone
      end

      if yday
        unless (1..366) === yday
          raise ArgumentError, "yday #{yday} out of range"
        end
        mon, day = (yday-1).divmod(31)
        mon += 1
        day += 1
        t = make_time(date, year, nil, mon, day, hour, min, sec, sec_fraction, zone, now)
        diff = yday - t.yday
        return t if diff.zero?
        day += diff
        if day > 28 and day > (mday = month_days(off_year, mon))
          if (mon += 1) > 12
            raise ArgumentError, "yday #{yday} out of range"
          end
          day -= mday
        end
        return make_time(date, year, nil, mon, day, hour, min, sec, sec_fraction, zone, now)
      end

      if now and now.respond_to?(:getlocal)

View on GitHub (pinned to 0e5b888e1c)

Solutions

  1. Validate before parsing: yday must be in 1..366 (1..365 for non-leap years)
  2. Build ordinal dates with the standard API: Date.ordinal(year, yday).to_time instead of string round-trips
  3. Clamp or reject the value at the producer that generates the string
  4. Rescue ArgumentError and report the offending record id

Example fix

# before
t = Time.parse("2021-400")           # raises: yday 400 out of range

# after
raise ArgumentError, "bad yday #{doy}" unless (1..366).cover?(doy)
t = Date.ordinal(2021, doy)&.to_time
Defensive patterns

Strategy: validation

Validate before calling

raise ArgumentError, "yday #{doy} out of range" unless (1..366).cover?(doy)
t = Date.ordinal(year, doy).to_time

Try / catch

begin
  Time.parse(ordinal_str)
rescue ArgumentError
  quarantine(record)  # log the bad ordinal date and move on
end

Prevention

When it happens

Trigger: Time.parse("2021-400"); Time.parse("2021-0"); strings like "21-367" where the parser reads a day-of-year; exporting tools that emit DDD without clamping.

Common situations: Malformed ordinal dates from data exports or industrial loggers (YYYY-DDD format); user-typed day-of-year treated as 0-based; hand-rolled date arithmetic producing yday 0 or 367+.

Related errors


AI-assisted analysis of ruby/ruby@0e5b888e1c (2026-08-21). Data as JSON: /api/errors/830d3523368ee6d1. Report an issue: GitHub.