Skip to content

Commit da99cb1

Browse files
committed
Improved DateTime handling.
1 parent 833c21e commit da99cb1

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

lib/db/postgres/native/types.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,20 @@ def initialize(name = "TIMESTAMP")
8484
attr :name
8585

8686
def parse(string)
87-
if match = string.match(/(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)([\+\-].*)?/)
87+
if string == '-infinity' || string == 'infinity' || string.nil?
88+
return string
89+
end
90+
91+
if match = string.match(/\A(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+(?:\.\d+)?)([-+]\d\d(?::\d\d)?)?\z/)
8892
parts = match.captures
89-
parts[6] ||= "UTC"
93+
94+
parts[5] = BigDecimal(parts[5])
95+
96+
if parts[6].nil?
97+
parts[6] = '+00:00'
98+
elsif /^[-+]\d\d$/ === parts[6]
99+
parts[6] += ':00'
100+
end
90101

91102
return Time.new(*parts)
92103
end
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2018-2024, by Samuel Williams.
5+
6+
require 'db/postgres/connection'
7+
require 'sus/fixtures/async'
8+
9+
ATimestamp = Sus::Shared("a timestamp") do |zone, time, expected|
10+
it "can get timestamps with microseconds and timezone" do
11+
connection.send_query("SET TIME ZONE '#{zone}'")
12+
13+
buffer = String.new
14+
buffer << "SELECT "
15+
connection.append_literal(time, buffer)
16+
buffer << "::TIMESTAMPTZ"
17+
18+
connection.send_query buffer
19+
20+
result = connection.next_result
21+
row = result.to_a.first
22+
23+
expect(row.first).to be == expected
24+
ensure
25+
connection.close
26+
end
27+
end
28+
29+
describe DB::Postgres::Connection do
30+
include Sus::Fixtures::Async::ReactorContext
31+
32+
let(:connection) {subject.new(**CREDENTIALS)}
33+
34+
[{
35+
# PG produces: "2022-11-11 12:38:59.123456+00"
36+
zone: 'UTC',
37+
time: '2022-11-11 23:38:59.123456+11',
38+
result: Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+11:00'),
39+
}, {
40+
# PG produces: "2022-11-11 12:38:59+00"
41+
zone: 'UTC',
42+
time: '2022-11-11 23:38:59+11',
43+
result: Time.new(2022, 11, 11, 23, 38, BigDecimal('59'), '+11:00'),
44+
}, {
45+
# PG produces: "2022-11-11 23:38:59.123456+00"
46+
zone: 'UTC',
47+
time: '2022-11-11 23:38:59.123456',
48+
result: Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+00:00'),
49+
}, {
50+
# PG produces: "2022-11-11 23:38:59+11"
51+
zone: 'Australia/Sydney',
52+
time: '2022-11-11 23:38:59',
53+
result: Time.new(2022, 11, 11, 23, 38, BigDecimal('59'), '+11:00'),
54+
}, {
55+
# PG produces: "2022-11-12 06:08:59.123456+11"
56+
zone: 'Australia/Sydney',
57+
time: '2022-11-11 23:38:59.123456+04:30',
58+
result: Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+04:30'),
59+
}, {
60+
# PG produces: "2000-01-01 05:30:00+05:30"
61+
zone: 'Asia/Kolkata',
62+
time: '2000-01-01 00:00:00+00',
63+
result: Time.new(2000, 1, 1, 5, 30, 0, '+05:30'),
64+
}, {
65+
# PG produces: "infinity"
66+
zone: 'UTC',
67+
time: 'infinity',
68+
result: 'infinity',
69+
}, {
70+
# PG produces: "-infinity"
71+
zone: 'UTC',
72+
time: '-infinity',
73+
result: '-infinity',
74+
}, {
75+
# PG produces: null
76+
zone: 'UTC',
77+
time: nil,
78+
result: nil,
79+
}].each do |spec|
80+
it_behaves_like ATimestamp, spec[:zone], spec[:time], spec[:result]
81+
end
82+
end

0 commit comments

Comments
 (0)