How to convert 2001 based timestamp to datetime in SQLite? - sqlite

ZPUBLICATIONDATETIME is of type TIMESTAMP.
So when I do this:
SELECT strftime('%d - %m - %Y ', datetime(ZPUBLICATIONDATETIME, 'unixepoch')) FROM ZTNNEWS;
I get 26 - 05 - 1984 instead of 2015. iOS (Core Data) writes datetime on 1 Jan 2001 based. What is the best approach to get the right date conversion?
Shall I just add 31 years to it or is there an alternative to unixepoch to put in there?
Essentially what I am trying to do is to get the records from past two days:
select *
from ZTNNEWS
where DATETIME(ZPUBLICATIONDATETIME) > DATETIME('now', '-2 day')
But because ZPUBLICATIONDATETIME is of type TIMESTAMP rather than Datetime, it doesn't output anything.
Any advice please?

Just had the same problem. Adding the date value to the seconds of 1 Jan 2001 seems to do the job:
SELECT * FROM ztnnews WHERE DATETIME(zpublicationtime + 978307200) > DATETIME('now', '-2 day');
I used ruby to get the seconds of 1 Jan 2001:
$ irb
2.2.3 :001 > require "time"
=> true
2.2.3 :002 > Time.parse( "2001-01-01T00:00:00Z").to_i
=> 978307200

Related

Get the MAX(value) using fiscal type years ie; 2016/2017, etc

My calendar year runs from 07-01-(of one year) to 06-30-(of the next year).
My SQLITE DB has a Timestamp column and it's data type is datetime and stores the timestamp as 2023-09-01 00:00:00.
What I'm trying to do is get the MAX date of the latest snowfall. For example, with my seasonal years beginning July-01 (earliest) and ending June 30 (latest), I want to find only the latest (MAX) date snowfall was recorded, regardless of the year, based on the month.
Say if out of five years (2017 to 2022) worth of data in the database and it snowed Mar 15, 2020. And there was no date greater than than this one in any year, then this would be the latest date regardless which year it fell.
I've been trying many variations of the below query. This query says it runs with no mistakes and returns "null" values. I'm using SQLITE DB Browser to write and test the query.
SELECT Timestamp, MAX(strftime('%m-%d-%Y', Timestamp)) AS lastDate,
snowDepth AS lastDepth FROM DiaryData
WHERE lastDepth <> 0 BETWEEN strftime('%Y-%m-%d', Timestamp,'start of year', '+7 months')
AND strftime('%Y-%m-%d', Timestamp, 'start of year', '+1 year', '+7 months', '- 1 day')
ORDER BY lastDate LIMIT 1
and this is what's in my test database:
Timestamp snowFalling snowLaying snowDepth
2021-11-10 00:00:00 0 0 7.2
2022-09-15 00:00:00 0 0 9.5
2022-12-01 00:00:00 1 0 2.15
2022-10-13 00:00:00 1 0 0.0
2022-05-19 00:00:00 0 0 8.82
2023-01-11 00:00:00 0 0 3.77
If it's running properly I should expect:
Timestamp
lastDate
lastDepth
2022-05-19 00:00:00
05-19-2022
8.82
What am I missing or is this not possible in SQLITE? Any help would be appreciative.
Use aggregation by fiscal year utilizing SQLite's feature of bare columns:
SELECT Timestamp,
strftime('%m-%d-%Y', MAX(Timestamp)) AS lastDate,
snowDepth AS lastDepth
FROM DiaryData
WHERE snowDepth <> 0
GROUP BY strftime('%Y', Timestamp, '+6 months');
See the demo.
I'd get season for each record first, snowfall date relative to record's season start date after this, and largest snowfall date relative to record's season start date finally:
with
data as (
select
*
, case
when cast(strftime('%m', "Timestamp") as int) <= 7
then strftime('%Y-%m-%d', "Timestamp", 'start of year', '-1 year', '+6 months')
else strftime('%Y-%m-%d', "Timestamp", 'start of year', '+6 months')
end as "Season start date"
from DiaryData
where 1==1
and "snowDepth" <> 0.0
)
, data2 as (
select
*
, julianday("Timestamp") - julianday("Season start date")
as "Showfall date relative to season start date"
from data
)
, data3 as (
select
"Timestamp"
, "snowFalling"
, "snowLaying"
, "snowDepth"
from data2
group by null
having max("Showfall date relative to season start date")
)
select
*
from data3
demo
You can use the ROW_NUMBER window function to address this problem, yet need to apply a subtle tweak. In order to account for fiscal years, you can partition on the year for timestamps slided 6 months further. In this way, ranges like [2021-01-01, 2021-12-31] will instead be slided to [2021-06-01, 2022-05-31].
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(
PARTITION BY STRFTIME('%Y', DATE(Timestamp_, '+6 months'))
ORDER BY Timestamp_ DESC ) AS rn
FROM tab
)
SELECT Timestamp_,
STRFTIME('%d-%m-%Y', Timestamp_) AS lastDate,
snowDepth AS lastDepth
FROM cte
WHERE rn = 1
Check the demo here.

How to convert epoch to datetime redshift?

I work in dbeaver. I have a table x.
TABLE x has a column "timestamp"
1464800406459
1464800400452
1464800414056
1464800422854
1464800411797
The result I want:
Wed, 01 Jun 2016 17:00:06.459 GMT
Wed, 01 Jun 2016 17:00:00.452 GMT
Wed, 01 Jun 2016 17:00:14.056 GMT
Wed, 01 Jun 2016 17:00:22.854 GMT
Wed, 01 Jun 2016 17:00:11.797 GMT
I tried redshift query
SELECT FROM_UNIXTIME(x.timestamp) as x_date_time
FROM x
but didn't work.
Error occurred:
Invalid operation: function from_unixtime(character varying) does not exist
I also tried
SELECT DATE_FORMAT(x.timestamp, '%d/%m/%Y') as x_date
FROM x
Error occurred:
Invalid operation: function date_format(character varying, "unknown") does not exist
Is there any wrong with the syntax? Or is there another way to convert to human readable date and time?
Redshift doesn't have the from_unixtime() function. You'll need to use the below SQL query to get the timestamp. It just adds the number of seconds to epoch and return as timestamp.
select timestamp 'epoch' + your_timestamp_column * interval '1 second' AS your_column_alias
from your_table
UDF is going to be pretty slow. Checked execution time for 3 solutions and 1k rows.
The slowest -
-- using UDF from one of the answers
SELECT from_unixtime(column_with_time_in_ms/ 1000)
FROM table_name LIMIT 1000;
Execution time: 00:00:02.348062s
2nd best -
SELECT date_add('ms',column_with_time_in_ms,'1970-01-01')
FROM table_name LIMIT 1000;
Execution time: 00:00:01.112831s
And the fastest -
SELECT TIMESTAMP 'epoch' + column_with_time_in_ms/1000 *INTERVAL '1 second'
FROM table_name LIMIT 1000;
Execution time: 00:00:00.095102s
Execution time calculated from stl_query -
SELECT *
,endtime - starttime
FROM stl_query
WHERE querytxt ilike('%table_name%limit%')
ORDER BY starttime DESC;
The simplest solution is to create from_unixtime() function:
CREATE OR REPLACE FUNCTION from_unixtime(epoch BIGINT)
RETURNS TIMESTAMP AS
'import datetime
return datetime.datetime.fromtimestamp(epoch)
'
LANGUAGE plpythonu IMMUTABLE;
See Redshift documentation on UDF for details
For quick reference, here is the SQL UDF implementation of the from_unixtime function shown above in Python. I've not tested the performance but I imagine it would be similar to the plain SQL version. It's a whole lot easier to write though.
Note: this calculates the number of seconds from the epoch.
CREATE FUNCTION from_unixtime (BIGINT)
  RETURNS TIMESTAMP WITHOUT TIME ZONE
IMMUTABLE
as $$
  SELECT TIMESTAMP 'epoch' + $1 / 1000 * interval '1 second'
$$ LANGUAGE sql;
I used it like this
CAST(DATEADD(S, CONVERT(int,LEFT(column_name, 10)), '1970-01-01')as timestamp) as column_name
SELECT
,task_id
,CAST(DATEADD(S, CONVERT(int,LEFT(SLA, 10)), '1970-01-01')as timestamp) as SLA
FROM my_schema.my_task_table ;

Coversion of IST date format to Oracle sysdate format

How can I to convert from Indian standard time format to oracle date format.
Eg:
Mon May 23 2016 00:00:00 GMT+0530 (India Standard Time)
required format
23-May-16
This parses the input string and returns a date value to you:
select cast(to_timestamp_tz('Mon May 23 2016 00:00:00 GMT+0530', 'Dy Mon DD YYYY HH24:MI:SS "GMT"TZHTZM') as date) as converted_to_date_value
from dual;
This parses the input string to a "timestamp with time zone" value and formats the value back to a string in your desired format:
select to_char(to_timestamp_tz('Mon May 23 2016 00:00:00 GMT+0530', 'Dy Mon DD YYYY HH24:MI:SS "GMT"TZHTZM'), 'DD-Mon-RR') as converted_to_your_format
from dual;
Enjoy!
Footnote: Please note that there's no such thing as "oracle date format" which you refer to. Oracle has its date data type, which can have many many many different display intepretations depending on your client as well as server locale settings.

SQL Server 2008 R2 looking for a way to get the night hours for an employee

Using SQL Server 2008 R2 we are looking for a way to select the shift hours that an employee has that are during the night which in the this case 22.00 and 6.00 +1.
Our problem becomes how to get the hours when the shift crosses midnight or how we get the overlap when a shift begins 05.30 to 22.30 and has an overlap in both the beginning and end of the shift.
Here is an example, theses are the data available in the database and the result we are looking for:
startDateTime | endDateTime | nightHours
--------------------------+---------------------------+----------------
2012-07-04 05:00:00.000 2012-07-04 23:00:00.000 2
2012-07-04 18:00:00.000 2012-07-05 05:00:00.000 7
Does anyone have an example or a few good pointer that we can use.
This may be overly complex, but it does work. We use a number of CTEs to construct useful intermediate representations:
declare #Times table (
ID int not null,
StartTime datetime not null,
EndTime datetime not null
)
insert into #Times (ID,StartTime,EndTime)
select 1,'2012-07-04T05:00:00.000','2012-07-04T23:00:00.000' union all
select 2,'2012-07-04T18:00:00.000','2012-07-05T05:00:00.000'
;With Start as (
select MIN(DATEADD(day,DATEDIFF(day,0,StartTime),0)) as StartDay from #Times
), Ends as (
select MAX(EndTime) EndTime from #Times
), Nights as (
select DATEADD(hour,-2,StartDay) as NightStart,DATEADD(hour,6,StartDay) as NightEnd from Start
union all
select DATEADD(DAY,1,NightStart),DATEADD(DAY,1,NightEnd) from Nights n
inner join Ends e on n.NightStart < e.EndTime
), Overlaps as (
select
t.ID,
CASE WHEN n.NightStart > t.StartTime THEN n.NightStart ELSE t.StartTime END as StartPeriod,
CASE WHEN n.NightEnd < t.EndTime THEN n.NightEnd ELSE t.EndTime END as EndPeriod
from
#Times t
inner join
Nights n
on
t.EndTime > n.NightStart and
t.StartTime < n.NightEnd
), Totals as (
select ID,SUM(DATEDIFF(hour,StartPeriod,EndPeriod)) as TotalHours
from Overlaps
group by ID
)
select
*
from
#Times t
inner join
Totals tot
on
t.ID = tot.ID
Result:
ID StartTime EndTime ID TotalHours
----------- ----------------------- ----------------------- ----------- -----------
1 2012-07-04 05:00:00.000 2012-07-04 23:00:00.000 1 2
2 2012-07-04 18:00:00.000 2012-07-05 05:00:00.000 2 7
You'll note that I had to add an ID column in order to get my correlation to work.
The Start CTE finds the earliest applicable midnight. The End CTE finds the last time for which we need to find overlapping nights. Then, the recursive Nights CTE computes every night between those two points in time. We then join this back to the original table (in Overlaps) to find those periods in each night which apply. Finally, in Totals, we compute how many hours each overlapping period contributed.
This should work for multi-day events. You might want to change the Totals CTE to use minutes, or apply some other rounding functions, if you need to count partial hours.
I think, the best way would be a function that takes start time and end time of the shift. Then inside the function have 2 cases: first when shift starts and ends on the same day and another case when starts on one day and finishes on the next one.
For the case when it starts and finishes on the same day do
#TotalOvernightHours=0
#AMDifference = Datediff(hh, #shiftStart, #6amOnThatDay);
if #AMDIfference > 0 than #TotalOvernightHours = #TotalOvernightHours + #AMDifference
#PMDifference Datediff(hh, #10pmOnThatDay, #ShiftEnd)
if #PMDifference > 0 than #TotalOvernightHours = #TotalOvernightHours + #PMDifference
For the case when start and finish are on different days pretend it is 2 shifts: first starts at #ShiftStart, but finishes at midnight. Second one starts at midnight, finishes at #ShiftEnd. And for every shift do apply the logic above.
In case you have shifts that a longer than 24 hours, break them up into smaller sub-shifts, where midnight is a divider. So if you have shift starting on 1 Jun 19:00 and finishing at 3 Jun 5:00 then you would end up with three sub-shifts:
1 Jun 19:00 - 1 Jun 24:00
2 Jun 00:00 - 2 Jun 24:00
3 Jun 00:00 - 3 Jun 5:00
And for every sub-shift you do calculate the overnight hours.
I'd probably would write a function that calculates overnight hours for one 24hrs period and another function that breaks the whole shift into 24hrs chunks, then feeds it into the first function.
p.s. this is not sql, only pseudo-code.
p.p.s. This would work only if you have ability to create functions. And it would get you a clean, easy-to ready code.

SQLite ISO (ie European style) week numbers

I want to return ISO standard week numbers (ie week 1-52/53) from a date.
I have tried using the built in function strftime, but with no success.
Can anyone suggest a way without having to write a custom C or other function.
I know this is an old question, but recently I was looking for an efficient solution for the same problem, and this is what I came up with:
SELECT
my_date,
(strftime('%j', date(my_date, '-3 days', 'weekday 4')) - 1) / 7 + 1 as iso_week
FROM my_table;
The basic idea is to calculate the ISO week number by simply performing integer division of the day of year of the Thursday of the date being looked up (my_date) by 7, giving a result between 0 and 52, and then adding 1 to it. And the subtraction by 1 just before the division is there just for the alignment of the division: Thursday of week 1, for example, can have a day of year between 1 and 7, and we want the result of the division to be 0 in all cases, so we need to subtract 1 from the day of year before dividing it by 7.
What specifically did you try?
This works for me (using built-in SQLite from Python REPL):
import sqlite3
c = sqlite3.connect(':memory:')
c.execute('''create table t (c);''')
c.execute('''insert into t values ('2012-01-01');''')
c.execute('''select c, strftime('%W',c) from t;''').fetchone()
# -> (u'2012-01-01', u'00')
OK, so I managed to answer my own question. For anyone who might need a similar solution, this is what I came up with. Please note, I do not have an IT background and my SQL is self taught.
General process
Get the Thursday of the week the date belongs too.
Get the 4th of January of the year of that Thursday.
Get the Thursday of the week the 4th January date belongs too.
Subtract Step 2 with Step 3, divide by 7 and add 1.
Translated into SQLite....
SELECT
date,
CASE CAST (strftime('%w', wknumjanfourth) AS INTEGER)
WHEN 0 THEN ((JULIANDAY(datesThur) - JULIANDAY(strftime("%s", wknumjanfourth) - 259200, 'unixepoch')) / 7) + 1
ELSE ((JULIANDAY(datesThur) - JULIANDAY(DATE(strftime("%s", wknumjanfourth) - (86400 * (strftime('%w', wknumjanfourth) - 1)), 'unixepoch'), '+3 day')) / 7) + 1
END AS weeknum
FROM
(
SELECT
date,
datesThur,
DATE(datesThur,'start of year','+3 day') AS wknumjanfourth
FROM
(SELECT
date,
CASE CAST (strftime('%w', date) AS INTEGER)
WHEN 0 THEN DATE(strftime("%s", date) - 259200, 'unixepoch')
ELSE DATE(DATE(strftime("%s", date) - (86400 * (strftime('%w', date) - 1)), 'unixepoch'), '+3 day')
END AS datesThur
FROM TEST
))
If anyone can improve this SQL, I would appreciate the feedback.

Resources