代码之家  ›  专栏  ›  技术社区  ›  Ross Attrill

Ruby Sequel检索日期时间并节省日光时间的问题

  •  0
  • Ross Attrill  · 技术社区  · 2 年前

    Ruby Sequel gem允许在不进行时区转换、转换为本地时区或转换为时区的情况下检索日期时间。在这三种情况下,当windows客户端操作系统上的时区设置与Ruby中的时区设置冲突时,我们在转换为日光节约时都会得到不可用的结果。例如:

    require 'sequel'
    require_relative './ojdbc8.jar'
    
    username = 'username'
    password = 'password'
    host = 'host'
    port = 1521
    sid = 'ORCL'
    
    connection_string = "jdbc:oracle:thin:#{username}/#{password}@#{host}:#{port}:#{sid}"
    puts "connection_string: #{connection_string}"
    ENV['TZ'] = 'Etc/GMT-10'
    # ENV['TZ'] = '+10:00'
    
    db = Sequel.connect(connection_string)
    db.drop_table :d
    db.create_table :d do
        primary_key :id
        DateTime :DATETIME, unique: true, null: false
        Integer :HOUR, null: false
    end
    
    # Using Time with TZ set to GMT+10
    d = db[:d]
    (1..4).each do|hour|
        t = Time.new(2022, 10, 2, hour, 0, 0)
        puts "time: #{t}"
        d.insert(DATETIME: t, HOUR: hour)
    end
    
    sql = "SELECT * FROM d"
    
    Sequel.default_timezone = :utc
    dataset = db[sql]
    puts "UTC timezone"
    dataset.each do |row|
        puts "row: #{row}"
    end
    
    Sequel.default_timezone = :local
    dataset = db[sql]
    puts "Local timezone..."
    dataset.each do |row|
        puts "row: #{row}"
    end
    
    Sequel.default_timezone = nil
    dataset = db[sql]
    puts "nil timezone (no conversion)..."
    dataset.each do |row|
        puts "row: #{row}"
    end
    

    使用Windows时区运行上述操作 (UTC+10) Canberra, Melbourne, Sydney Adjust for Daylights Savings 设置为true将导致以下结果:

    time: 2022-10-02 01:00:00 +1000
    time: 2022-10-02 02:00:00 +1000
    time: 2022-10-02 03:00:00 +1000
    time: 2022-10-02 04:00:00 +1000
    UTC timezone
    row: {:id=>1, :datetime=>2022-10-02 01:00:00 UTC, :hour=>1}
    row: {:id=>2, :datetime=>2022-10-02 03:00:00 UTC, :hour=>2}
    row: {:id=>3, :datetime=>2022-10-02 03:00:00 UTC, :hour=>3}
    row: {:id=>4, :datetime=>2022-10-02 04:00:00 UTC, :hour=>4}
    Local timezone...
    row: {:id=>1, :datetime=>2022-10-02 01:00:00 +1000, :hour=>1}
    row: {:id=>2, :datetime=>2022-10-02 03:00:00 +1000, :hour=>2}
    row: {:id=>3, :datetime=>2022-10-02 03:00:00 +1000, :hour=>3}
    row: {:id=>4, :datetime=>2022-10-02 04:00:00 +1000, :hour=>4}
    nil timezone (no conversion)...
    row: {:id=>1, :datetime=>2022-10-02 01:00:00 +1000, :hour=>1}
    row: {:id=>2, :datetime=>2022-10-02 03:00:00 +1000, :hour=>2}
    row: {:id=>3, :datetime=>2022-10-02 03:00:00 +1000, :hour=>3}
    row: {:id=>4, :datetime=>2022-10-02 04:00:00 +1000, :hour=>4}
    

    请注意,在所有情况下,小时2和3返回的Time对象都是相同的。小时2不正确。鉴于TZ环境变量在代码中明确设置,如果 :local 选项为 Sequel.default_timezone = :local 使用TZ时区,而不是使用windows中的其他信息。请注意,如果TZ变量设置为非空值,则 Time 它本身将尊重这一设置,超越Windows设置。

    数据库中的实际DATETIME列没有时区信息。

    我还尝试了使用 named_timezones 扩展,但存在与上述相同的问题。这包括使用DateTime类而不是Time类。

    我们发现的唯一解决方案是使用 TO_CHAR() 函数将DATETIME列转换为字符串。

    还有其他人解决了这个问题吗?


    当使用JRuby 9.4.0.0和与Oracle的JDBC连接时,会出现上述问题。我在MRI和SQLite中使用了非常相似的代码,并且没有出现所描述的问题。使用MRI时,default_timezone=nil或:utc可以正常工作,如果:local和named_timezone与Datetime和Time类都可以正常工作。

    0 回复  |  直到 2 年前