From 378eb1484d9a01369174a7c2f606dbc90aa1bd86 Mon Sep 17 00:00:00 2001 From: Nicholas Jakobsen Date: Thu, 22 May 2025 22:15:01 -0700 Subject: [PATCH] fix: Support time zone when serializing DateTimes Previously a DateTime being serialized would ignore the timezone, effectively assuming the timezone of the value was the same as the column. Instead, the timezone is now taken into account so the time can be given in any timezone and it will be converted to the timezone of the column. --- lib/click_house/type/date_time64_type.rb | 8 ++++++-- lib/click_house/type/date_time_type.rb | 8 ++++++-- spec/click_house/type/date_time64_spec.rb | 17 +++++++++++++++-- spec/click_house/type/date_time_type_spec.rb | 10 ++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/click_house/type/date_time64_type.rb b/lib/click_house/type/date_time64_type.rb index dc802c8..fb9bdbd 100644 --- a/lib/click_house/type/date_time64_type.rb +++ b/lib/click_house/type/date_time64_type.rb @@ -32,8 +32,12 @@ def cast(value, precision = 0, tz = nil) end end - def serialize(value, precision = 3, _tz = nil) - value.strftime(SERIALIZE_FORMATS.fetch(precision)) + def serialize(value, precision = 3, tz = nil) + if tz + value.in_time_zone(Time.find_zone(tz)).strftime(SERIALIZE_FORMATS.fetch(precision)) + else + value.strftime(SERIALIZE_FORMATS.fetch(precision)) + end end end end diff --git a/lib/click_house/type/date_time_type.rb b/lib/click_house/type/date_time_type.rb index e40767e..c9c429d 100644 --- a/lib/click_house/type/date_time_type.rb +++ b/lib/click_house/type/date_time_type.rb @@ -13,8 +13,12 @@ def cast(value, tz = nil) end end - def serialize(value, *) - value.strftime(FORMAT) + def serialize(value, tz = nil) + if tz + value.in_time_zone(Time.find_zone(tz)).strftime(FORMAT) + else + value.strftime(FORMAT) + end end end end diff --git a/spec/click_house/type/date_time64_spec.rb b/spec/click_house/type/date_time64_spec.rb index 8904873..ddb3ea8 100644 --- a/spec/click_house/type/date_time64_spec.rb +++ b/spec/click_house/type/date_time64_spec.rb @@ -1,5 +1,5 @@ RSpec.describe ClickHouse::Type::DateTime64Type do - let(:precisions) do + let(:precisions) do (0..9).to_a end @@ -9,11 +9,24 @@ end it 'works' do - precisions.each do |precision| + precisions.each do |precision| tail = "." + "0" * precision if precision > 0 expect(subject.serialize(time, precision)).to eq("2019-01-01 09:05:06#{tail}") end end + + context 'when zone exists' do + let(:time) do + Time.new(2019, 1, 1, 9, 5, 6, Time.find_zone('UTC')) + end + + it 'works' do + precisions.each do |precision| + tail = "." + "0" * precision if precision > 0 + expect(subject.serialize(time, precision, 'Europe/Kyiv')).to eq("2019-01-01 11:05:06#{tail}") + end + end + end end describe '#cast' do diff --git a/spec/click_house/type/date_time_type_spec.rb b/spec/click_house/type/date_time_type_spec.rb index 78a5700..76b8c61 100644 --- a/spec/click_house/type/date_time_type_spec.rb +++ b/spec/click_house/type/date_time_type_spec.rb @@ -7,6 +7,16 @@ it 'works' do expect(subject.serialize(time)).to eq('2019-01-01 09:05:06') end + + context 'when zone exists' do + let(:time) do + Time.new(2019, 1, 1, 9, 5, 6, Time.find_zone('UTC')) + end + + it 'works' do + expect(subject.serialize(time, 'Europe/Kyiv')).to eq('2019-01-01 11:05:06') + end + end end describe '#cast' do