I have a requirement such that if I enter a timestamp(yyyy-mm-dd hh:mm:ss) say
2015-04-05 16:45:12
I need it converted to
2015-04-05 16:00:00
Is there an elegant way to do this in Teradata rather than extracting hour and then casting it with date?
Instead of casting from/to a string two times it's probably more efficient to substract intervals:
ts - (EXTRACT(MINUTE FROM ts) * INTERVAL '01' MINUTE)
- (EXTRACT(SECOND FROM ts) * INTERVAL '01' SECOND)
If this is to much code simply put it in a SQL UDF.
One way is to extract the substr you want to retain the values, and then concatenate the zeros for minutes and seconds.
For example,
SELECT concat(substr('2015-04-05 16:45:12', 1, 14), '00:00');
If you want, you could convert this back to timestamp, thus you will have the new timestamp value with the minutes and seconds value set to zero.
Related
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.
I have a database that contains a series of events and their timestamp.
I find myself needing to select all events that happen between 11:00 and 11:10 and 21:00 and 21:05, for all days.
So what I would do is I extract from timestamp the hour and the minute, and:
SELECT *
WHERE (hour = 11 AND minute <= 10)
OR (hour = 21 AND minute <= 05)
However, I was wondering if there's a simpler / less verbose way to do this, such as when you query between dates:
SELECT *
WHERE date BETWEEN '2020-07-01' AND '2020-07-05'
I read here that this is doable in SQLite, I was wondering if it's possible to be done in presto as well. I've looked at the docs but couldn't find an analogue function that does what time() does in SQLite.
You could use date formatting functions, e.g. date_format, then string comparisons:
select *
from mytable
where
date_format(mydate, '%H:%i') between '11:00' and '11:09'
or date_format(mydate, '%H:%i') between '21:00' and '21:04'
Note that I substracted one minute from the upper bound, since I assume you don't want to include the last minute. between '11:00' and '11:09' gives you everything from 11:00:00 to 11:09:59.
I have two fields dateTS and closingTime.
dateTS is a normal timestamp field (e.g. 2019-07-13 22:31:10.000000)
closingTime is a HH:MM format of when a store closes (e.g. 23:00)
I need a PostgreSQL query to subtract the two field and get the number of minutes difference between them.
Using the examples given above the difference between the two fields would be 28 minutes
So far I've tried different variations of the datediff function, but it won't work.
My guess is I either have to
a. generate a fake timestamp for closingTime which is the same day as the dateTs field and subtract the 2 timestamps.
or
b. convert the hour/minutes of both field to a float and subtract the two values to get the hours difference and convert that to minutes
You can just subtract them by converting the timestamp to a time:
select closingtime - datets::time
from your_table;
That will give you an interval as the result.
To convert that to minutes you can get the number of seconds and divide it by 60:
select (extract epoch from closingtime - datets::time) / 60
from your_table;
Cast your closing time to an interval and the timestamp to time and then subtract the two. By casting the timestamp to time you are effectively discarding the date part. You can the subtract one from the other to generate the difference as an interval.
select closingTime::interval - dateTS::time...
e.g.:
# select '23:00'::interval - now()::time;
?column?
-----------------
05:31:00.031141
(1 row)
If needed you can then convert the interval to minutes:
# select extract(epoch from ('23:00'::interval - now()::time)) / 60;
?column?
------------------
327.435313083333
(1 row)
I need to substract 2 timestamps in the given format:
16/01/17 07:01:06,165000000
16/01/17 07:01:06,244000000
I want to express the result with 2 decimal values but somewhere in the CAST process I am loosing precision. My atempt by now goes this way:
select
id,
trunc((CAST(MAX(T.TIMESTAMP) AS DATE) - CAST(MIN(T.TIMESTAMP) AS DATE))*24*60*60,2) as result
from table T
group by id;
But I get id_1 '0' as a result for the two timestamps above even after I set the truncate decimals at 2.
Is there a way that I can obtain the 0.XX aa a result of the substraction?
It's because you are casting the timestamp to date.
Use to_timestamp to convert your string into timestamp.
Try this:
with your_table(tstamp) as (
select '16/01/17 07:01:06,165000000' from dual union all
select '16/01/17 07:01:06,244000000' from dual
),
your_table_casted as (
select to_timestamp(tstamp,'dd/mm/yy hh24:mi:ss,ff') tstamp from your_table
)
select trunc(sysdate + (max(tstamp) - min(tstamp)) * 86400 - sysdate, 2) diff
from your_table_casted;
The difference between two timestamps is INTERVAL DAY TO SECOND.
To convert it into seconds, use the above trick.
DATE—This datatype stores a date and a time, resolved to the second. It does not include the time zone. DATE is the oldest and most commonly used datatype for working with dates in Oracle applications.
TIMESTAMP—Time stamps are similar to dates, but with these two key distinctions: you can store and manipulate times resolved to the nearest billionth of a second (9 decimal places of precision), and you can associate a time zone with a time stamp, and Oracle Database will take that time zone into account when manipulating the time stamp.
The result of a substraction of two timestamps is an INTERVAL:
INTERVAL—Whereas DATE and TIMESTAMP record a specific point in time, INTERVAL records and computes a time duration. You can specify an interval in terms of years and months, or days and seconds.
You can find more information here
PreparedStatement psnmt=con.prepareStatement("SELECT (?)-(?) as DiffDate FROM dual");
psnmt.setTimestamp(1,ctenderdate);
psnmt.setTimestamp(2,btenderdate);
ResultSet resrt=psnmt.executeQuery();
if(!resrt.next())
{
out.println("No Records Found");
}
else
{
do
{
datediff=resrt.getString("DiffDate");
}
while(resrt.next());
System.out.println("the no of days Difference"+datediff);
}
ctenderdate=2015-06-27 00:00:00.0
btenderdate=2015-06-29 00:00:00.0
datediff=1 10:18:51.940000000
Expected datediff=2
How to round it off datediff to number of days
EDIT
Subtract TIMESTAMP values
If we really want to subtract two TIMESTAMP values, then we have to work with the INTERVAL DAY TO SECOND datatype that's returned. The easiest way to work with that is to use the EXTRACT function.
If want to return integer number of days (emulating the CEIL function) then we could test whether any part of the time (HOUR, MINUTE, SECOND) was non-zero. If they are all zero, we can use just the DAY portion. Otherwise, we have to add 1 to the DAY portion, and return that.
For example:
SELECT EXTRACT(DAY FROM diff.idts)
+ CASE
WHEN EXTRACT(HOUR FROM diff.idts) > 0
OR EXTRACT(MINUTE FROM diff.idts) > 0
OR EXTRACT(SECOND FROM diff.idts) > 0
THEN 1
ELSE 0
END
AS days_diff
FROM ( SELECT ? - ? AS idts FROM dual ) diff
ORIGINAL ANSWER
For Oracle database, you can perform this operation in the database:
SELECT CEIL(TO_DATE(?,'YYYY-MM-DD HH24:MI:SS.F')-TO_DATE(?,'YYYY-MM-DD HH24:MI:SS.F'))
FROM dual
This assumes the bind parameters are passed as strings, in format that matches the format model specified in the TO_DATE function, for example:
'2015-06-27 14:45:21.0'
(I'm assuming Oracle because of the use of the dual table, and because you are using subtraction operation between two dates. You would need a different statement for a different database.)
To unpack that expression a little bit...
The Oracle TO_DATE function converts a character string into an Oracle DATE value. The second argument is the format model, specifies that format of the first argument.
A subtraction operation between two DATE values returns the difference as a number of days (integer days plus fractional days.)
The CEIL function rounds a non-integer value up to the next higher integer.
FOLLOWUP
Q: how to use it with timestamp?
A: A subtraction of two TIMESTAMP values gets returned as an INTERVAL DAY TO SECOND datatype. And I'd prefer to avoid working with that.
In Oracle, when we do a subtraction of two DATE values, we get a decimal number. That's much easier to work with.
And in terms of "rounding" up a difference in days, I'm fine with disregarding fractional seconds.
If I had to pass in TIMESTAMP values, I would convert them to DATE values. The expressions above are already expecting string values, so I would just replace the ? with
TO_CHAR(?,'YYYY-MM-DD HH24:MI:SS')
If I had a requirement to pass in TIMESTAMP datatype, and return integer days difference rounded up, I would use a query like this:
SELECT CEIL( TO_DATE(TO_CHAR( ? ,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
- TO_DATE(TO_CHAR( ? ,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
) AS days_diff
FROM dual
Check out this link. There are answers for results in hours or minutes. What you are looking for should be similar.
My bad. I should not post just-a-link-answers. What you can do, as described there is:
SELECT TRUNC (SYSDATE) - TO_DATE ('10/20/2012', 'mm/dd/yyyy') FROM DUAL;
Notice the following details:
ENDDATE - STARTDATE will give you a number that corresponds to the
number of days between the two dates.
If you want the result in hours, multiply by 24; if minutes, multiply
by 24*60 and so forth.
You can also convert the result to an INTERVAL. There are two type of
intervals: NUMTODSINTERVAL(ENDDATE - STARTDATE, 'DAY') or
NUMTOYMINTERVAL(ENDDATE - STARTDATE, 'DAY')