This algorithm is pretty popular, but in some cases i do get some conflict with TimeUnit results.
long millis = 12884983;
System.out.println(((millis / (1000 * 60)) % 60));
System.out.println(java.util.concurrent.TimeUnit.MILLISECONDS.toMinutes(millis));
Prints:
34
214
First line is wrong:
System.out.println(((millis / (1000 * 60)) % 60));
and should be
System.out.println((millis / (1000 * 60)));
The mod operation cuts off your result. If you calculate 214 % 60 you get 34.
Related
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
I am trying to calculate the duration of a service where the times in the table are stored as Char(4) HHMM. For example, the start time is 1402, which would be 14:02, and the end time is 1536, which would be 15:36.
I need it to return a duration of 94 minutes. When I tried to just convert to numeric and subtract I get 134. I have tried to convert to time, but every example I have tried gives me a conversion type message.
Just convert the value to a time, and then use DATEDIFF:
SELECT DATEDIFF(MINUTE, CONVERT(time,STUFF(StartTime,3,0,':')),CONVERT(time,STUFF(EndTime,3,0,':')))
FROM dbo.YourTable;
You can use string functions and arithmetics:
select t.*,
(left(starttime, 2) * 60 + right(starttime, 2) - left(endtime, 2) * 60 - left(endtime)) / 60 minutes_diff
from mytable t
This converts the strings to a number of seconds, substracts the values, then converts back to minutes.
You can convert the difference to minutes and then add that back to a zero time:
select convert(time,
dateadd(minute,
(((et / 100) * 60) + (et % 60)) - (((st / 100) * 60) + (st % 60)),
0)
)
from (values (1402, 1536)) v(st, et);
Here is a db<>fiddle.
Thank you everyone for the answers, but I found my answer!
DateDiff(Minute, try_cast(substring(c.start_time, 1, 2) + ':' + substring(start_time, 3, 2) as time),
try_cast(substring(stop_time, 1, 2) + ':' + substring(c.stop_time, 3, 2) as time))
Task: given two parametes as char(4)
1402, 1536 in format HHMM
Return duration in minutes: 15*60+36 - 14*60+02 => 94
Solution:
SELECT (CAST(SUBSTRING('1536',1,2) AS int)*60 + CAST(SUBSTRING('1536',3,2) AS int))
- (CAST(SUBSTRING('1402',1,2) AS int)*60 + CAST(SUBSTRING('1402',3,2) AS int));
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.
I am using this query
SELECT
(date_trunc('hour', b.pub_ts) - DATE '1970-01-01')* 24 * 60 * 60 +
EXTRACT(SECOND FROM b.pub_ts),
date_trunc('hour', b.pub_ts)
from tablename b
limit 10;
ERROR: operator does not exist: interval + double precision
LINE 1: ...ur', b.pub_ts) - DATE '1970-01-01')* 24 * 60 * 60 + EXTRACT...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
After #Vao said i try the output is
the actual output should be
Because then i have to apply round on the decimal but it is coming in interval.
Like this
round (((date_trunc('hour', b.pub_ts) - DATE '1970-01-01')* 24 * 60 * 60) +
concat(EXTRACT(SECOND FROM b.pub_ts),' seconds')::interval,3)
instead of
+ EXTRACT(SECOND FROM b.pub_ts),
try
+concat(EXTRACT(SECOND FROM b.pub_ts),' seconds')::interval,
The idea behind is that seconds is the only part of interval (or timestamp) that can have decimals, so you need to explicitely define you add seconds with decimals - then it should accept it
The answer to question
> round((extract(epoch from ((date_trunc('hour', b.pub_ts) -
DATE '1970-01-01')* 24 * 60 * 60)) +
EXTRACT(SECOND FROM b.pub_ts))::numeric,3)
AND also if you want day to be extracted instead of eposh
(round((extract(DAY from((date_trunc('hour', b.pub_ts)
- DATE '1970-01-01')* 24 * 60 * 60)) +
EXTRACT(SECOND FROM b.pub_ts))::numeric,3) *1000 / 1000)
https://www.postgresql.org/message-id/3FCF7C40.2040505%40klaster.net
How to convert Minutes (integer) values in to Hours float (HH.MM) in SQL Server 2008.
for example 398 Minutes get converted into 6.38 Hours, 419 Minutes get converted into 6.59 hours etc.
Please try:
SELECT 398 / 60 + (398 % 60) / 100.0
SELECT 419 / 60 + (419 % 60) / 100.0
specific
SELECT CONVERT(NUMERIC(18, 2), 398 / 60 + (398 % 60) / 100.0)
SELECT CONVERT(NUMERIC(18, 2), 419 / 60 + (419 % 60) / 100.0)
The above mentioned method fails when a decimal number is given though i'm not sure whether your application needs a decimal value.
SELECT CONVERT(NUMERIC(18, 2), 90.90 / 60 + (90.90 % 60) / 100.0)
1.82
try
select dateadd(minute,398,0)