SQLite timestamp conversion function - sqlite

I've inherited a SQLite DB, in it I've a TIMESTAMP field called ZDATE.
One value is 401,580,000 and I know it correspond to Sept 23rd, 2013.
I've calculated that the 0 of this field is the midnight of Jan 1st, 2001 (?).
However, I didn't find any conversion function to get a formatted date, in fact if I use date() I get:
ZDATE date(zdate)
401580000 1094776-12632211-20
Any help will be appreciated.

> select 401580000 / (julianday('2013-09-23') - julianday('2001-01-01'));
86398.4509466437
> select 60*60*24;
86400
So this timestamp appears to use seconds.
To convert it into a timestamp that SQLite can use directly, i.e., a Unix epoch timestamp, just add the appropriate offset:
> select datetime(401580000 + strftime('%s', '2001-01-01 02:00:00'), 'unixepoch');
2013-09-23 00:00:00

Related

Why does SQLite consider larger number < smaller number to be true?

Querying the SQLite database of my Android app, I'm running into a curious problem. I've got a query that checks one epoch time (stored in the database in an integer field) against the current epoch time. To simplify debugging, I wrote a little test query to see how SQLite handles my epoch integer versus the strftime function. Here's my query:
select 1615759200 < strftime('%s', 'now');
The result is:
1
For reference: the value 1615759200 is the date March 14, 2021. The current date at time of writing is April 28, 2020 which is roughly 1588033692 in epoch time. For obvious reasons, I'm expecting the above query to result 0: false, as the date in 2021 is NOT smaller than the date in 2020. And yet, it returns 1: true! It's infuriating! Can anyone tell me what I'm missing here?
The data type that is returned by strftime() is text and you must cast it to an integer so that the comparison will work the way that you expect:
select 1615759200 < cast(strftime('%s', 'now') as int)
or:
select 1615759200 < strftime('%s', 'now') + 0
You can find more about data types and affinities of SQLite: Datatypes In SQLite Version 3

TeradataSQL: Time to String, Add to Date and Compare to Another Time and Data

I'm trying to figure out the cleanest way to do a comparison in Teradata SQL Assistant. I have the scheduled start date (TimeStamp), the Schedule start time (varchar), actual start and end times (TimeStamp). I need to consolidate the scheduled start date and time and be able to compare it to the actual start and end date and time without modifying the original data (because it's not mine). I realize that the Scheduled Start Time [SST] is in a 24 hour time format with a AM/PM suffix, but like I said before, I can't change that.
I tried to do select cast(substr(scheduled_start_date,1,5) as TIMESTAMP(0)) from DB.TBL but am getting the "Invalid timestamp" error. There is example table data below.
Sch Start Date Sch Start Time Actual Start Actual End
09/11/2017 00:00:00 11:30 AM 09/11/2017 11:34:16 09/11/2017 11:58:00
05/26/2017 00:00:00 15:30 PM 05/26/2017 15:40:00 05/26/2017 15:55:15
11/06/2017 00:00:00 19:30 PM 11/06/2017 21:25:00 11/06/2017 21:45:00
Thanks!
You need to cast the schedule start time as an Interval, then you can easily add it to the start date:
scheduled_start_date
+ Cast(Substr(scheduled_start_time, 1,5) AS INTERVAL HOUR TO MINUTE)
A start date which is a timestamp seems to indicate this was ported from Oracle/SQL Server?
And a 24 hour time format with a AM/PM suffix is also quite strange.
A couple things to try:
Convert the separate Scheduled Date and Scheduled Time fields into strings, concatenate them, and feed that into a TIMESTAMP CAST. Something like:
SELECT
CAST(CAST(Scheduled_Date AS DATE) AS VARCHAR(25)) AS Date_String,
CAST(CAST(Scheduled_Time AS TIME FORMAT 'HH:MM BB') AS VARCHAR(25)) AS Time_String,
CAST(TRIM(Date_String) || ' ' || TRIM(Time_String) AS TIMESTAMP(0)) AS MyTimestamp
Cast the Scheduled Time field as a TIME data type. Cast the Scheduled Date field as a DATE data type. Then somehow combine the two into a TIMESTAMP field -- either with a CAST or some kind of timestamp constructor function (not sure if this is possible)
Option 1 should work for sure as long as you properly format the strings. Try to avoid using SUBSTRING and instead use FORMAT to cast as DATE/TIME fields. Not sure about Option 2. Take a look at these link for how to format DATE/TIME fields using the FORMAT clause:
https://www.info.teradata.com/HTMLPubs/DB_TTU_16_00/index.html#page/SQL_Reference%2FB035-1143-160K%2Fmuq1472241377538.html%23wwID0EPHKR
https://www.info.teradata.com/HTMLPubs/DB_TTU_16_00/index.html#page/SQL_Reference/B035-1143-160K/cmy1472241389785.html
Sorry, I don't have access to a TD system to test it out. Let me know if you have any luck.

SQLite doesn't seem to convert unix epoch correctly

I insert timestamps in a column of type real. The timestamps are in unixepoch format, eg 1505720496876 which is GMT: Monday, September 18, 2017 7:41:36.876 AM.
However, when I perform the query
select datetime(timestamp, 'unixepoch', 'localtime') from history I get -1413-03-01 14:07:12 as result.
What am I doing wrong?
You are currently using milliseconds but you need to use seconds:
select datetime(timestamp / 1000, 'unixepoch', 'localtime')
from history
From the documentation:
The "unixepoch" modifier (11) only works if it immediately follows a timestring in the DDDDDDDDDD format. This modifier causes the DDDDDDDDDD to be interpreted not as a Julian day number as it normally would be, but as Unix Time - the number of seconds since 1970.

What format is the Safari History.db history_visits.visit_time in?

When looking at the History.db from Safari, there's a table named history_visits which has a column named visit_time, which is a REAL value. It has values such as 470799793.096987. What format is that in? I'd like to see it in a format such as 12/08/2015 05:12:05.
It's the number in seconds since 00:00:00 UTC on 1 January 2001. It must be coming from an NSDate.
NSDate objects encapsulate a single point in time, independent of any particular calendrical system or time zone. Date objects are immutable, representing an invariant time interval relative to an absolute reference date (00:00:00 UTC on 1 January 2001).
— NSDate Class Reference
To get a decent human value out of it, you must add 978307200 (the epoch for 2001-01-01 00:00:00).
This query should give you what you want:
.headers on
select datetime(v.visit_time + 978307200, 'unixepoch', 'localtime') as date, v.visit_time + 978307200 as epoch, v.visit_time, i.domain_expansion, i.url
from history_items i left join history_visits v on i.id = v.history_item
order by i.id desc
limit 100;
Example output:
date|epoch|visit_time|domain_expansion|url
2015-12-31 11:51:27|1451562687.28465|473255487.284646|duckduckgo|https://duckduckgo.com/?q=current+timestamp+2015-12-31+11:51&t=osx
PS: Just for future reference, the Safari db file is located at ~/Library/Safari/History.db
To convert the visit_time value in the history.db in an excel spread sheet, open the history.db file in a tool such as DB browser for SQLLite (Windows) and export the history_visits values to a CSV file.
Open the CSV file and create a column where you will populate your values in human readable time adjusted to your time zone, and use the following formula convert your NSDate:
=((((C2+978307200)/60)/60)/24)+DATE(1970,1,1)+(-5/24)
In the above formula, the time value is in cell C2, and my time zone GMT-5. To adjust to your own time zone adjust the statement in the last set of parenthesis. Presently I have (-5/24) to represent GMT-5.
When I first approached this conversion, I mistakenly assumed the time in the history.db to be epoch time, which starts at 1/1/1970, and did not understand why there was such a skew in time. Adding the required conversion factor +978307200 solved the problem.
I found the domain_expansion field to be null in some cases, here's a modified query:
SELECT SUBSTR(
SUBSTR(url, INSTR(url, '/')+2),
1,
INSTR(SUBSTR(url, INSTR(url, '/')+2),'/') - 1
) domain,
url,
datetime(hv.visit_time + 978307200, 'unixepoch', 'localtime') visit_time
FROM history_items hi
JOIN history_visits hv on hi.id = hv.history_item;

Storing my dates as long (milliseconds) in SQLite: Can I use strftime(...)?

I'm storing my dates in SQLite in a column of data type INTEGER. I'm storing the milliseconds since 1970.
Eg:
date (long) other columns ...
-----------------------------------------
1407297600000 ...
1407211200000 ...
1407124800000 ...
My question is: how can I use strftime() under this circumstances?
If not, I should use TEXT as the column type??
Running this:
select strftime('%Y-%m', date) from my_table;
Is throwing nonesense stuff:
strftime('%Y-%m', date)
-----------------------------------------
1968-19
1968-19
1968-19
Unless you tell it otherwise, strftime() thinks those numbers are Julian day values - very different from Unix epoch milliseconds.
You'll want to convert to seconds, and tell strftime() these are Unix epoch numbers:
select strftime('%Y-%m', date / 1000, 'unixepoch');
See the Modifiers section in the SQLite Date and Time Functions docs.

Resources