Skip to content

Commit 9a0d678

Browse files
authored
Improved DateTime handling. (#11)
1 parent 833c21e commit 9a0d678

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

lib/db/postgres/native/types.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,18 @@ 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'
98+
end
9099

91100
return Time.new(*parts)
92101
end
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
# PG produces: "2022-11-11 12:38:59.123456+00"
35+
it_behaves_like ATimestamp, 'UTC', '2022-11-11 23:38:59.123456+11', Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+11:00')
36+
37+
# PG produces: "2022-11-11 12:38:59+00"
38+
it_behaves_like ATimestamp, 'UTC', '2022-11-11 23:38:59+11', Time.new(2022, 11, 11, 23, 38, BigDecimal('59'), '+11:00')
39+
40+
# PG produces: "2022-11-11 23:38:59.123456+00"
41+
it_behaves_like ATimestamp, 'UTC', '2022-11-11 23:38:59.123456', Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+00:00')
42+
43+
# PG produces: "2022-11-11 23:38:59+11"
44+
it_behaves_like ATimestamp, 'Australia/Sydney', '2022-11-11 23:38:59', Time.new(2022, 11, 11, 23, 38, BigDecimal('59'), '+11:00')
45+
46+
# PG produces: "2022-11-12 06:08:59.123456+11"
47+
it_behaves_like ATimestamp, 'Australia/Sydney', '2022-11-11 23:38:59.123456+04:30', Time.new(2022, 11, 11, 23, 38, BigDecimal('59.123456'), '+04:30')
48+
49+
# PG produces: "2000-01-01 05:30:00+05:30"
50+
it_behaves_like ATimestamp, 'Asia/Kolkata', '2000-01-01 00:00:00+00', Time.new(2000, 1, 1, 5, 30, 0, '+05:30')
51+
52+
# PG produces: "2022-11-11 23:38:59+01"
53+
it_behaves_like ATimestamp, 'Europe/Lisbon', '2022-11-11 23:38:59+01', Time.new(2022, 11, 11, 23, 38, BigDecimal('59'), '+01:00')
54+
55+
# PG produces: "infinity"
56+
it_behaves_like ATimestamp, 'UTC', 'infinity', 'infinity'
57+
58+
# PG produces: "-infinity"
59+
it_behaves_like ATimestamp, 'UTC', '-infinity', '-infinity'
60+
61+
# PG produces: null
62+
it_behaves_like ATimestamp, 'UTC', nil, nil
63+
end

0 commit comments

Comments
 (0)