Project

General

Profile

Patch #22320 » 0002-Fixes-Query-date_clause-timezone-handling.patch

Jens Krämer, 2016-03-26 09:22

View differences:

app/models/query.rb
966 966
    end
967 967
  end
968 968

  
969
  def date_for_user_time_zone(y, m, d)
970
    if tz = User.current.time_zone
971
      tz.local y, m, d
972
    else
973
      Time.local y, m, d
974
    end
975
  end
976

  
969 977
  # Returns a SQL clause for a date or datetime field.
970 978
  def date_clause(table, field, from, to, is_custom_filter)
971 979
    s = []
972 980
    if from
973 981
      if from.is_a?(Date)
974
        from = Time.local(from.year, from.month, from.day).yesterday.end_of_day
982
        from = date_for_user_time_zone(from.year, from.month, from.day).yesterday.end_of_day
975 983
      else
976 984
        from = from - 1 # second
977 985
      end
......
982 990
    end
983 991
    if to
984 992
      if to.is_a?(Date)
985
        to = Time.local(to.year, to.month, to.day).end_of_day
993
        to = date_for_user_time_zone(to.year, to.month, to.day).end_of_day
986 994
      end
987 995
      if self.class.default_timezone == :utc
988 996
        to = to.utc
test/unit/query_test.rb
1696 1696
    c = QueryColumn.new('foo', :caption => lambda {'Foo'})
1697 1697
    assert_equal 'Foo', c.caption
1698 1698
  end
1699

  
1700
  def test_date_clause_should_respect_user_time_zone_with_local_default
1701
    @query = IssueQuery.new(:name => '_')
1702

  
1703
    # user is in Hawaii (-10)
1704
    User.current = users(:users_001)
1705
    User.current.pref.update_attribute :time_zone, 'Hawaii'
1706

  
1707
    # assume timestamps are stored in server local time
1708
    local_zone = Time.zone
1709

  
1710
    from = Date.parse '2016-03-20'
1711
    to = Date.parse '2016-03-22'
1712
    assert c = @query.send(:date_clause, 'table', 'field', from, to, false)
1713

  
1714
    # the dates should have been interpreted in the user's time zone and
1715
    # converted to local time
1716
    # what we get exactly in the sql depends on the local time zone, therefore
1717
    # it's computed here.
1718
    f = User.current.time_zone.local(from.year, from.month, from.day).yesterday.end_of_day.in_time_zone(local_zone)
1719
    t = User.current.time_zone.local(to.year, to.month, to.day).end_of_day.in_time_zone(local_zone)
1720
    assert_equal "table.field > '#{Query.connection.quoted_date f}' AND table.field <= '#{Query.connection.quoted_date t}'", c
1721
  end
1722

  
1723
  def test_date_clause_should_respect_user_time_zone_with_utc_default
1724
    @query = IssueQuery.new(:name => '_')
1725

  
1726
    # user is in Hawaii (-10)
1727
    User.current = users(:users_001)
1728
    User.current.pref.update_attribute :time_zone, 'Hawaii'
1729

  
1730
    # assume timestamps are stored as utc
1731
    ActiveRecord::Base.default_timezone = :utc
1732

  
1733
    from = Date.parse '2016-03-20'
1734
    to = Date.parse '2016-03-22'
1735
    assert c = @query.send(:date_clause, 'table', 'field', from, to, false)
1736
    # the dates should have been interpreted in the user's time zone and
1737
    # converted to utc. March 20 in Hawaii begins at 10am UTC.
1738
    assert_equal "table.field > '2016-03-20 09:59:59.999999' AND table.field <= '2016-03-23 09:59:59.999999'", c
1739
  ensure
1740
    ActiveRecord::Base.default_timezone = :local # restore Redmine default
1741
  end
1742

  
1699 1743
end
(2-2/3)