I am trying to add seconds to an existing date to find the end time. I have start time in one field and total duration in one field , i find in internet that we can add number to date but we should to dived on 86400
(chargestarttime + (NVL (callduration, 0) / 86400))
// where chargestarttime is date , callduration is number
// sample (chargestarttime is 2020-05-30 02:21:58 and callduration is 65 the output is 2020-05-30 02:23:03)
my question is why we need to div on 86400 ? if I convert the date to UNIX_TIMESTAMP and then add just the 65 it will give the same result without div on 86400 (24 hours) or there are a reason that we div on 86400 (24 hours)
why we need to div on 86400?
In date arithmetics, Oracle uses 1 to represent 1 day. If you start from a number of seconds, you need to convert that to days, so
chargestarttime + NVL(callduration, 0) / 60 / 60 / 24
-- seconds per minutes-----^
-- minutes per hour -----^
-- hours per day -----^
86400 is just the number of seconds there is in a day.
Your query is adding seconds as a fraction of a whole day (i.e. 1 day = 24 hours = 1440 minutes = 86400 seconds).
Alternatively, you could add seconds directly to the date using an INTERVAL data type:
chargestarttime + NVL(callduration, 0) * INTERVAL '1' SECOND
or
chargestarttime + NUMTODSINTERVAL( NVL(callduration, 0), 'SECOND' )
Related
For instance:
WITH
CTE_DATE_RANGE AS (
SELECT
*
FROM
UNNEST(GENERATE_DATE_ARRAY(CURRENT_DATE()-20, CURRENT_DATE())) as date
)
select
*
FROM
CTE_DATE_RANGE
gives me a date range for the last 20 days.
But I want this data at a minute level for the last x number of days.
How to generate a minute level time range for last 10 days in BigQuery?
You might consider using GENERATE_TIMESTAMP_ARRAY function.
SELECT *
FROM UNNEST(GENERATE_TIMESTAMP_ARRAY(
TIMESTAMP(CURRENT_DATE - 9),
TIMESTAMP_TRUNC(TIMESTAMP(CURRENT_DATE + 1), DAY) - INTERVAL 1 MINUTE,
INTERVAL 1 MINUTE
)) AS date_time;
output will be from 2022-11-28 00:00:00 UTC to 2022-12-07 23:59:00 UTC for last 10 days including today.
I'm writing a query to group rows by their timestamps into aggregation blocks. The query parameters include the start time start of the first aggregation block and a positive integer period which is the length of each and every aggregation block in minutes. Given a row's timestamp row_stamp, which is later than start, I want to calculate its block_start such that
block_start <= row_stamp < block_start + period minutes, and
block_start = start + (N * period minutes) where N is a nonnegative integer
It's easy enough to find row_stamp - start, which appears to be an interval. I figure I'll want block_start to be either start + (period minutes) * FLOOR((row_stamp - start) / (period minutes)) or row_stamp - MOD(row_stamp - start, period minutes). I know neither of these is exact syntax, but I think you see the algorithms I'm going for. Unfortunately, it looks like neither FLOOR nor MOD works well with an interval as its first parameter. What's the recommended way to turn an interval into a number of minutes and then, after the math, turn it back to an interval again?
My apologies for not mentioning earlier that I'm looking for the number of rows in each aggregation block. Edited to add an example.
CREATE TABLE "DEV_JKNIGHT" ( "ROW_STAMP" TIMESTAMP (6) NOT NULL );
insert into dev_jknight values (TIMESTAMP '2022-06-27 14:27:00');
insert into dev_jknight values (TIMESTAMP '2022-06-27 14:32:00');
insert into dev_jknight values (TIMESTAMP '2022-06-27 14:33:00');
insert into dev_jknight values (TIMESTAMP '2022-06-27 15:01:00');
insert into dev_jknight values (TIMESTAMP '2022-06-27 16:32:00');
Suppose the query parameters are a start time of '2022-06-27 14:15:00' and a period of 15 minutes. Then the aggregation blocks are as follows. The first begins at the specified start time and lasts for the period number of minutes. The next block starts immediately after the first one ends and lasts the same length.
14:15:00 - 14:30:00, June 27
14:30:00 - 14:45:00, June 27
14:45:00 - 15:00:00, June 27
15:00:00 - 15:15:00, June 27
and so on
If I run the query with those parameters, then I'm looking for these four rows of output.
Block start = '2022-06-27 14:15:00', count = "1"
Block start = '2022-06-27 14:30:00', count = "2"
Block start = '2022-06-27 15:00:00', count = "1"
Block start = '2022-06-27 16:30:00', count = "1"
The first row of output indicates that there is one, and only one, dev_jknight row in the aggregation block which starts at 14:15:00 -- namely, the row at 14:27:00.
The second row of output indicates that there are two dev_jknight rows in the aggregation block which starts at 14:30:00 -- the rows at 14:32 and 14:33.
Because there are zero dev_jknight rows in the third aggregation block (14:45 - 15:00), there is no output row for it.
The last two rows of output indicate that there is one dev_jknight rows in the aggregation block which starts at 15:00 and one in the block which starts at 16:30.
Thank you for your patience while I clarified this.
Turn an interval into a number of minutes?
Use EXTRACT:
SELECT EXTRACT(DAY FROM value) * 24 * 60
+ EXTRACT(HOUR FROM value) * 60
+ EXTRACT(MINUTE FROM value)
+ EXTRACT(SECOND FROM value) / 60 AS minutes
FROM (
SELECT INTERVAL '1 12:34:56.789' DAY TO SECOND AS value
FROM DUAL
);
Which outputs:
MINUTES
2194.946483333333333333333333333333333333
and then turn it back to an interval again?
Multiply a 1 minute interval by the number of minutes:
SELECT INTERVAL '1' MINUTE * 2194.94648333333 AS interval_value
FROM DUAL;
or, use the NUMTODSINTERVAL function:
SELECT NUMTODSINTERVAL(2194.94648333333, 'MINUTE') AS interval_value FROM DUAL;
INTERVAL_VALUE
+000000001 12:34:56.789000000
db<>fiddle here
So i am putting the sql code in that i have shown below and my output that i get from the ProcessEnd minus ProcessStart is the duration time which comes out as "0 0:0:8.135". However, i need it to only show in terms of minutes, i don't want the hours or seconds, just the minutes the process runs.
TO_CHAR(rh.PROCESSSTART,'DD-MM-YYYY HH24:MI:SS') AS "PROCESSSTART",
TO_CHAR(rh.PROCESSEND,'DD-MM-YYYY HH24:MI:SS') AS "PROCESSEND",
(rh.PROCESSEND - rh.PROCESSSTART) AS "DURATION",
"0 0:0:8.135"
It looks that PROCESSEND and PROCESSSTART are DATEs.
If so, subtracting them results in number of days.
In order to get number of minutes, you'll have to multiply number of days by
24, as there are 24 hours in a day
60, as there are 60 minutes in an hour
so the final result would be
(rh.processend - rh.processstart) * 24 * 60 as number_of_minutes
I've got some code that generates hours between an oldest record in the table (MIN) and getdate(), and am using
CONVERT(CHAR(8),DATEADD(SECOND,DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()),0),108)
to get the HH:MM:SS, but when the hours is more than 24 hours it just shows the hours part. i.e. 30 hours difference shows as 6 hours... how do I get it to show dd.hh:mm:ss i.e. 1.06:00:00
watch out for the case where the 'time' in the start day has not been reached in the end date
select cast(DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()) / 86400 as varchar(4)) + '.' + CONVERT(CHAR(8),DATEADD(SECOND,DATEDIFF(SECOND,MIN(OLDESTRECORD),GETDATE()) % 86400 ,0),108)
I am creating a query that shows me the time elapsed between two dates, only taking into account only the one that is Monday through Friday from 08:00 to 17:00, for example:
For example, if a petition opens on day 1 at 6:30 p.m. and closes on day 2 at 8:45 p.m., the TMO is 45 minutes.
If it closes on day 3 at 8:45, the TMO is 9 hours and 45 minutes.
Example 2:
If a petition opens on Friday at 16:45 and closes on Tuesday at 8:30, the MTO would be: 15 minutes on Friday, nine hours on Monday and 30 minutes on Tuesday for an MTO = 9 hours 45 minutes
The query is performed on a single column of type date as I show below
I currently use a LAG function to make the query, but I can not create something functional, not even optimal to incorporate, I would greatly appreciate your help.
In the solution below I will ignore the "lag" part of your problem, which you said you know how to use. I am only showing how to count "working hours" between any two date_times (they may be during or before or after work hours, and/or they can be on weekend days; the computation is the same in all cases).
Explaining the answer in words: For two given date-times, "start" and "end", calculate how many "work" hours elapsed from the beginning of the week (from Monday 00:00:00) till each of them. This is in fact a calculation for ONE date, not for TWO dates. Then: given "start" and "end", calculate this number of hours for each of them; subtract the "end" number of hours from the "start" number of hours. To the result, add x times 5 times 9, where x is the difference in weeks between Monday 00:00:00 of the two dates. (If they are in the same week, the difference will be 0.)
To truncate a date to the beginning of the day, we use TRUNC(dt). To truncate to the beginning of Monday, TRUNC(dt, 'iw').
To compute how many "work" hours are from the beginning of the date dt until the actual time-of-day we can use the calculation
greatest(0, least(17/24, dt - trunc(dt)) - 8/24)
(the results will be in days; we calculate everything in days and then we can convert to hours). However, in the final formula we must check to see if the date is a Saturday or Sunday, in which case this should just be zero. Or, better, we can adjust the calculation a bit later, when we count from the beginning of Monday (we can use least( 5*9/24, ...)).
Putting everything together:
with
inputs ( dt1, dt2 ) as (
select to_date('2017-09-25 11:30:00', 'yyyy-mm-dd hh24:mi:ss'),
to_date('2017-10-01 22:45:00', 'yyyy-mm-dd hh24:mi:ss')
from dual
)
-- End of SIMULATED input dates (for testing only).
select 24 *
( least(5 * (17 - 8) / 24, greatest(0, least(17/24, dt2 - trunc(dt2)) - 8/24)
+ (17 - 8) / 24 * (trunc(dt2) - trunc(dt2, 'iw')))
-
least(5 * (17 - 8) / 24, greatest(0, least(17/24, dt1 - trunc(dt1)) - 8/24)
+ (17 - 8) / 24 * (trunc(dt1) - trunc(dt1, 'iw')))
+ 5 * (17 - 8) / 24 * (trunc(dt2, 'iw') - trunc(dt1, 'iw')) / 7
)
as duration_in_hours
from inputs
;
DURATION_IN_HOURS
-----------------
41.500