Hive/SQL Error when converting milliseconds to DDDD:HH:mm:ss - sql

I have an output in milliseconds that is too big to be described in HH:mm:ss format, I will need to expand to DDDD:HH:mm:ss.
The code I'm currently using only works on big numbers:
select from_unixtime(cast(floor(2513702864/1000) as bigint), 'DDDD:HH:mm:ss');
gives: 0030:02:15:02 , this is correct
select from_unixtime(cast(floor(17259/1000) as bigint), 'DDDD:HH:mm:ss');
gives: 0001:00:00:17 , this is not correct.
select from_unixtime(cast(floor(127259/1000) as bigint), 'DDDD:HH:mm:ss');
gives: 0001:00:02:07, this is also not correct.
How to fix the erroneous 1 in DDDD part when dealing with smaller milliseconds?

The logic is simple math. BIGINT timestamp is the number of seconds or milliseconds passed from Unix Epoch (1970-01-01 00:00:00 UTC).
To get milliseconds part use (ts % 1000) - returns reminder after division by 1000
To get total whole seconds passed, use (ts div 1000) - returns integer part, all other figures will be calculated from this number: days, hours, minutes, seconds.
days: (ts div 1000) div 86400 - returns integer part after division of total seconds by number of seconds in a day
To get hours left after whole days calculation: take reminder after days calculation ((ts div 1000) % 86400) and divide by number of seconds in hour, take integer part (((ts div 1000) % 86400) div 3600)
And so on.
Demo:
with your_data as (
select 1 id, bigint(2513702864) ts union all
select 2, bigint(17259) union all
select 3,bigint(127259) union all
select 4,bigint(1272) union all
select 5,bigint(127)
)
select --format output as required. For example days:hours:minutes:seconds.millis
concat(days,':',hours,':',minutes,':',seconds,'.',millis)
from
(
select ((ts div 1000) div 86400) days, --number of whole days
lpad(((ts div 1000) % 86400) div 3600, 2, 0) hours, --whole hours left
lpad((((ts div 1000) % 86400) % 3600) div 60, 2, 0) minutes, --whole minutes left
lpad((((ts div 1000) % 86400) % 3600) % 60, 2, 0) seconds, --seconds left
(ts % 1000) as millis
from your_data
)s
Result:
1 29:02:15:02.864 --29 whole days, 2 hours, 15 minutes, 2 seconds, 864 millis
2 0:00:00:17.259 --17 whole seconds and 259 millis
3 0:00:02:07.259 --two whole minutes, 7 seconds and 259 millis
4 0:00:00:01.272 --one whole second and millis
5 0:00:00:00.127 --we have only milliseconds
Now you can see the difference between this calculation and what from_unixtime returns.
For record id=1 the number of whole days is 29. Why from_unixtime returns 30 (for pattern 'D')? Because 29 whole days passed and we are 2 hrs 15 min 2 sec 864 mi in a new day 30. In other words, from_unixtime returns timestamp formatted and calculation in my query returns interval formatted, "day in a year" and "whole days passed from" are different things.
Hope, now it is as clear as a day.
See also similar question: https://stackoverflow.com/a/57497316/2700344
And if you need to convert bigint timestamp in milliseconds to string with milliseconds preserved (yyyy-MM-dd HH:mm:ss.SSS) use this:
select concat(from_unixtime(ts div 1000), '.', (ts % 1000)) as timestamp_with_millis
from (select bigint(2513702864) as ts) s
Result:
1970-01-30 02:15:02.864

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

Convert seconds to days, hours, minutes in Bigquery

i'm having trouble in converting seconds in Bigquery, is there any function to convert seconds to hour:minute:second format in Bigquery? i already tried the TIMESTAMP_SECONDS() function but it also returns some date and i can't use it if the hour more than 23.
for example:
second= 100000
result= 27:46:40
or maybe as 1 day 3 hour 46 minute 40 second
and i also want it in timestamp datatype so i can order it ascending or descending.
Below is for BigQuery Standard SQL
#standardSQL
select seconds,
regexp_replace(
cast(time(ts) as string),
r'^\d\d',
cast(extract(hour from time(ts)) + 24 * unix_date(date(ts)) as string)
) as option1,
format(
'%i day %i hour %i minute %i second',
unix_date(date(ts)),
extract(hour from time(ts)),
extract(minute from time(ts)),
extract(second from time(ts))
) as option2
from `project.dataset.table`,
unnest([timestamp_seconds(seconds)]) ts
if to apply to sample data from your question as in
with `project.dataset.table` AS (
select 100000 seconds union all
select 200000 union all
select 300000
)
the output is
With recently introduced INTERVAL data type and respective functions - such conversion becomes much easier
select seconds,
make_interval(second => seconds) result,
justify_interval(make_interval(second => seconds)) normalized_result
from `project.dataset.table`
with output like

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

convert date_time to specific decimal place

How do I convert the seconds in this date part so that it display it the all seconds as 0.047 rather than 0.047777777777777 or 0.333 instead of 0.33333333322?
Code below:
((DATE_PART('day', completed_at::timestamp - created_at::timestamp) * 24 +
DATE_PART('hour', completed_at::timestamp -created_at::timestamp)) * 60 +
DATE_PART('minute', completed_at::timestamp - created_at::timestamp)) * 60 +
DATE_PART('second', completed_at::timestamp -created_at::timestamp) As Duration
You can use the ROUND function http://www.w3schools.com/sql/sql_func_round.asp
You use it like that :
ROUND(column_name,decimals)
In your example (if you want 3 decimals after the comma):
SELECT ROUND(...,3) AS Duration FROM yourTable
(replace ... with the part of your query that outputs 0.047777777777777
The solution is to use timestamp(0) which defines the precision instead of timestamp - or in your case timestamp(3)
"time, timestamp, and interval accept an optional precision value p which specifies the number of fractional digits retained in the seconds field. By default, there is no explicit bound on precision. The allowed range of p is from 0 to 6 for the timestamp and interval types.
"
https://www.postgresql.org/docs/9.0/static/datatype-datetime.html

Teradara: Casting Seconds to Hours, Minutes and Seconds

I need to cast a Duration, measured in seconds, Decimal(18,0) to Hours, Minutes and Seconds.
e.g.:
8192 Seconds => 2:16:32 (Hours:Minutes:Seconds)
I've found (here) that I can do this if the seconds are a literal string, like this:
SELECT CAST(INTERVAL '8192' SECOND AS INTERVAL HOUR TO SECOND)
But when I try:
SELECT Event_Id
, CAST(INTERVAL Duration SECOND AS INTERVAL HOUR TO SECOND)
FROM EVENT_TABLE
WHERE <some conditions>
Event_Id and Duration are both declared Decimal(18,0) in the table EVENT_TABLE
Teradata complains:
[Error 3707] Syntax error, expected something like a string or Unicode character literal between the 'INTERVAL' keyword and the integer 8
What is the correct syntax or approach to use here?
SOLUTION: based on BellevueBob's post
SELECT Event_Id
, CAST(
Duration SECOND * INTERVAL '0000:01' MINUTE TO SECOND /* 1 */
AS INTERVAL HOUR TO SECOND /* 2 */
)
FROM EVENT_TABLE
WHERE <some conditions>
Explanation:
Multiply the known duration in seconds with an interval of one second length
convert the resulting intervall of seconds into an interval of hours, minutes and seconds.
From the same solution you found, try this:
select CAST(duration * INTERVAL '0000:01' MINUTE TO SECOND
AS INTERVAL HOUR TO SECOND)
from (
select cast(8192 as decimal(18,0)) as duration
) x