How to calculate hours from varchar2 fields? - sql

I have two varchar2 date fields like clock_in and clock_out. I am inserting datetime by sysdate so the date looks like this:
Clock_In Clock_Out
12-28-13 08:00 AM 12-28-13 05:00 PM
Now I want to calculate the no of hours he work. Can you please help in this matter?

You could just convert the data to dates using the to_date function, and then subtract the two values. Since subtracting dates returns a difference in days, you can simply multiply by 24 to get the difference in hours:
SELECT (TO_DATE(clock_out, 'DD-MM-YY HH:MI AM') -
TO_DATE(clock_in, 'DD-MM-YY HH:MI AM')) * 24 AS hours_worked
FROM my_table
EDIT:
An even better solution would probably be to save clock_in and clock_out as date fields to begin with and avoid the hassle of converting in the query, but I'm not sure this is possible for the OP.

Related

How to convert VARCHAR (AM/PM) to TIMESTAMP (24 h) in SQL (Teradata v17)

I've tried multiple solutions, but I keep getting errors. I need to create a new column casting VARCHAR to TIMESTAMP that includes AM, PM or -ideally- changes it to 24 hrs format.
VARCHAR format (Start_Date column): 8/3/2022 4:58:49 PM
I found the below solution is some other post, but I'm getting error: 'Format code appears twice'
SELECT itab.*,
TO_TIMESTAMP(Start_Date, 'MM/DD/YYYY HH:MM:SS AM') AS start_TS
FROM db.info_table itab
Please advise.
You have two problems.
MI is the format for minutes, MM is for months (you have it twice, this is why you are getting that error).
Your date/time string has single digit values for month, day, etc. You can use a pretty simple regex for that.
select to_timestamp(regexp_replace('8/3/2022 4:58:49 PM', '\b([0-9])\b', '0\1'), 'MM/DD/YYYY HH:mi:SS AM')
TO_TIMESTAMP returns a TIMESTAMP(6). If you don't want microseconds you can specify the precision using
CAST(RegExp_Replace(start_date, '\b([0-9])\b', '0\1') AS timestamp(0) FORMAT 'MM/DD/YYYYbHH:Mi:SSbT')
All you need is pad day and month in Teradata (as opposed to Oracle etc). m/d/y format has not been implemented.
select '8/3/2022 4:58:49 PM' date1,
to_timestamp(
lpad(strtok(date1,'/',1),2,'0')||'/'||lpad(strtok(date1,'/',2),2,'0')||'/'||strtok(date1,'/',3)
,'mm/dd/yyyy hh24:mi:ss AM'
);

Hours and minutes between 2 incorrectly formatted datetimes

So i have some timestamps in a DB and i want to get the hours and minutes difference from them
The problem is the timestamp portion is formatted incorrectly where the hour is always 12 and the minutes portion is actually the hours and the seconds is actually the minutes.
Example DB timestamp: 10/1/2020 12:08:52 AM
So in the above example the time is actually 8:52 AM not 12:08 AM
How can i convert this datetime to something i can use in order to calculate the difference in minutes and hours between these 2 oddly formatted timestamps?
My ideal end goal is something that displays the difference in the HH:MM format
EDIT: the timestamps in oracle actually look like below, and in this eaxmple the 12 means nothing and 18 is actually the hours.
Example of what I'm looking for:
01-OCT-20 12.18.44.000000000 AM - 01-OCT-20 12.12.42.000000000 AM
Output: 06:02 . so the timespan would be 6 hours and 2 minutes in this case.
Thanks,
You can turn your string to an Oracle date (resp timestamp) with to_date() (resp to_timestamp()):
to_timestamp(mystring, 'dd/mm/yyyy ss:hh12:mi am')
Then you can use date arithmetics to compute the difference. Substrating timestamps gives you an interval, which is pretty much what you seem to be looking for, so:
to_timestamp(mystring1, 'dd/mm/yyyy ss:hh12:mi am')
- to_timestamp(mystring2, 'dd/mm/yyyy ss:hh12:mi am')
as myinterval
Like so?
(my default date format is 'yyyy-mm-dd hh24:mi:ss' in Oracle ...)
WITH
indata(sdb) AS (
SELECT '10/1/2020 12:08:52 AM' FROM dual
UNION ALL SELECT '10/1/2020 12:08:52 PM' FROM dual
)
SELECT
TO_TIMESTAMP(sdb,'dd/mm/yyyy 12:hh:mi AM') AS ts
FROM indata;
-- out ts
-- out ---------------------
-- out 2020-01-10 08:52:00
-- out 2020-01-10 20:52:00

Using TO_DATE() with AM/PM Formatting

I am trying to select some dates from a table where the format of the dates is like this:
14-APR-14 10.35.00.0000000000 AM
01-NOV-16 02.43.00.0000000000 PM
Note that the dates can be either AM or PM, but when I try to do a simple SELECT from the table such as:
SELECT * FROM MyTable
WHERE TO_DATE(MyDate, 'DD-MON-YYYY HH:MI:SS AM') > '31-DEC-2016 08:00:00 AM';
I get the error:
ORA-01855: AM/A.M. or PM/P.M. required
I've been trying to get this work for some time but with no luck. Any help here would be appreciated.
Several problems.
Your inputs are obviously strings, since they have ten decimal places and timestamps in Oracle have at most 9. Then, strings with fractions of a second can't be converted to a date with to_date - you need to use to_timestamp or else you need to remove all the fractional parts. In the solution below I only remove the last (the tenth) decimal, since you may have non-zero fractional parts in the table - although not in the sample you posted.
Then, your format mask has yyyy but your inputs have only two digits for the year (which probably means 93 means 1993 and not 2093, so the correct thing to use would be rr rather than yy). And you use : in the format mask where your inputs use .
Finally, don't even compare dates in string format: in string comparisons, 01-JAN-2015 is before 20-NOV-2013.
You probably want something like this:
select mydate
from (
select '14-APR-14 10.35.00.0000000000 AM' as mydate from dual
union all
select '01-NOV-16 02.43.00.0000000000 PM' from dual
) mytable
where to_timestamp(substr(mydate, 1, 28) || substr(mydate, -3), 'dd-MON-rr hh.mi.ss.ff AM')
> to_timestamp('31-DEC-2016 08:00:00 AM', 'dd-MON-yyyy hh:mi:ss AM');
This query compiles correctly, and it produces no rows in the output (for obvious reasons).
NOTE: In a comment you (the OP) say the mydate field is a timestamp(6) datatype. Hard to believe (you show ten decimal places), but if indeed it is a timestamp or date, then you don't need to wrap it within any to_timestamp or to_date function, it should stand alone in the left-hand side of the inequality.
From your comment:
It's actually a timestamp; not a string. Timestamp(6) to be precise
You can just use a TIMESTAMP literal:
SELECT *
FROM MyTable
WHERE MyDate > TIMESTAMP '2016-12-31 08:00:00';

Convert 24 Hour time to 12 Hour plus AM/PM indication Oracle SQL

I am required to do the following as an exercise, and I am struggling to find a solution:
Write a SELECT statement that returns these columns from the Invoices table:
The invoice_date column
Use the TO_CHAR function to return the invoice_date column with its full date and time including a four-digit year on a 24-hour clock
Use the TO_CHAR function to return the invoice_date column with its full date and time including a four-digit year on a 12-hour clock with an am/pm indicator.
Use the CAST function to return the invoice_date column as VARCHAR2(10)
All I can get is:
select invoice_date, to_char(invoice_date, 'DD-MM-YYYY HH:MM:SS') "Date 24Hr"
from invoices
Which gets my first two columns, however I can't figure out any way to select the third column.
Any help would be great, thanks. (And yes, this is from my school textbook)
For the 24-hour time, you need to use HH24 instead of HH.
For the 12-hour time, the AM/PM indicator is written as A.M. (if you want periods in the result) or AM (if you don't). For example:
SELECT invoice_date,
TO_CHAR(invoice_date, 'DD-MM-YYYY HH24:MI:SS') "Date 24Hr",
TO_CHAR(invoice_date, 'DD-MM-YYYY HH:MI:SS AM') "Date 12Hr"
FROM invoices
;
For more information on the format models you can use with TO_CHAR on a date, see http://docs.oracle.com/cd/E16655_01/server.121/e17750/ch4datetime.htm#NLSPG004.
'hh' is for 12 hour format , 'HH' is for 24 format and 'tt' is for AM/PM
SELECT FORMAT(invoice_date, N'dd-MMM-yyyy hh:mm:ss tt')

Display correct subtraction of two timestamps in create view

By using normal minus '-' function between two timestamps, the answer given from oracle is incorrect.
This is what i want to do:
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='DD-MON-RR HH24:MI TZR';
Created table:
CREATE TABLE TEST (
StartTime timestamp with time zone
,EndTime timestamp with time zone
,Science varchar2(7)
);
I create the column data type as timestamp with time zone. This is value I have inserted:
INSERT INTO TEST
VALUES('05-OCT-2013 01:00 +08:00'
,'05-OCT-2013 23:00 +06:00'
,'SCIENCE');
INSERT INTO TEST
VALUES('05-OCT-2013 12:00 +08:00'
,'05-OCT-2013 15:00 -12:00'
,'Maths');
Attempted for rounding time:
CREATE VIEW TESTRECRDS AS
SELECT (Extract(hour FROM(ENDTIME- STARTTIME)) || 'Hours' ||
Extract(minute FROM(ENDTIME- STARTTIME))>=60 Then (Extract(hour FROM(ENDTIME- STARTTIME)) + Extract(minute FROM(ENDTIME- STARTTIME))/60 ELSE 0 END || 'Minutes' AS DURATION,
Science
FROM Test;
Now i have two questions regarding on the calculation and rounding off the minutes to nearest hours.
First let's say the endtime is 1535 +0600 and starttime is 01:50 +0800
So when i deduct endtime - starttime:
the formula should be:
2135 - 0950 = 2085 - 0950
= 1135
But if i use my successful attempt answer to calculate, it is not the correct exact answer. The oracle answer would be 15 hours 45 minutes.
In your last CREATE VIEW statement you try to multiply text, which cannot work:
SELECT To_Char(STARTTIME - ENDTIME, 'HH24:MI TZR')*24 AS DURATION
*24 is operating on the text to_char() returns.
You have to multiply the interval before converting to text.
You define the column Science varchar2(6), then you insert 'SCIENCE', a 7-letter word?
I also fixed a syntax error in your INSERT statement: missing '.
About your comment:
"I would like to insert timestamp with timezone during creation of my tables. Can DATE data type do that too?
Read about data types in the manual.
The data type date does not include time zone information.
If by "timezone difference" you mean the difference between the timezone modifiers, use this to calculate:
SELECT EXTRACT(timezone_hour FROM STARTTIME) AS tz_modifier FROM tbl
Keywords here are timezone_hour and is timezone_minute. Read more in the manual.
But be aware that these numbers depend on the daylight saving hours and such shenanigans. Very uncertain territory!
Get it in pretty format - example:
SELECT to_char((EXTRACT (timezone_hour FROM STARTTIME) * 60
+ EXTRACT (timezone_minutes FROM STARTTIME))
* interval '1 min', 'HH:MI')
In PostgreSQL you would have the simpler EXTRACT (timezone FROM STARTTIME), but I don't think Oracle supports that. Can't test now.
Here is a simple demo how you could round minutes to hours:
SELECT EXTRACT(hour FROM (ENDTIME - STARTTIME))
+ CASE WHEN EXTRACT(minute FROM (ENDTIME - STARTTIME)) >= 30 THEN 1 ELSE 0 END
FROM Test;
I'm not sure what number you're trying to calculate, but when you subtract two dates in Oracle, you get the difference between the dates in units of days, not a DATE datatype
SELECT TO_DATE('2011-01-01 09:00', 'yyyy-mm-dd hh24:mi') -
TO_DATE('2011-01-01 08:00', 'yyyy-mm-dd hh24:mi') AS diff
FROM dual
DIFF
----------
.041666667
In this case 8am and 9am are 0.41667 days apart. This is not a date object, this is a scalar number, so formatting it as HH24:MI doesn't make any sense.
To round you will need to do a bit of more math. Try something like:
TO_DATE(ROUND((ENDTIME - STARTTIME) * 96) / 96, 'HH24:MI')
The difference between dates is in days. Multiplying by 96 changes the measure to quarter hours. Round, then convert back to days, and format. It might be better to use a numeric format want to format, in which case you would divide by 4 instead of 96.
Timezone is not particularly relevant to a time difference. You will have to adjust the difference from UTC to that timezone to get the right result with Timezone included.