I have a function that queries an SQLite database and returns names, dates and values. In SQLite the dates are in Julian format. I convert the dates in the SQLite query to a date time string which give me "2022-08-01 00:00:00". I want to display this date as the date string "Aug 1, 2022". The only way I have been able to achieve this is to convert the first date string to a date via a date formatter then convert this date to the desired date string via a second date formatter. Is there a more direct way to do this?
func AccessSQLiteDB(db: OpaquePointer?) {
let queryTradingDaysStatement = """
WITH
TempTable1
AS
(
SELECT
max(TimeStamp) - 365.25 as StartingDate
FROM
TradingDays
WHERE
FundName = 'Fund1'
),
TempTable2
AS
(
SELECT
main.FundName,
datetime(main.TimeStamp) as SQLDateString,
main.Close
FROM
TradingDays main, TempTable1 as temp
WHERE
main.FundName = 'Fund1'
AND
main.TimeStamp >= temp.StartingDate
)
SELECT
FundName,
SQLDateString,
Close
FROM
TempTable2
ORDER By
SQLDateString ASC
;
"""
let sqlDateStringFormatter = DateFormatter()
sqlDateStringFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
sqlDateStringFormatter.timeZone = .gmt
var queryTradingDaysCPtr: OpaquePointer?
if sqlite3_prepare_v2(db, queryTradingDaysStatement, -1, &queryTradingDaysCPtr, nil) == SQLITE_OK {
while (sqlite3_step(queryTradingDaysCPtr) == SQLITE_ROW) {
let fundName = sqlite3_column_text(queryTradingDaysCPtr, 0)
let timeStamp = sqlite3_column_text(queryTradingDaysCPtr, 1)
let close = sqlite3_column_double(queryTradingDaysCPtr, 2)
let fundNameAsString = String(cString: fundName!)
let timeStampAsString = String(cString: timeStamp!)
print(timeStampAsString) // returns this format 2022-08-01 00:00:00
let timeStampAsDate: Date = sqlDateStringFormatter.date(from: timeStampAsString)!
print("\(timeStampAsDate)") // returns this format 2022-08-01 00:00:00 +0000
let mediumDataFormatter = DateFormatter()
mediumDataFormatter.dateStyle = .medium
mediumDataFormatter.timeZone = .gmt
let dateString = mediumDataFormatter.string(from: timeStampAsDate)
print(dateString) // returns this format Aug 1, 2022
let closeAsString = String(format: "$%.2f", close)
print(fundNameAsString + " - " + dateString + " - " + closeAsString)
} // end while loop
} else {
let errorMessage = String(cString: sqlite3_errmsg(db))
print("\nQuery is not prepared \(errorMessage)")
}
sqlite3_finalize(queryTradingDaysCPtr)
}
Is there a more direct way to do this?
Definitely. Currently it’s doing all this:
- calling
datetime()
within SQLite to convert a stored Julian value to a string; - using one
DateFormatter
to parse that string into aDate
value; - using a second
DateFormatter
to convert thatDate
value back to a string.
You can eliminate 1 and 2. Just project the raw Julian value in your query (fetching it via sqlite3_column_double
) and then construct your Date
value directly using init(timeIntervalSinceReferenceDate:)
. It just requires simple math to convert from Julian (days since 4713 BC) to Apple reference date (seconds since 2001).
Also this will help your ORDER BY
clause a little, since now it will be sorting by a number rather than a string.
And (basic “code review” comment) you can construct mediumDateFormatter
just once, before the loop. No need to do it inside the loop.