Does Sqlite3 Understand 12 Hours time format? - sqlite

I'm create a Table as follows:
CREATE TABLE IF NOT EXISTS problem(`row_id` INTEGER PRIMARY KEY, `datetime` TEXT)
I insert the values into table
INSERT INTO problem(`row_id`, `datetime`) VALUES
(1, '2021-01-03 12:50 PM'),
(2, '2021-01-03 04:55 PM');
Select the values ordered by column name
SELECT *FROM problem ORDER BY `datetime`
Reselt is here:
row_id datetime
2 2021-01-03 04:55 PM
1 2021-01-03 12:50 PM
In my view, row id 1 will be the first item and row id 2 will be the second entry.
If it does not understand 12 hours time what's the solution?

Does Sqlite3 Understand 12 Hours time format?
No, it understands 24 hour time format (see link below).
If it does not understand 12 hours time what's the solution?
The correct solution would be to store the data in a recognized format as per https://sqlite.org/lang_datefunc.html#time_values
Using a recognised format means that you can then take advantage of SQLite knowing that the column is a date/time/datetime column and thus utilise date time functions as well as being suitable for ordering and comparison.
An example, utilising your dates (note the use of 24 hour times when storing) to get the dates in the 12 hour format based upon 12:00 being PM is :-
DROP TABLE IF EXISTS problem;
CREATE TABLE IF NOT EXISTS problem(`row_id` INTEGER PRIMARY KEY, `datetime` TEXT);
INSERT INTO problem(`row_id`, `datetime`) VALUES
(1, '2021-01-03 12:50'),
(2, '2021-01-03 10:50'),
(3, '2021-01-03 13:55'),
(4, '2021-01-03 16:55'),
(5, '2021-01-03 00:55');
SELECT `row_id`,
date(`datetime`)||
CASE
/* Handle times that are 13:00 or greater i.e. use PM and subtract 12 hours from the stored time */
WHEN time(`datetime`) > '12:59'
THEN ' '||strftime('%H:%M',`datetime`,'-12 hours')||' PM'
/* Handle times that have 12 as the hour i.e. use PM with stored time */
WHEN time(`datetime`) > '11:59'
THEN ' '||strftime('%H:%M',`datetime`)||' PM'
/* ELSE use AM with stored time */
ELSE ' ' || strftime('%H:%M',`datetime`)||' AM'
END
AS `newdatetime` /* Note alias otherwise column name is generated according to column selection code */
FROM problem ORDER BY `datetime`;
Note that the order is as per the datetime column which being in a sortable format is always correct as the 24 hour format is used.
Note that the precision is only suitable for hh:mm e.g. if seconds then 12:59 should be 12:59:59 .....
The result of running the above is :-
The above utilises some of the Date Time Functions found at https://sqlite.org/lang_datefunc.html
The date function returns the date in yyyy-mm-dd format,
The time
function returns the time in hh:mm:ss format,
strftime is the
underlying function that can return a value in many formats based
upon a formatting string and modifiers.
All 3 use a take a time_value
(often the respective column containing the time).
You could perhaps simplify matters by utilising a function in whatever programming language your are using that converts from 24 hour to 12 hour. This could reduce the need for the complicated queries.

Related

Incorrect update in Oracle SQL DB

I tried to update a lot of rows in date format ('DD-MON-YY'). S
So, in cases such 22-FEB-99, I got 22th February 1999, instead of 22th February 2099.
Is there a way to specify the year in such cases?
I tried to update a lot of rows in date format ('DD-MON-YY').
If you have a DATE column then that is a binary data type consisting of 7 bytes (representing century, year-of-century, month, day, hour, minute and second); it ALWAYS has those components and it is NEVER stored in any (human-readable) format.
What you probably mean is that your client application (SQL Developer) is displaying the dates in the format DD-MON-RR and it is not showing you the century or time components.
Is there a way to specify the year in such cases?
Rather than letting the client application apply a default format for displaying the date, you can apply an explicit format using TO_CHAR:
SELECT TO_CHAR(your_date_column, 'FMDDth Month YYYY', 'NLS_DATE_LANGUAGE=English')
AS formatted_date
FROM your_table;
Which, for the sample data:
CREATE TABLE your_table (your_date_column) AS
SELECT SYSDATE FROM DUAL UNION ALL
SELECT DATE '2022-01-01' FROM DUAL UNION ALL
SELECT DATE '1970-01-01' FROM DUAL;
Outputs:
FORMATTED_DATE
2nd November 2022
1st January 2022
1st January 1970
in cases such 22-FEB-99, I got 22th February 1999, instead of 22th February 2099.
If you get the value 22th February 1999 then that is because the date is stored as 1999 and not 2099. Note: that a DATE data type always has a century component so the query will display what is stored in the column.
You have probably inserted (or updated) the date as a string:
INSERT INTO your_table (your_date_column)
VALUES('22-FEB-99');
'22-02-99' is not a date data type, it is a string literal. Oracle has tried to be helpful and implicitly convert the date to a string using the NLS_DATE_FORMAT session parameter effectively converting the query to:
INSERT INTO your_table (your_date_column)
VALUES(
TO_DATE(
'22-FEB-99',
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
)
);
However, your NLS_DATE_FORMAT session parameter is set to DD-MON-RR and the RR format model will convert 99 to 1999 and not 2099.
What you need to do is NEVER use implicit conversion from strings to dates; instead:
Use a date literal:
INSERT INTO your_table(your_date_column) VALUES (DATE '2099-02-22');
Use a timestamp literal (which also allows you to specify the time):
INSERT INTO your_table(your_date_column) VALUES (TIMESTAMP '2099-02-22 00:00:00');
Explicitly convert the string using TO_CHAR and the correct format model:
INSERT INTO your_table(your_date_column)
VALUES (TO_DATE('22-FEB-99', 'DD-MON-YY', 'NLS_DATE_LANGUAGE=English'));
fiddle
Fixing invalid data
If you have the data as 1999 and want 2099 then you will need to fix it:
UPDATE your_table
SET your_date_column = your_date_column + INTERVAL '100' YEAR(3)
WHERE your_date_column = DATE '1999-02-22';
or:
UPDATE your_table
SET your_date_column = ADD_MONTHS(your_date_column, 1200)
WHERE your_date_column = DATE '1999-02-22';
or:
UPDATE your_table
SET your_date_column = DATE '2099-02-22'
WHERE your_date_column = DATE '1999-02-22';
2-digits year is evil (does Y2K ring a bell?). You should really use 4 digits for years. Meanwhile, see whether YY vs. RR format models do any difference in your case.
(you don't have to alter the session; my database uses different date format and language so I'm setting it now)
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> alter session set nls_date_language = 'english';
Session altered.
Sample data and how yy/rr affect the result:
SQL> with test (col) as
2 (select '22-FEB-99' from dual)
3 select to_date(col, 'dd-mon-yy') val1,
4 to_date(col, 'dd-mon-rr') val2
5 from test;
VAL1 VAL2
---------- ----------
22.02.2099 22.02.1999
SQL>

Negative dates in sqllite database

I am working locally with an sqllite DB. I have imported some records from teradata where there was a date field in the format of 'YYYY-MM-DD'. When i imported the records the date switched from a date to a number. I know this is a feature of sqllite and that one can access it via date(sqllite_date) when selecting it in a where clause.
My problem is that the dates now appear to be a bit odd. For example the year appears to be negative.
Is there anyway to recover this to the correct format?
Below is an example of converting a number in the database into a date
SELECT date(18386)
# -4662-03-28
SELECT datetime('now')
# 2021-02-11 10:41:52
SELECT date(sqllite_date) FROM mydb
# Returns -4662-03-28
# Should return 2020-05-04
I am very new to this area so apologies if this is a basic question. Thank you very much for your time
In SQLite you can store dates as TEXT, REAL or INTEGER.
It seems that you stored the dates in a column with INTEGER or REAL affinity.
In this case, if you use the function date(), it considers a value like 18386 as a Julian day, meaning the number of days since noon in Greenwich on November 24, 4714 B.C.
This is why date(18386) returns 4662-03-28B.C.
But I suspect that the date values that you have are the number of days since '1970-01-01'.
In this case, 18386 days after '1970-01-01' is '2020-05-04'.
So you can get the dates in the format YYYY-MM-DD if you add the value of your column as days to '1970-01-01':
SELECT date('1970-01-01', datecolumn || ' day') FROM tablename
Or by transforming your date values to seconds and treat them as UNIX time (the number of seconds since '1970-01-01 00:00:00 UTC'):
SELECT date(datecolumn * 24 * 3600, 'unixepoch') FROM tablename
Replace datecolumn with the name of your column.

How to filter data between date & time in sqlite

I have a table Orders with Order_Date datatype is smalldatetime and my Order_Date Format is 01/10/2018 10:00:00 PM
Now I want to filter data between 01/10/2018 04:00:00 PM AND 02/10/2018 04:00:00 AM
What I tried
SELECT distinct(Order_No),Order_Date from Orders WHERE Order_Date BETWEEN '01/10/2018 04:00:00 PM' and '02/10/2018 04:00:00 AM'
This query is showing only 01/10/2018 Data but I want the data BETWEEN 01/10/2018 04:00:00 PM and 02/10/2018 04:00:00 AM
Is there any way to get the data from today 4PM To Next Day 4AM?
First off, sqlite does not have actual date/time types. It's a simple database with only a few types. Your smalldatetime column actually has NUMERIC affinity (See the affinity rules).
For Sqlite's builtin functions to be able to understand them, date and times can be stored as numbers or text; numbers are either the number of seconds since the Unix epoch, or a Julian day. Text strings can be one of a number of formats; see the list in the docmentation. All these have the additional advantage that, when compared to other timestamps in the same format, they can be properly sorted.
You seem to be using text strings like '01/10/2018 04:00:00 PM'. This is not one of the formats that sqlite date and time functions understand, and it doesn't sort naturally, so you can't use it in comparisons aside from testing equality. Plus it's ambiguous: Is it October 1, or January 10? Depending on where you're from you'll have a different interpretation of it.
If you change your timestamp format to a better one like (Assuming October 1) '2018-10-01 16:00:00', you'll be able to sort and compare ranges, and use it with sqlite functions.

SQLite strftime() weekday

I have been trying with no success to to count how many values were created in a specific week day:
SELECT count(*) as count FROM packets WHERE strftime("%w", timeIn) = '1';
I have this values in timeIn
1472434822.60033
1472434829.12632
1472434962.34593
I don't know what I am doing wrong here.
furthermore, if I use this:
SELECT count(*) as count FROM packets WHERE strftime("%w", timeIn) = '6';
I get
2
which makes no sense. Thank you in advance.
You appear to be storing the date as the number of seconds since 1970 (the Unix epoch) - a common representation. The time strings accepted by the SQLite date functions (see the Time Strings section) default to interpreting numeric time strings as a Julian day numbers:
Similarly, format 12 is shown with 10 significant digits, but the date/time functions will really accept as many or as few digits as are necessary to represent the Julian day number.
You can see this with the following SELECT:
SELECT strftime('%Y-%m-%d', 1472428800.6) AS t
the result of which is:
4026-48-26
For your date representation to be interpreted as a Unix epoch, you need to include 'unixepoch' in the strftime call:
SELECT strftime('%Y-%m-%d', 1472428800.6, 'unixepoch') AS t
which returns:
2016-08-29
If you modify your SELECT to be:
SELECT count(*) as count FROM packets WHERE strftime("%w", timeIn, 'unixepoch') = '6'
you should see results more inline with your expectations.

SQlite: Select rows within a specific time range, ignoring the date

I have a table called messages that stores messages from a chat with the following columns: username, message, datetime, where the type of datetime is TEXT and it is stored in the following format: "yyyy/MM/dd hh:mm:ss". I want to retrieve the average count of rows within a specific time range, without bothering with the date. For instance:
SELECT avg(count(message))
FROM messages
WHERE datetime < "2016/mm/dd 13:00:00" AND
datetime > "2016/mm/dd 12:00:00"
Is there some operator that allows any character to take the place of "mm" and "dd". Essentially, I am trying to construct a query that retrieves the average amount of messages within a specific time range, not the amount of messages on a specific date.
If I read your question correctly, you want to use your WHERE clause to restrict to any calendar date in 2016 between 12 and 13 hours. In this case, you can use STRFTIME to extract the year and hour in string format from your datetime column.
SELECT COUNT(message)
FROM messages
WHERE STRFTIME('%Y', datetime) = '2016' AND
STRFTIME('%H', datetime) < '13' AND
STRFTIME('%H', datetime) > '12'
Note that the reason while the inequalities should work with strings is because numerical strings still sort based on their lexigraphical order.
Update:
Since your datetime column is in a non standard format, you may be able to workaround this by substringing off the various pieces you need to use in the WHERE clause:
SELECT COUNT(message)
FROM messages
WHERE SUBSTR(datetime, 1, 4) = '2016' AND
SUBSTR(datetime, 12, 2) < '13' AND
SUBSTR(datetime, 12, 2) > '12'

Resources