ruby / ruby/time

zone_offset returns nil when it should return 0 for ISO8601 dates

Open
#24 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
20
Forks
20
Avg merge
12h 43m
Merged PRs (30d)
2

Description

I get the error

NoMethodError: undefined method `<' for nil:NilClass

In time.rb:156 when I am parsing ISO8601-format (eg. 2024-10-17T12:49:41.854Z) expiration dates of cookies in a Rails 7 application.

The error comes from the apply_offset method being passed a nil value in the off parameter instead of a number. That value is calculated by the zone_offset method. Something goes wrong in the comparison with ZoneOffset but I don't understand why.

I've made a quick and dirty refinement, defining the zone offsets in a variable inside the method and this one works as expected.

module TimeRefinements
  refine Time do
    class << Time
      def zone_offset(zone, year=self.now.year)
        z_offset = {
          'UTC' => 0,
          # ISO 8601
          'Z' => 0,
          # RFC 822
          'UT' => 0, 'GMT' => 0,
          'EST' => -5, 'EDT' => -4,
          'CST' => -6, 'CDT' => -5,
          'MST' => -7, 'MDT' => -6,
          'PST' => -8, 'PDT' => -7,
          # Following definition of military zones is original one.
          # See RFC 1123 and RFC 2822 for the error in RFC 822.
          'A' => +1, 'B' => +2, 'C' => +3, 'D' => +4,  'E' => +5,  'F' => +6,
          'G' => +7, 'H' => +8, 'I' => +9, 'K' => +10, 'L' => +11, 'M' => +12,
          'N' => -1, 'O' => -2, 'P' => -3, 'Q' => -4,  'R' => -5,  'S' => -6,
          'T' => -7, 'U' => -8, 'V' => -9, 'W' => -10, 'X' => -11, 'Y' => -12,
        }

        off = nil
        zone = zone.upcase
        if /\A([+-])(\d\d)(:?)(\d\d)(?:\3(\d\d))?\z/ =~ zone
          off = ($1 == '-' ? -1 : 1) * (($2.to_i * 60 + $4.to_i) * 60 + $5.to_i)
        elsif zone.match?(/\A[+-]\d\d\z/)
          off = zone.to_i * 3600
        elsif z_offset.include?(zone)
          off = z_offset[zone] * 3600
        elsif ((t = self.local(year, 1, 1)).zone.upcase == zone rescue false)
          off = t.utc_offset
        elsif ((t = self.local(year, 7, 1)).zone.upcase == zone rescue false)
          off = t.utc_offset
        end
        off
      end
    end
  end
end

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at time.rb:156 and trace apply_offset with the ISO8601 value 2024-10-17T12:49:41.854Z, then inspect how zone_offset determines the offset for Z. Reproduce the cookie expiration parsing failure and confirm that zone_offset supplies a numeric offset so the NoMethodError no longer occurs.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.