SQLite epoch time in milliseconds - sqlite

I have a time column in a table which is supposed to represent the time (on the server), in milliseconds since the Epoch, when the record was created.
However, strftime("%s") returns an integer, omitting the millisecond value.
It appears the strftime("%f") returns a second value relative to the current minute, and a millisecond value that is synchronized with both the second of the minute and the epoch.
So it appears that I can get the value I want using this rather convoluted statement:
select CAST(strftime('%s','now') || '.' || substr(strftime('%f','now'),4,3) AS REAL)
Is this reliable? My main concern is the fact that I have to call strftime() twice, is it possible that the second value will advance between calls so that I get (for example) 4.999 when I should get 3.999? I can imagine maybe creating a temporary table to store the results of strftime("%f %s") and then taking the substr of two separate selects, but this is even more convoluted and I'm not sure if it is necessary (is SQLite smart enough to only call strftime() once and return the same result twice?) Is there a better way to do this?

It is safe. From the documentation,
The 'now' argument to date and time functions always returns
exactly the same value for multiple invocations within the same
sqlite3_step() call.
This can be verified with the following query:
WITH RECURSIVE cnt(x,y) AS (
SELECT 1,1
UNION ALL
SELECT
x+1,
CAST(strftime('%s','now') || '.' || substr(strftime('%f','now'),4,3) AS REAL)
FROM cnt
LIMIT 10000)
SELECT x,y FROM cnt;
On my machine this query takes 40ms, but all time values are the same.

Related

Force Oracle's sysdate to return different value for multiple statements

I'd like to force Oracle sysdate function to return different values for separate statements, just like it does in Postgres. I've done some digging over the documentation, net and SO itself but couldn't find an answer to address this.
Documentation seems to be pretty poor for this one: see for yourself
I'm using Oracle 11g with SQL Developer 18.3
Please read on the MVCE below.
After executing this:
create table t(a timestamp);
insert into t values (sysdate);
insert into t values (sysdate);
insert into t values (sysdate);
select * from t;
I get:
A
---------------------------
18/12/25 04:25:59,000000000
18/12/25 04:25:59,000000000
18/12/25 04:25:59,000000000
I would want to get (changed by hand):
A
---------------------------
18/12/25 04:25:59,1234
18/12/25 04:25:59,7281
18/12/25 04:26:00,1928
Real issue is presented within different CALL statements to procedures, but the above sample seems to replicate the issue for me.
UPDATE
One thing I found to be helpful is to put pauses between statements, but this really isn't what I'm looking for:
set pause on;
create table t(a timestamp);
insert into t values (sysdate);
pause
insert into t values (sysdate);
pause
insert into t values (sysdate);
As noted in the documentation, the sysdate function returns a date, which only has precision down to seconds - it does not support fractional seconds. So, multiple calls within the same second will always get the same value, and you can't force it to do anything else.
You're putting that date value into a timestamp column, which is causes an implicit conversion from one data type to the other, but that conversion can't set/create a new fractional seconds value - it keeps the implicit fractional seconds from the date, which is of course always zero.
As well as sysdate, Oracle has a systimestamp function, which returns a timestamp with time zone value - and that does have fractional seconds. The precision is limited by the platform you're running on. If you use that to populate your plain timestamp column then an implicit conversion still occurs, but you essentially just throw away the time zone information.
Oracle also supports current_date and current_timestamp, which are very similar - except they return the date/time in the current session time zone, rather than in the server time zone as the sys* versions do.
I found that current_timestamp does the job:
drop table t;
create table t(a timestamp);
insert into t values (current_timestamp);
insert into t values (current_timestamp);
insert into t values (current_timestamp);
select * from t;
Outputs:
A
---------------------------
18/12/25 04:48:54,134000000
18/12/25 04:48:54,142000000
18/12/25 04:48:54,149000000

Sqlite order of query

I'm running this query on a sqlite db and it looks that its working fine.
SELECT batterij ,timestamp FROM temphobbykamer WHERE nodeid= 113 AND timestamp >= 1527889336634 AND timestamp <= 1530481336634 AND ROWID % 20 =0
But can i be sure that the query is handled in the correct order?
It must find all records from node113 between time A and B. From this selection found I only want to have every 20th record.
I can imagine if the query order difference, that if you query every 20th record between time A and B and select from this selection all the node113 records that the response will be different.
When no ORDER BY is specified, the order is undefined. However, typically sqlite will return in ROWID order since you haven't specified anything else. To make sure you get consistent results, you should specify ORDER BY ROWID

Comparison of a number with strftime() works inconsistenly

I want to select today's visited urls from the firefox database places.sqlite.
As first attempt, the query I used to accomplish this was (see the operator >):
SELECT datetime(moz_places.last_visit_date/1000000,'unixepoch'), moz_places.title
FROM moz_places
WHERE moz_places.last_visit_date/1000000>strftime('%s','now','start of day')
ORDER BY moz_places.last_visit_date DESC;
The answer to this query is nothing.
Then I changed the query to this, which is pretty much the same (see the operators - and >):
SELECT datetime(moz_places.last_visit_date/1000000,'unixepoch'), moz_places.title
FROM moz_places
WHERE moz_places.last_visit_date/1000000-strftime('%s','now','start of day')>0
ORDER BY moz_places.last_visit_date DESC;
then the answer is correct.
Does anybody out there know why > works in one query by does not in the other?
The strftime() function always returns a string, and a string always compares larger than a number.
When you try to use a string with addition/subtraction, it is automatically converted into a number first, so the result of last_visit_date-strftime(...) is a number.
You could change the function call in the original query to:
CAST(strftime('%s', ...) AS NUMBER)
or, less obvious, if you want to save typing:
strftime('%s', ...)+0

How can I check data type of node value in cypher query?

I am having graph database which is collection of events and attendees.
I store start_time property of an event as unix timestamp so that its easier to search upcoming events just by comparing unix timestamp.
Now the problem is by mistake I stored date string as start_time value in few events and now I can not compare date string with unix timestamp, and thats why query returns no events.
How can I compare data type of start_time property before comparing its value?
Please guide me the correct way to achieve my objective..
You can implicitly check for the property type using the toInt function and comparing with the value. To convert all string style start_time to their numeric variant:
MATCH (n)
WHERE has(n.start_time) and (toInt(n.start_time)<>n.start_time)
SET n.start_time = toInt(n.start_time)
In case of a lot of nodes use SKIP and LIMIT to work on reasonable batches.
This is how I solved this problem.
"START attendee=node:attendee('user_id:100001195447969') MATCH (attendee)-[:friends_with]-(friend)-[:attending]-(event) WITH event,attendee as user, count(distinct friend.user_id) as count WHERE REPLACE(str(event.start_time),"-","") = str(event.start_time) AND count >= 1 RETURN event.start_time;"
So now it does not give me events having start_time like "2014-06-05 10:00:00". And I can compare start_time of rest of the events.
I don't know if this would work, but could you compare the value to the value wrapped in a str function? It may not work if the string properties are formatted like unix timestamp, but it's worth a try.
MATCH (e:Event) WHERE e.start_date = str({e.start_date}) RETURN e;

How can I store the current timestamp in SQLite as ticks?

I have a SQLite database where I store the dates as ticks. I am not using the default ISO8601 format. Let's say I have a table defined as follows:
CREATE TABLE TestDate (LastModifiedTime DATETIME)
Using SQL, I wish to insert the current date and time. If I execute any of the below statements, I end up getting the date and time stored as a string and not in ticks.
INSERT INTO TestDate (LastModifiedTime) VALUES(CURRENT_TIMESTAMP)
INSERT INTO TestDate (LastModifiedTime) VALUES(DateTime('now'))
I have looked at the SQLite documenation, but I do not seem to find any option to obtain the current timestamp in ticks.
I can of course define a parameter in C# and store the value as a System.DateTime. This does result in the datetime getting stored to the database in ticks.
What I would like to do is be able to insert and update the current timestamp directly from within the SQL statement. How would I do this?
Edit:
The reason I want the data stored as ticks in the database, is that the dates are stored in the same format as stored by the ADO.Net data provider, and so that when the data is also queried using the ADO.Net provider it is correctly retrieved as a System.DataTime .Net type.
This particular oddity of SQLite caused me much anguish.
Easy way - store and retrieve as regular timestamp
create table TestDate (
LastModifiedTime datetime
);
insert into TestDate (LastModifiedTime) values (datetime('now'));
select datetime(LastModifiedTime), strftime('%s.%f', LastModifiedTime) from TestDate;
Output: 2011-05-10 21:34:46|1305063286.46.000
Painful way - store and retrieve as a UNIX timestamp
You can use strftime to retrieve the value in ticks. Additionally, to store a UNIX timestamp (roughly equivalent to ticks), you can can surround the number of seconds in single-quotes.
insert into TestDate (LastModifiedTime) values ('1305061354');
SQLite will store this internally as some other value that is not a UNIX timestamp. On retrieval, you need to explicitly tell SQLite to retrieve it as a UNIX timestamp.
select datetime(LastModifiedTime, 'unixepoch') FROM TestDate;
To store the current date and time, use strftime('%s', 'now').
insert into TestDate (LastModifiedTime) VALUES (strftime('%s', 'now'));
Full example:
create table TestDate (
LastModifiedTime datetime
);
insert into TestDate (LastModifiedTime) values (strftime('%s', 'now'));
select datetime(LastModifiedTime, 'unixepoch') from TestDate;
When executed by sqlite3, this script with print:
2011-05-10 21:02:34 (or your current time)
After further study of the SQLite documentation and other information found on date number conversions, I have come up with the following formula, which appears to produce correct results:
INSERT INTO TestDate(LastModifiedTime)
VALUES(CAST((((JulianDay('now', 'localtime') - 2440587.5)*86400.0) + 62135596800) * 10000000 AS BIGINT))
Seems like a painful way to produce something that I would expect to be available as a built-in datetime format, especially that the database supports the storing of datetime values in ticks. Hopefully, this becomes useful for others too.
Update:
The above formula is not perfect when it comes to daylight savings. See section Caveats And Bugs in SQLite docs regarding local time calculation.
The following will return the number of milliseconds since the UNIX Epoch:
SELECT (strftime('%s', 'now') - strftime('%S', 'now') + strftime('%f', 'now')) * 1000 AS ticks
It works by grabbing the number of seconds since the Unix Epoch (%s), subtracting the number of seconds in the current time (%S), adding the number of seconds with decimal places (%f), and multiplying the result by 1000 to convert from seconds to milliseconds.
The subtraction and addition are to add precision to the value without skewing the result. As stated in the SQLite Documentation, all uses of 'now' within the same step will return the same value.

Resources