Unix timestamp or IS0-8601 date string in SQLite - sqlite

SQLite doesn't support DATE/DATETIME data type. Therefore datetime can be presented in database as unix timestamp e.g. integer, number of seconds since Jan 01 1970 or as IS0-8601 string
YYYY-MM-DD HH:MM:SS
When datetime is stored as unix timestamp we can perform queries like this:
select * from table where c1 < datetime(1452598502, 'unixepoch', 'localtime')
Also if date is stored as string in the form:
2016-01-10 15:44:42
queries like upper are still correctly executed (lexicographical comparison on the strings will match datetime comparison).
select * from table where c1 < '2016-01-10 15:43:52'
Futher more unix timestamp has max value year 2038, afterthat it's overflow. YYYY has maximum date 9999. Both have a max value. Is there any advantage one over another? I just can't seem to prefer one over another. Maybe I prefer datetime as string YYYY-MM-DD HH:mm:ss as it has max value greater than unixtimestamp.

Unix timestamps overflow in the year 2038 only if they are stored as 32-bit values. SQLite supports 64-bit values.
A single number requires less storage space than a string (but this matters only if you have a very large number of records). You have to balance this against the easier debuggability of strings.

Related

decimal number valued datetime formatting in 4gl

The value of the field is in (deci-5 99999999.99999) format, like:
20201231.65624
where 2020 is year, 12 is month, 31 is date and .65624 is the hour and minute value.
I want to display it like 31/12/2020 18:13.
I mean DD/MM/YY hh:mm like this format. So far, I am able to display only the date part i.e. 31/12/2020. But not able to display the hour and minute part.
Appreciate help on this regards. Thanks.
This will display the time portion in hh:mm:ss if the value is a string:
display string( integer ( entry( 2, "20201231.65624", "." )), "hh:mm:ss" ).
or, if the value is a decimal:
define variable d as decimal no-undo initial 20201231.65624.
display string( integer(( d - truncate( d, 0 )) * 100000 ), "hh:mm:ss" ).
Obviously you would want to abstract that approach to fit whatever your real need is.
The technique of using a character or decimal field to hold a datetime is a legacy of ancient versions of Progress that did not support a DATETIME or DATETIME-TZ datatype. Since OpenEdge 10 you have a native datatype that you should be using for that purpose. This kind of approach with decimals and strings should really only be used for backwards compatibility to old code and old database schemas.

How to parse 18-digit sqlite timestamp

The sqlite timestamp here is 18 digits, but how can one know its specific date. 132079170460000000 should correspond to July 2019, but this year cannot be obtained regardless of interpretation or other conversions. I want to get time like 2019-07-30 13:23:40.
This is sqllite timestamp, but product specific model does not know,only know that this timestamp is 18-digit just like these:
132079170420000000
132079218060000000
If 132089746940000000 is equivalent to "2019-07-31 13:42:31" as mentioned in the comments, then try this:
SELECT datetime( DateColumnWith18Digits / 1.0E11 + 1137798.60179213 )
FROM SomeTable
If the example you shared was just a random value, this technique might still work, but you'll need to find the offset factor. The conversion assumes that the 18-digit value is the number of milliseconds since some epoch. I simply assumed that one of the comments contained a valid equivalence and found the offset to match the Julian date value.
The reverse encoding would be like
SELECT (julianday('2019-07-31 13:42:31') - 1137798.60179213) * 1E11

SQLite select count records from 10 hours ago

I have this database
Table [Ticks]
Fields: 2
[Value]: INT
[Time]: DATETIME
Indexes: 1
[TicksIdx]
[Time]
[Value]
Triggers: 0
Table constraints:
Primary Key:
Fields:
On Conflict:
Foreign Keys: 0
Unique constraints: 0
Check constraints: 0
Table [Ticks] end
And I want to count all the records with value=-1 and Time < (Now-10 hours) from 10 hours ago until now
I have this query and always returns 0
select count(*) from Ticks where Value=-1 and
time>=datetime('now', '-10 hours')
If I change the query to this then it returns all the records
select count(*) from Ticks where Value=-1 and
time<datetime('now', '-10 hours')
and I have records with time values more recent than 10 hours
Explanations
You issue will be due to the value stored in the time column not being in a recognised format, complicated also with not comparing like for like.
The SQLite recognised formats can be found here SQL As Understood By SQLite - Date And Time Functions - Time Strings.
For example YYYY-MM-DD HH:MM:SS (e.g. 2018-12-09 12:40:01) is such a recognised format.
You query is (assuming 9/12/2018 12:40:01 AM from c# and the runtime is the same) saying:-
is 9/12/2018 12:40:01 AM >= 2018-12-09 12:40:01
as the values are non-numeric then a character by character comparison is undertaken so using these times 9 IS greater than 2 (of course if it were 09/12..... then IS NOT).
The correct way, to ensure like for like comparison, if the underlying data is in a recognised format, would be to ensure that both sides compare dimetime's as such really the SQL should therefore be :-
SELECT count(*) FROM Ticks WHERE Value=-1 AND datetime(time) >= datetime('now', '-10 hours')
note datetime(time) may only be needed if the date in the time column were another recognised format than the example format.
-note you may need to incorporate localtime to adjust times e.g. datetime(time) >= datetime('now','localtime', '-10 hours')
as per
The "localtime" modifier (12) assumes the time string to its left is
in Universal Coordinated Time (UTC) and adjusts the time string so
that it displays localtime. If "localtime" follows a time that is not
UTC, then the behavior is undefined. The "utc" modifier is the
opposite of "localtime". "utc" assumes that the string to its left is
in the local timezone and adjusts that string to be in UTC. If the
prior string is not in localtime, then the result of "utc" is
undefined.
Fix(es)
To fix the issue you would need to either
do a complex reformat of the time column, dependant upon the format of the value in the time column, for the comparison (not recommended)
or ensure that the value is stored in a SQlite recognised format.
If the time is the current time when the ticks row is inserted, then you could use time DATETIME DEFAULT CURRENT_TIMESTAMP as the definition for the time column and not supply a value for the time column when inserting a row.
Otherwise you should change the format of the value to a recognised format before storing the value.

Local date in SQLite

I have records containing timestamps, and I want to be able to group by date (according to my local time zone).
The timestamps are already ISO 8601 strings (in the same local time zone with UTC offset specified). I tried using the SQLite date function, however it seems to only give UTC dates:
select date(time), time from mytable;
('2001-07-14', '2001-07-15 09:40:02.500000+10:00'),
('2001-07-14', '2001-07-15 09:39:38.500000+10:00'),
('2001-07-21', '2001-07-22 09:46:09.500000+10:00'),
...
In Postgres I would take a UTC timestamp and do something like ((mystring::timestamp at time zone 'UTC') at time zone 'AEST')::date. I suppose if my timestamps are already expressed with my desired offset, I could just do a string truncation (i.e. substr(time,1,10)), but this seems much less readable code. Can SQLite generally convert timestamps to localised dates?
Can try date(time,'localtime') provided that the target timezone is also currently the system local time zone (which is an awkward requirement).
Otherwise, date(time, '+10 hours').

How to compare two dates in SQLite?

I kind of assumed it was a string, so I compared it as a string, but not surprisingly it failed. I believe thats how it works in Mysql. I could be wrong as I haven't worked on it in a while. In either case, how can I check if dates are equal in SQLite? I will be using it in a WHERE clause.
SELECT a._id, b._id, b.start_date,a.event_name, b.start_time,
b.end_date, b.end_time, b.location FROM events_info b INNER JOIN events a ON
a._id=b.event_id WHERE b.start_time = '6:00';
(added space to make it easier to look at)
SQLite doesn't have a dedicated DATETIME type. Normally what people do is make sure they store the date as a formatted string that is consistent; for example, YYYY-MM-DD hh:mm:ss. If you do so, as long as you're consistent, then you can compare dates directly:
SELECT * FROM a WHERE q_date < '2013-01-01 00:00:00';
This works because even though the comparison is technically an alphabetical comparison and not a numeric one, dates in a consistent format like this sort alphabetically as well as numerically.
For such a schema, I would suggest storing dates in 24-hour format (the above example is midnight). Pad months, days, and hours with zeros. If your dates will span multiple timezones, store them all in UTC and do whatever conversion you need client-side to convert them to the local time zone.
Normally dates and times are stored all in one column. If you have to have them separated for whatever reason, just make sure you dates are all consistent and your times are all consistent. For example, dates should all be YYYY-MM-DD and times should all be hh:mm:ss.
The reason that YYYY-MM-DD hh:mm:ss is the preferred format is because when you go from the largest date interval (years) to the smallest (seconds), you can index and sort them very easily and with high performance.
SELECT * FROM a WHERE q_date = '2012-06-04 05:06:00';
would use the index to hone in on the date/time instead of having to do a full table scan. Or if they're in two separate rows:
SELECT * FROM a WHERE q_date = '2012-06-04' AND q_time = '05:06:00';
The key is to make sure that the dates and times are in a consistent format going into the database. For user-friendly presentation, do all conversion client-side, not in the database. (For example, convert '2012-06-04 05:06:00' to "1:06am Eastern 6/4/2012".)
If this doesn't answer question, could you please post the exact format that you're using to store your dates and times, and two example dates that you're trying to compare that aren't working the way you expect them to?
Sqlite can not compare dates directly. we need to convert them in seconds as well as integer also.
Example
SELECT * FROM Table
WHERE
CAST(strftime('%s', date_field) AS integer) <=CAST(strftime('%s', '2015-01-01') AS integer) ;
From Datatypes In SQLite Version 3:
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.
If you look at the examples in Date And Time Functions, something like this should get you close to what you want (which, I'm assuming, is 6:00 of the current day):
WHERE b.start_time = date('now', 'start of day', '+6 hours')

Resources