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
Related
Morning Team,
I have an Oracle SQL script that is calculating from creation of an event and how many minutes old compared to the systimestamp.
I need to convert the minutes, which are coming out as 120 for 2 hour for example, into Hours:Minutes version, i.e. 2:00
I'm struggling with that part and would like to ask if someone could help? My current code for the calculation is:
(ROUND(((cast(systimestamp as date) - cast(n.createdttm as date)))*1440,0)) "Minutes old",
I'm sure it's something simple but with all my fiddling I am not able to get it.
Thank you
You can create an INTERVAL form the minutes.
select numtodsinterval(120, 'minute') from dual
Or create a datetime from the minutes and convert its time part to a string of hours and minutes.
select to_char(trunc(sysdate) + interval '1' minute * 120, 'hh24:mi') from dual
It looks like createdttm is a timestamp, so you can just subtract:
systimestamp - createdtm
... to get an interval value like +000000000 02:00:00.00000. You can't format that directly, but you can either extract the various elements and concatenate those back together, or treat it as a string and cut out the bits you want.
If you only want the time part and it will always be less than a day you can just do:
substr(systimestamp - createdtm, 12, 5)
02:00
But if it can go over 24 hours then you probably want the day part too, which you could still get just with substr (and maybe replace to change the space to another colon) if you know it can never be more than 2 days:
substr(systimestamp - createdtm, 10, 7)
0 02:00
That's unlikely to be a safe assumption though, so instead you could extract the number of days and concatenate that:
extract(day from (systimestamp - createdtm)) || ':' || substr(systimestamp - createdtm, 12, 5)
0:02:00
You could only show the number of days if it's non-zero, but that would probably be quite confusing to who/whatever is looking at the results; but if you really wanted to:
case when extract(day from (systimestamp - createdtm)) > 0
then extract(day from (systimestamp - createdtm)) || ':'
end || substr(systimestamp - createdtm, 12, 5)
02:00
db<>fiddle with a few sample values.
One thing to note is this effectively truncates the seconds off the time; your original attempt included round(), but that might not have been what you meant.
If u want to convert minutes to hours and minutes.
If x is the number of minutes (such as 350):
TO_CHAR ( FLOOR (x / 60)) || ':'
|| TO_CHAR ( MOD (x, 60)
, 'FM00'
)
If u want to convert hours and minutes to minutes.
SELECT (TRUNC (x) * 60) +
( (MOD (x, 1)
* 100
)
FROM dual;
where x is a NUMBER. If you have a sting, s, instead, use TO_NUMBER (s) in place of x.
I have two timestamp columns: arrTime and depTime.
I need to find the number of munites the bus is late.
I tried the following:
SELECT RouteDate, round((arrTime-depTime)*1440,2) time_difference
FROM ...
I get the following error: inconsistent datatype . expected number but got interval day to second
How can i parse the nuber of minutes?
If i simply subtract: SELECT RouteDate, arrTime-depTime)*1440 time_difference
The result is correct but not well formatted:
time_difference
+00000000 00:01:00 0000000
The result of timestamp arithmetic is an INTERVAL datatype. You have an INTERVAL DAY TO SECOND there...
If you want the number of minutes one way would be to use EXTRACT(), for instance:
select extract( minute from interval_difference )
+ extract( hour from interval_difference ) * 60
+ extract( day from interval_difference ) * 60 * 24
from ( select systimestamp - (systimestamp - 1) as interval_difference
from dual )
Alternatively you can use a trick with dates:
select sysdate + (interval_difference * 1440) - sysdate
from (select systimestamp - (systimestamp - 1) as interval_difference
from dual )
The "trick" version works because of the operator order of precedence and the differences between date and timestamp arithmetic.
Initially the operation looks like this:
date + ( interval * number ) - date
As mentioned in the documentation:
Oracle evaluates expressions inside parentheses before evaluating those outside.
So, the first operation performed it to multiply the interval by 1,440. An interval, i.e. a discrete period of time, multiplied by a number is another discrete period of time, see the documentation on datetime and interval arithmetic. So, the result of this operation is an interval, leaving us with:
date + interval - date
The plus operator takes precedence over the minus here. The reason for this could be that an interval minus a date is an invalid operation, but the documentation also implies that this is the case (doesn't come out and say it). So, the first operation performed is date + interval. A date plus an interval is a date. Leaving just
date - date
As per the documentation, this results in an integer representing the number of days. However, you multiplied the original interval by 1,440, so this now represented 1,440 times the amount of days it otherwise would have. You're then left with the number of seconds.
It's worth noting that:
When interval calculations return a datetime value, the result must be an actual datetime value or the database returns an error. For example, the next two statements return errors:
The "trick" method will fail, rarely but it will still fail. As ever it's best to do it properly.
SELECT (arrTime - depTime) * 1440 time_difference
FROM Schedule
WHERE ...
That will get you the time difference in minutes. Of course, you can do any rounding that you might need to to get whole minutes....
Casting to DATE first returns the difference as a number, at least with the version of Oracle I tried.
round((cast(arrTime as date) - cast(depTime as date))*1440)
You could use TO_CHAR then convert back to a number. I have never tested the performance compared to EXTRACT, but the statement works with two dates instead of an interval which fit my needs.
Seconds:
(to_char(arrTime,'J')-to_char(depTime,'J'))*86400+(to_char(arrTime,'SSSSS')-to_char(depTime,'SSSSS'))
Minutes:
round((to_char(arrTime,'J')-to_char(depTime,'J'))*1440+(to_char(arrTime,'SSSSS')-to_char(depTime,'SSSSS'))/60)
J is julian day and SSSSS is seconds in day. Together they give an absolute time in seconds.
A table has a time column in float datatype is given as:
40m
11m
2m
0m
3m
1m
1m
How can I sum these values to get it in hours and minutes?
You could use Gordon's answer, which directly leverages SQL Server's built in time ability. An alternative would be the "brute force" approach of computing the number of hours and minutes represented by the sum of your time column:
WITH cte AS (
-- strip off 'm' units and convert to numbers
SELECT CONVERT(int, REPLACE(time, 'm', '')) AS time
FROM yourTable
)
SELECT
CONVERT(varchar(10), FLOOR(SUM(time) / 60)) + ':' +
CONVERT(varchar(10), FLOOR(SUM(time) % 60)) AS timestamp
FROM cte;
Demo
The demo shows that the logic holds up even if the number of minutes in your column should exceed 24 hours.
You can use dateadd() and then cast the result back to a time:
select cast(dateadd(minute, sum(col), 0) as time)
from t;
Note: This only works up to 23:59:00. The SQL Server time type does not support larger values.
Here is a rextester.
I am getting and posting data between HubSpot and my database.
HubSpot hold DateTime as UNIX Milliseconds and I am having trouble getting the same value when converting too and from.
(I want to store it as DateTime in my database which is why I am converting between them)
Starting value from HubSpot: 1531316462651
--FROM UNIX Starting Value TO DATETIME (This seems fine and gives me the value I would expect)
SELECT DATEADD(S, 1533046489401 / 1000, '1970-01-01T00:00:00.000')
--TO UNIX Starting Value FROM DATETIME (This doesn't give me the starting value - need help)
SELECT CAST(DATEDIFF(S, '1970-01-01T00:00:00.000', '2018-07-31 14:14:49.000') AS BIGINT) * 1000
As you can see when converting to unix from datetime, it is a different value to what I started with. I might be missing something obvious from looking at this too long (SQL Blindness I call it). Hopefully a simple resolve for someone who has done this before.
Thanks in advance.
EDIT: So I changed the first select statement and second statement so it reads like this:
--FROM UNIX TO DATETIME
SELECT DATEADD(MILLISECOND, 1531316462651 % 1000, DATEADD(SECOND, 1531316462651 / 1000, '19700101'))
--TO UNIX FROM DATETIME
SELECT (CAST(DATEDIFF(day, '1970-01-01T00:00:00.000', '2018-07-11 13:41:02.650') AS BIGINT) * 24 * 60 * 60 * 1000 +
DATEDIFF(millisecond, CAST('2018-07-11 13:41:02.650' as DATE), '2018-07-11 13:41:02.650')
)
Both return ALMOST the same value (1 Millisecond out) and I believe that is because SQL datetime rounds milliseconds in 3. So my original value 651 gets rounded to 650 when going to a datetime. I don't know how I can resolve this in SQL if anyone can help?
Microsoft has recognized this problem and created a function to solve it, DATEDIFF_BIG(). This is available since version 2016.
Before that, you need to do more complex manipulations. I think this does what you want:
SELECT (CAST(DATEDIFF(day, '1970-01-01T00:00:00.000', '2018-07-31 14:14:49.000') AS BIGINT) * 24 * 60 * 60 * 1000 +
DATEDIFF(millisecond, CAST('2018-07-31 14:14:49.000' as DATE), '2018-07-31 14:14:49.000')
)
That is, extract the days, multiply, and then extract the milliseconds from today. A day has 86,400,400 milliseconds, so this easily fits in an integer.
To get your original value, you need milliseconds in your date/time:
SELECT (CAST(DATEDIFF(day, '1970-01-01T00:00:00.000', '2018-07-31 14:14:49.000') AS BIGINT) * 24 * 60 * 60 * 1000 +
DATEDIFF(millisecond, CAST('2018-07-31 14:14:49.401' as DATE), '2018-07-31 14:14:49.401')
)
How want to use the sum of the time(n) operator so that i can calculate the overall total of the time but Sql server saying can't add the Time(n) column
i have a casted column which contain difference of two dates, and being casted as Time(n) by me. Now i want to add those column to get how much time i had used in total How much hours minute and seconds so i apply
select Sum(cast ((date1-date2) as Time(0))) from ABC_tbl
where date1 is reaching time and date2 is startingtime in Date format and i want to total of all hours
Convert the time to an integer value before you sum it (for example, seconds):
SELECT SUM(
datediff(second, '00:00:00', [TimeCol])
)
FROM
...
Replace [TimeCol] with the name of the Time(n) column. This gives you the total time in seconds, which you can then easily convert to minutes, hours, etc...
Hope this example help you.
DECLARE #A TABLE (SD TIME(0),ED TIME(0))
INSERT INTO #A VALUES
('09:01:09','17:59:09'),
('09:08:09','16:10:09'),
('08:55:05','18:00:00')
SELECT SUM(DATEDIFF(MINUTE,SD,ED)) SUM_IN_MINUTES,
SUM(DATEDIFF(HOUR,SD,ED)) SUM_IN_HOURS
FROM #A
Result:
SUM_IN_MINUTES | SUM_IN_HOURS
---------------------------------------
1505 | 25
select Sum(DATEDIFF(Minute,date1,date2)) AS TIME from ABC_tbl
u have to calculate the date difference with DATEDIFF function then use SUM function to calculate your sum of time.
you can change Minute to Second-Hour-month etc..
Try this:
DECLARE
#MidnightTime TIME = '00:00:00.0000000',
#MidnightDateTime DATETIME2 = '0001-01-01 00:00:00.0000000';
SELECT SumOfTime = DATEADD(SECOND, SUM ( DATEDIFF(SECOND, #MidnightTime, x.Col1) ), #MidnightDateTime)
FROM (VALUES
(1, CONVERT(TIME, '10:10:10.0000001')),
(2, CONVERT(TIME, '00:00:05.0000002')),
(3, CONVERT(TIME, '23:59:59.0000003'))
) x(ID, Col1)
/*
SumOfTime
---------------------------
0001-01-02 10:10:14.0000000 = 1 day (!), 10 hours, 10 minutes, 14 seconds
*/
Note: instead of SECOND you could use another precision: MINUTE, HOUR or ... NANOSECOND (see section Arguments > datepart). Using a higher precision could leads to Arithmetic overflow errors (use CONVERT(BIGINT|NUMERIC(...,0), ...).
Note #2: because the precision is SECOND the result (SumOfTime) has 0000000 nanoseconds.