Skip to content

Wrong time returned for timestamptz with :local default_timezone around DST time change #2147

Open
@ioev

Description

@ioev

We're having some trouble with the timestamptz data format when using :local time in the database. I traced the issue to around here:
https://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb#L261

EDIT: I updated the test case to make sure local time is set to one that uses DST, since I don't think it will fail unless this is the case.

I also included an extra spec for a case that we've also run into, where a time isn't formatted correctly for a timestamp_with_timezone column. Probably not an easy fix since I don't think the query can know at this point what the column type really is. A workaround might be to wrap the time in some other class, so that _quote can properly format it as "TO_TIMESTAMP_TZ()"?

Steps to reproduce

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails", github: "rails/rails", branch: "6-0-stable"
  gem "activerecord-oracle_enhanced-adapter",  github: "rsim/oracle-enhanced", branch: "release60"
  gem "rspec"

  platforms :ruby do
    gem "ruby-oci8"
  end
end

require "active_record"
require "rspec"
require "logger"
require "active_record/connection_adapters/oracle_enhanced_adapter"

# Set Oracle enhanced adapter specific connection parameters
DATABASE_NAME = ENV["DATABASE_NAME"] || "dev"
DATABASE_HOST = ENV["DATABASE_HOST"]
DATABASE_PORT = ENV["DATABASE_PORT"]
DATABASE_USER = ENV["DATABASE_USER"] || "oracle_enhanced"
DATABASE_PASSWORD = ENV["DATABASE_PASSWORD"] || "oracle_enhanced"
DATABASE_SYS_PASSWORD = ENV["DATABASE_SYS_PASSWORD"] || "admin"

CONNECTION_PARAMS = {
  adapter: "oracle_enhanced",
  database: DATABASE_NAME,
  host: DATABASE_HOST,
  port: DATABASE_PORT,
  username: DATABASE_USER,
  password: DATABASE_PASSWORD
}

ActiveRecord::Base.logger = Logger.new(STDOUT)
Time.zone = ActiveSupport::TimeZone.new('Central Time (US & Canada)')

describe "bug test" do
  before(:all) do
    ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
    ActiveRecord::Schema.define do
      create_table :posts, force: true do |t|
        t.timestamptz :posted_at
      end
    end

    class Post < ActiveRecord::Base
    end
  end

  it "should properly store/retrieve timestamp with tz in :local" do
    ActiveRecord::Base.default_timezone = :local
    time = Time.new(2014, 11, 2, 1, 0, 0, '-05:00')
    post = Post.create!(posted_at: time)
    post.reload
    expect(post.posted_at).to eq time
  end

  it "should be able to properly format times for timestamptz column" do
    ActiveRecord::Base.default_timezone = :utc
    time = Time.now
    post = Post.create!(posted_at: time)

    expect(Post.where('posted_at = ?', time).first).to eq post
  end
end

Expected behavior

The time should be correctly returned.

Actual behavior

Time is offset by 1 hour.

System configuration

Rails version: 6-0-stable

Oracle enhanced adapter version: 6.0.6

Ruby version: 2.7.2

Oracle Database version: 12.2.0.1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions