Skip to content

Commit a9a862d

Browse files
authored
Fix Date precision error (#33)
* Fixes #31 Co-authored-by: Austin Payne <[email protected]>
1 parent cb114dc commit a9a862d

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

Sources/SQLiteNIO/SQLiteDataConvertible.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ extension Date: SQLiteDataConvertible {
126126
default:
127127
return nil
128128
}
129-
self.init(timeIntervalSince1970: value)
129+
// Round to microseconds to avoid nanosecond precision error causing Dates to fail equality
130+
let valueSinceReferenceDate = value - Date.timeIntervalBetween1970AndReferenceDate
131+
let secondsSinceReference = round(valueSinceReferenceDate * 1e6) / 1e6
132+
self.init(timeIntervalSinceReferenceDate: secondsSinceReference)
130133
}
131134

132135
public var sqliteData: SQLiteData? {

Tests/SQLiteNIOTests/SQLiteNIOTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,31 @@ final class SQLiteNIOTests: XCTestCase {
2626
let rows = try conn.query("SELECT ? as date", [date.sqliteData!]).wait()
2727
XCTAssertEqual(rows[0].column("date"), .float(date.timeIntervalSince1970))
2828
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!)?.description, date.description)
29+
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!), date)
30+
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!)?.timeIntervalSinceReferenceDate, date.timeIntervalSinceReferenceDate)
31+
}
32+
33+
func testTimestampStorageRoundToMicroseconds() throws {
34+
let conn = try SQLiteConnection.open(storage: .memory, threadPool: self.threadPool, on: self.eventLoop).wait()
35+
defer { try! conn.close().wait() }
36+
37+
// Test value that when read back out of sqlite results in 7 decimal places that we need to round to microseconds
38+
let date = Date(timeIntervalSinceReferenceDate: 689658914.293192)
39+
let rows = try conn.query("SELECT ? as date", [date.sqliteData!]).wait()
40+
XCTAssertEqual(rows[0].column("date"), .float(date.timeIntervalSince1970))
41+
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!)?.description, date.description)
42+
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!), date)
43+
XCTAssertEqual(Date(sqliteData: rows[0].column("date")!)?.timeIntervalSinceReferenceDate, date.timeIntervalSinceReferenceDate)
44+
}
45+
46+
func testDateRoundToMicroseconds() throws {
47+
let secondsSinceUnixEpoch = 1667950774.6214828
48+
let secondsSinceSwiftReference = 689643574.621483
49+
let timestamp = SQLiteData.float(secondsSinceUnixEpoch)
50+
let date = try XCTUnwrap(Date(sqliteData: timestamp))
51+
XCTAssertEqual(date.timeIntervalSince1970, secondsSinceUnixEpoch)
52+
XCTAssertEqual(date.timeIntervalSinceReferenceDate, secondsSinceSwiftReference)
53+
XCTAssertEqual(date.sqliteData, .float(secondsSinceUnixEpoch))
2954
}
3055

3156
func testTimestampStorageInDateColumnIntegralValue() throws {

0 commit comments

Comments
 (0)