Any better way to convert timestamp (HH:mm:ss) to Seconds in Hive - sql

I have one hive field of type string which has timestamp in following format:
HH:mm:ss
mm:ss
ss
I need to convert them as below:
Input:
10:30:40
30:40
40
Output Expected:
10:30:40 = (10*3600) + (30 * 60) + 40 = 37,840
30:40 = (30 * 60) + 40 = 1840
40 = 40 = 40
I tried doing something like this
case
when duration like '%:%:%' then
split(duration, ':')[0] * 3600 +
split(duration, ':')[1] * 60 +
split(duration, ':')[2]
when duration like '%:%' then
split(duration, ':')[0] * 60 +
split(duration, ':')[1]
else
duration
end
This works but seems inefficient way. is there a better way to do the same when I have to process billions of records.

Your expressions will not create much additional load when executed in hive. You can simplify query a bit using unix_timestamp function, but it will run not faster.
with input as(--use your table instead of this
select stack(3, '10:30:40',
'30:40',
'40') as duration
)
select duration, case when duration like '%:%:%' then unix_timestamp(duration,'HH:mm:ss')
when duration like '%:%' then unix_timestamp(duration,'mm:ss')
else duration
end as result
from input
Result:
duration result
10:30:40 37840
30:40 1840
40 40
Or even simpler:
select duration, coalesce(unix_timestamp(duration,'HH:mm:ss'), unix_timestamp(duration,'mm:ss'), duration) as result
returns exactly the same.

Related

Convert duration string into seconds integer

I want to turn strings that represent durations into their duration in seconds as an integer.
All of the strings are formatted in the following way:
hh:mm:ss
I was working with substrings, which I cast to integers and then multiplied with 3600, 60 or 1 respectively and in the end summed everything up.
Just like this:
SELECT
cast(substr(time_string, 1, 2) as smallint) * 3600 + cast(substr(time_string, 4, 2) as smallint) * 60 + cast(substr(time_string, 7, 2) as smallint) as seconds
from table_name
As I have to do this for multiple fields, I would be interested in a better way to achieve this result. My search for a better solution, though, fell flat so far.
I would appreciate any input or help!
Try using date_parse, cast to time and use date_diff with required unit:
select date_diff(
'second',
time '00:00:00', -- zero time
cast(date_parse('12:10:56', '%T') as time)
) seconds
Output:
seconds
43856

How to format seconds as integer into HH:MM:SS in Presto

I have a table as:
id time_seconds
5 140
6 5
7 15000
I want to get it as:
id time_format
5 23:52
6 00:05
7 04:10:00
Basically format of HH:MM:SS
Now the thing is that I don't have many records with hours so the HH: should be in the output only if there are hours. Otherwise it should be just MM:SS
Presto has function that does similar thing
SELECT parse_duration('60s');
But the output isn't what I need
0 00:01:00.000
and I'm not sure this is the way to use it?
This is what I did so far:
select id, concat(cast(time_seconds as varchar(10)),'s')
from mytable
not sure how to continue
You can readily convert this to a time:
select time '00:00:00' + time_seconds * interval '1' second
I think that that is the best way to represent the value. Adding the hour conditionally seems like a bad idea -- it can lead to confusion.
I think the following will work on times:
select (case when time_seconds < 60 * 60
then date_format(time '00:00:00' + time_seconds * interval '1' second, '%i:%s')
else date_format(time '00:00:00' + time_seconds * interval '1' second, '%H:%i:%s')
end) as hhmmss
This is not a particularly elegant approach, but it'll produce the targeted output format.
Without dropping the potential '00:' hours portion:
select regexp_replace(concat(
cast(round(time_seconds/3600) as varchar),':',
cast(round((time_seconds%3600)/60) as varchar),':',
cast(round((time_seconds%3600)%60) as varchar)
),'(\d+)(:|\b)', match -> if(length(match)=1,'0'||match[1],match[1]) || match[2])
If '00:' hours must be dropped, then one could wrap the above in an additional: regexp_replace(<THE_INNER_RESULT>,'(^00:)(.*)','$2').
Note: This also doesn't satisfy the possible case of time_seconds>86400 (handling days) which #hkravitz points out in their comment.

Time stamp to something readable

I have this SQL Query that pulls exactly what I want but I am having trouble converting the time stamp to something readable.
Here is what the Database outputs:
The timestamp should be 8/21/19 1:56 PM
Here is the SQL Query I have right now:
Can someone help me with this? Thank you!
select MACHINE_ID as ZUM_TOOL_GROUP, LAST_VALUE as MISTI, LAST_TIMESTAMP
from machine_signal
where machine_id like 'WSI%' and signal_id = 'RT2_COUNT'
order by ZUM_TOOL_GROUP ASC
Updated Picture with the new code:
New Code:
select MACHINE_ID as ZUM_TOOL_GROUP, LAST_VALUE as MISTI,
(date '1970-01-01' + LAST_TIMESTAMP / (24 * 60 * 60 * 1000)) as time_date
from machine_signal
where machine_id like 'WSI%' and signal_id = 'RT2_COUNT'
order by ZUM_TOOL_GROUP ASC
The format works perfect but how do I get the timestamp correct? it should be 12:19 PM not 5:19PM
This looks a Unix timestamp in milliseconds. Here is a simple conversion:
select date '1970-01-01' + 1566402391000 / (24 * 60 * 60 * 1000)
from dual;
If you want this in a particular timezone, you should offset it by the appropriate amount.

ORACLE-SQL : how to calculate 2 time in number type?

I kept my Time data as number type (NUMBER(4,2)) and I want to calculate the column like below
2.15 (2:15 am.) - 1.45 (1:45 am)
***result***
0.30 (a half hour)
Please kindly explain me the method to calculate.
Try this one I hove it will work for u
select to_char(to_date(((to_date(to_char(09.15),'hh24.mi')-to_date(to_char(01.45),'hh24.mi'))*24*60*60),'sssss'),'hh24:mi') time from dual;
Try this code:
select (trunc(2.15)* 0.6 + (2.15 - trunc(2.15))) - (trunc(1.45)* 0.6 + (1.45 - trunc(1.45)))
as result
from YOUR_TABLE
Result: 0,30
Assuming you can get them into separate columns:
with mins_calc as
(
select (floor(mytime1) - floor(mytime2))*60 + (mod(mytime1,1)-mod(mytime2,1)) as tot_mins
from Mytable
)
select to_char(floor(tot_mins/60))||'.'||to_char(mod(tot_mins,60)) as time_diff_char
from mins_calc
Convert to hours:
select ( trunc(t1) + (t1 - trunc(t1)) * 60) -
trunc(t2) + (t2 - trunc(t2)) * 60)
) as hours
This converts the difference to fractional hours. I would advise you to leave it like that or convert to minutes.
You can convert your two 'times' to minutes; this uses bind variables to provide both numeric values as it isn't clear where you're actually getting them from:
var time_1 number;
var time_2 number;
exec :time_1 := 2.15;
exec :time_2 := 1.45;
select 60 * trunc(:time_1) + 100 * (:time_1 - trunc(:time_1)) as minutes_1,
60 * trunc(:time_2) + 100 * (:time_2 - trunc(:time_2)) as minutes_2,
(60 * trunc(:time_1) + 100 * (:time_1 - trunc(:time_1)))
- (60 * trunc(:time_2) + 100 * (:time_2 - trunc(:time_2))) as minutes_diff
from dual;
MINUTES_1 MINUTES_2 MINUTES_DIFF
---------- ---------- ------------
135 105 30
You can then convert the difference in minutes back to a number in the (odd) format you're using by reversing the calculation; this uses a second CTE to get the difference in minutes calculated above to simplify things and avoid repeating the long terms:
with diff (minutes) as (
select (60 * trunc(:time_1) + 100 * (:time_1 - trunc(:time_1)))
- (60 * trunc(:time_2) + 100 * (:time_2 - trunc(:time_2)))
from dual
)
select minutes,
trunc(minutes/60) + mod(minutes, 60) / 100 as minutes_as_number
from diff;
MINUTES MINUTES_AS_NUMBER
---------- -----------------
30 .3
DATEDIFF (Transact-SQL)
This function returns the count (as a signed integer value) of the specified datepart boundaries crossed between the specified startdate and enddate.
//You can return: second, minute, day, year. In your case is minute.
SELECT DATEDIFF(minute, '2018-08-03 02:15:00am', '2018-08-03 1:45:00am');
return value: -30
if you would like to get exact (30) converted in varchar use like that.
SELECT CONVERT(varchar, ABS(DATEDIFF(minute, '2018-08-03 02:15:00am', '2018-08-03 1:45:00am')));
First use ABS() to get the absolute number (removing the (-) minus signal) and convert to varchar using CONVERT().
source: https://learn.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-2017
ORACLE Version
SELECT TO_DATE('2000-01-02', 'YYYY-MM-DD') - TO_DATE('2000-01-01', 'YYYY-MM-DD') AS DateDiff FROM dual

Converting time to seconds then calculations based on this new field

I have a simple table with a number of fields but the only 3 that I'm interested in are below. I want to see if the time of the advert goes past 00:00 (midnight);
ID
start_advert_time
advert_duration
The problem is the above time fields are just text string. So a table would look like this.
ID start_advert_time advert_duration
---- ----------------- ---------------
1234 162438 0060
1235 235900 0080
This means;
ID 1234, time 16:24:38 and duration is 60 seconds
ID 1235, time 23:59:00 and duration is 80 seconds
As you can see the second row will go over the midnight range and this is the rows i want to pull out. I am stump how to do this but think I'm on the right lines
I wanted to convert the string to Time if possible. Then add the seconds to this which would create an "end time". How to do this I'm not sure.
SO 16:24:38 = 59078 seconds + 60 seconds duration = 59138, which in turn is 16:25:38
SO 23:59:00 = 86340 seconds + 80 seconds duration = 86420, which in turn is 00:00:20 <- over midnight and what I need
tl;dr
Assuming start_advert_time always contains exactly 6 characters, this should do what you want:
SELECT *
FROM YourTableNameHere
WHERE DateDiff("s", CDate(0), CDate(Format(start_advert_time, "00\:00\:00"))) + Val(advert_duration) > 86399
Here is an Immediate window session to explain how that works.
' first transform start_advert_time so that CDate() will accept it ...
start_advert_time = "162438"
? Format(start_advert_time, "00\:00\:00")
16:24:38
? CDate(Format(start_advert_time, "00\:00\:00"))
4:24:38 PM
' what is the total of seconds in a day at the last second before midnight?
? DateDiff("s", CDate(0), #23:59:59#)
86399
' how many seconds does start_advert_time represent?
? DateDiff("s", CDate(0), CDate(Format(start_advert_time, "00\:00\:00")))
59078
' and now how many seconds when you add advert_duration?
advert_duration = "0060"
? DateDiff("s", CDate(0), CDate(Format(start_advert_time, "00\:00\:00"))) + Val(advert_duration)
59158
' is that total seconds greater than 86399?
? DateDiff("s", CDate(0), CDate(Format(start_advert_time, "00\:00\:00"))) + Val(advert_duration) > 86399
False
' now do same for second row of sample data ...
start_advert_time = "235900"
advert_duration = "0080"
? DateDiff("s", CDate(0), CDate(Format(start_advert_time, "00\:00\:00"))) + Val(advert_duration) > 86399
True
CONVERTED TO ACCESS :
SELECT ID, start_advert_time, advert_duration
FROM Tabela1
WHERE (((CInt([advert_duration]))>(86400-DateDiff('s',#1/1/1999#,'1999-1-1 '+Mid([start_advert_time],1,2)+':'+Mid([start_advert_time],3,2)+':'+Mid([start_advert_time],5,2)))));
This should work (TSQL):
SELECT [ID]
,[start_advert_time]
,[advert_duration]
FROM Time where CAST(advert_duration as int) > (86400- DATEDIFF(ss, cast('00:00:00.0000000' as time), STUFF(Stuff([start_advert_time],3,0,':'), 6,0,':')))