Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-4853

Querying Date fields using a TimeWithZone instance queries by the date in local time zone

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 7.1.4, 7.0.10
    • Affects Version/s: 7.0.6, 7.1.0
    • Component/s: Query

      Given the following model:

      class Person
        include Mongoid::Document
      
        field :dob, type: Date
      end
      

      A user can query the dob field of this model using a Time value.

      Time.now
      # => 2020-04-22 15:27:39 -0400
      
      Person.lte(dob: Time.now)
      # => selector: {"dob"=>{"$lte"=>2020-04-22 00:00:00 UTC}}
      

      During that query, the original Time is converted to a different Time instance equivalent to midnight UTC on the same day as the original Time.

      However, when the same field is queried using a TimeWithZone value, the query is constructed using a TimeWithZone value equivalent to midnight on that same day in the current time zone.

      Time.use_zone('Europe/Moscow') { Person.lte(dob: Time.zone.now) }
      # {"dob"=>{"$lte"=>Wed, 22 Apr 2020 00:00:00 MSK +03:00}}
      

      The behavior between these two classes is inconsistent. I believe that when TimeWithZone values are used to query Date fields, a TimeWithZone equivalent to midnight on that day in UTC should be used as the query value.


      The original ticket description is below:

      The following spec used to pass up to and including Mongoid 7.0.5 and started failing with Mongoid 7.0.6:

      require "spec_helper"
      
      describe "Date valued fields" do
        context "when the TimeZone is ahead of UTC" do
          around do |example|
            Time.use_zone('Europe/Moscow') do
              example.run
            end
          end
      
          let!(:match) do
            Person.create(dob: Time.zone.today)
          end
      
          let!(:non_match) do
            Person.create(dob: Time.zone.tomorrow)
          end
      
          it "returns the matching documents" do
            expect(Person.lte(dob: Time.zone.now)).to match_array([match])
          end
        end
      
        context "when the TimeZone is trailing UTC" do
          around do |example|
            Time.use_zone('America/New_York') do
              example.run
            end
          end
      
          let!(:match) do
            Person.create(dob: Time.zone.today)
          end
      
          let!(:non_match) do
            Person.create(dob: Time.zone.yesterday)
          end
      
          it "returns the matching documents" do
            expect(Person.gte(dob: Time.zone.now.beginning_of_day)).to match_array([match])
          end
        end
      end
      

      The reason is the introduction of mongo/active_support:

      In the first case we try to match 2020-03-12 with Mongoid's selector

      { "dob" => {"$lte"=>Thu, 12 Mar 2020 00:00:00 MSK +03:00} }
      

      which is equivalent to

      { "dob" => {"$lte"=>Wed, 11 Mar 2020 21:00:00 UTC} }
      

      The match will succeed if we expand 2020-03-12 into Thu, 12 Mar 2020 00:00:00 MSK +03:00 and fail if we interpret it as Thu, 12 Mar 2020 00:00:00 UTC.

            Assignee:
            oleg.pudeyev@mongodb.com Oleg Pudeyev (Inactive)
            Reporter:
            larnold@givve.com Leo Arnold
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: