Identify date format in PLSQL - sql

I'm trying to write a plsql stored procedure which identifies any date format and converts it into single datetime format 'mm/dd/yyyy hh:mi:ss'. How do I do it. I tried using case statment but there are so many date combinations that its not possible to write case statment for all of them.
For ex: 27-Oct-1967, October 27 1967 11:15:45, 1967-OCT-27, etc.
How do I convert all these to single format.
Thank you.

Simply to_char() will do,
select to_char(yourDateField,'mm/dd/yyyy hh:mi:ss') from dual;

Maybe this can help you:
CREATE TABLE temp_date
AS
SELECT '1967-OCT-27' some_date
FROM dual
UNION
SELECT '27-Oct-1967' FROM dual
UNION
SELECT 'October 27 1967 11:15:45' FROM dual
/
Declare
CURSOR i_cur IS
Select some_date
From temp_date;
--
v_date1 Varchar2(30);
v_date2 Varchar2(30);
v_date3 Varchar2(30);
v_char Varchar2(30);
v_cnt Number:= 0;
Begin
For i_rec IN i_cur
Loop
v_cnt:= v_cnt + 1;
Begin
v_date1:= to_char(to_date(i_rec.some_date), 'MM/DD/YYYY hh24:mi:ss');
dbms_output.put_line(v_cnt||'.'||chr(9)||v_date1);
EXCEPTION
When Others Then
Begin
v_date2:= to_char(to_date(i_rec.some_date, 'MM/DD/YYYY hh24:mi:ss'), 'MM/DD/YYYY hh24:mi:ss');
dbms_output.put_line(v_cnt||'.'||chr(9)||v_date2);
EXCEPTION
When Others Then
Begin
v_date3:= to_char(to_date(i_rec.some_date, 'YYYY-MON-DD'), 'MM/DD/YYYY hh24:mi:ss');
dbms_output.put_line(v_cnt||'.'||chr(9)||v_date3);
EXCEPTION
When Others Then
-- Insert into Exceptions table (or any temp table) then convert... --
v_char:= i_rec.some_date;
dbms_output.put_line(v_cnt||'. '||chr(9)||i_rec.some_date||' : '||v_char);
End;
End;
End;
End Loop;
End;
/
1. 10/27/1967 00:00:00
2. 10/27/1967 00:00:00
3. 10/27/1967 11:15:45

The most desired way of would be to formatting date into the format that you need. Then do whatever calculations that you require on it.
Otherwise you will have to write ridiculously large number of select cases to define the format. Not to say that it doesn't make sense since dates can come in many different formats....as Mat mentioned. And further Date is a component that can be influenced by your system.
You may try the following:
Convert date input into the desired format using To_Date() given you may not even know if this input comes as a String or a real date. So you may need some validations to make sure it's a proper date.
SELECT TO_DATE(mydate,'mm/dd/yyyy hh:mi:ss') FROM Dual;

Related

Working with dates in PL SQL

I have a simple PL SQL code. However it is failing at date level. The date column is CODT. I declared CODT as date. And in database level, it is date with format YYYY-MM-DD.
I also tried alter session set nls_date_format = 'YYYY-MM-DD'; But it is throwing error.
The error message is ORA-01830: date format picture ends before converting entire input string
00000 - "date format picture ends before converting entire input string"
Could you let me know where I need to change it to date format/ where I am making a mistake ?
DECLARE
RID VARCHAR2(100);
KY VARCHAR2(200);
CODT DATE;
CURSOR FETCH_DTLS IS
SELECT ROW_ID,
KEY,
CUT_OFF_DT,
FROM TMP1
WHERE RN = 1;
BEGIN
OPEN FETCH_DTLS;
LOOP
FETCH FETCH_DTLS
INTO RID,
KY,
CODT;
EXIT WHEN FETCH_DTLS%NOTFOUND;
INSERT INTO tmp2
VALUES
(RID,
KY,
CODT
);
END LOOP;
COMMIT;
CLOSE FETCH_DTLS;
COMMIT;
END;
if you have date column which defined varchar2 in db you should use it like this:to_date(your_column/*CUT_OFF_DT*/, 'yyyy-mm-dd')
when you use VARCHAR2 field and insert it in a table with DATE data-type, then you tell oracle to: Cast VARCHAR2 to DATE
So your mistake is casting without providing any format, here are some date format examples used in oracle:
'YYYY-MM-DD'
'YYYY-MM-DD HH24:MI:SS'
there is also another function in oracle called TO_DATE which will do the job, it simply casts the string(char or varchar) to date with provided date-format and also provided calendar! Here is some examples:
TO_DATE('2016-12-15','YYYY-MM-DD')--uses default calendar of session
TO_DATE('2016-12-15','YYYY-MM-DD', 'nls_calendar=gregorian')
TO_DATE('1395-09-25','YYYY-MM-DD', 'nls_calendar=persian')--Solar base date used in IRAN
and reverse function is TO_CHAR
TO_CHAR(SYSDATE,'YYYY-MM-DD')--SYSDATE is in Date type so this works
there is another data-type related to dates, which is called TIMESTAMP
TO_CHAR(SYSTIMESTAMP,'YYYY-MM-DD HH24:MI:SSxFF')--SYSTIMESTAMP is in TIMESTAMP type so this works
finally we can use INTERVAL type to calculate interval between 2 dates(Specially timestamps) and there is a useful function called numtodsinterval which converts numbers to intervals, you can use it like this:
SYSDATE+NUMTODSINTERVAL(1,'Minute')
and this is an example:
SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS'),
TO_CHAR(SYSDATE+NUMTODSINTERVAL(1,'Minute'),'YYYY-MM-DD HH24:MI:SS')
FROM DUAL
which outputs:
1 2016-12-15 15:05:10 2016-12-15 15:06:10
I hope it will be useful in your future usages of DATE, goodluck

PL/SQL - Cannot convert string to desired date format using to_date()

I have a string like "01-JAN-15 13:05:01". I used to_date() function to convert the string to date format and store it to a date field. However, the time value stored is not correct, which is "01/01/2015 04:12:43 PM". I used to_char() function to show the value of the converted date, but the returned value does not have any problem.
Input(String): 01-JAN-15 13:05:01
Desired Output(Date): 01/01/15 01:05:01 PM
Actual Output(Date): 01/01/15 04:12:43 PM
Code for conversion:
select to_date('01-JAN-15 13:05:01', 'dd-mon-yy hh24:mi:ss') into result_date from dual;
to_char()
to_char(result_date, 'dd/mm/yyyy hh:mi:ss');
UPDATE:
whenever sqlerror exit 99 ROLLBACK;
set echo on;
set verify on;
set serverout on;
declare
result_date date;
begin
select to_date('01-JAN-15 13:05:01', 'dd-mon-yy hh24:mi:ss') into result_date from dual;
insert into temp_table values (result_date);
commit;
end;
Above code should not give a problem. I ran below code snippet and gave me the expected result. Double check once if you are using above code only.
DECLARE
result_date DATE;
BEGIN
select to_date('01-JAN-15 13:05:01', 'dd-mon-yy hh24:mi:ss') INTO result_date from dual;
DBMS_OUTPUT.PUT_LINE(to_char(result_date, 'dd/mm/yyyy hh:mi:ss AM'));
END;

Why the Time is missing?

I have code below:
declare
v_rst varchar2(200);
cursor c_cur is
select sysdate from dual;
begin
open c_cur;
fetch c_cur
into v_rst;
close c_cur;
dbms_output.put_line(v_rst);
end;
the output result for it is 23-DEC-14
When I run below query, the result is 12/23/2014 11:21:06 AM:
select sysdate from dual;
I do not know why the TIME part is gone when I run the first code.
The time is not "gone". That format is just the default. You need to set the NLS_DATE_FORMAT for the default value:
ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH:MI:SS';
or whatever format your want.
Or, change your query to format the date field using the to_char function
select to_char(sysdate, 'MM/DD/YYYY HH:MM:SS') from dual;
See the format model here.

ORA-06502: PL/SQL: numeric or value error: character string buffer too small in Oracle sql query

I want to calculate the time difference between two dates in Oracle sql query. I have written the following query:
DECLARE
v_time varchar2(40);
diff_hours varchar2(40);
BEGIN
select substr(((select date_time from observation_measurement where observation_measurement_id=2861971)), 1,17)
into v_time
from dual;
dbms_output.put_line(v_time);
select 24 * (to_date('06-25-2014 09:46:36', 'MM-DD-YYYY hh24:mi:ss')
- to_date(v_time, 'YY-MM-DD hh24:mi:ss')) into diff_hours
from dual;
END;
The first select statement returns correct result. When I am trying to calculate the time difference from current date to the previous calculated date then it is showing error. How can I get the correct result?
Thanks!!!!
Increasing the size of diff_hours variable working. Thanks Krishna. :-)
Make diff_hours a NUMBERvariable instead of a VARCHAR2 variable!
Of course you can make diff_hours long enough to hold all the insignificant decimals your query produces, but declaring it VARCHAR2 is pointless anyway!
Hi I have made some corrections in your query . Tell me if that works
DECLARE
v_time varchar2(40);
-- Increase the size
diff_hours varchar2(200);
BEGIN
select substr(((select date_time from observation_measurement where observation_measurement_id=2861971)), 1,17)
into v_time
from dual;
dbms_output.put_line(v_time);
-- using the same format mask for both the dates
select 24 * (to_date('06-25-2014 09:46:36', 'MM-DD-YYYY hh24:mi:ss')
- to_date(v_time, 'MM-DD-YYYY hh24:mi:ss')) into diff_hours
from dual;
END;
You can increase diff_hours and it might work in some cases, but the problem is it might not work in other cases.
To be sure, you need explisitly convert number to string (example with 2 digits after dot):
select trunc(24*...., 2) into diff_hours

Select doesn't return expected result with Date type in Oracle DB

Table my_table is:
CREATE TABLE MY_TABLE(
ID NUMBER NOT NULL,
MY_DATE DATE NOT NULL);
Typing the following query:
select sysdate from dual
the result is:
10-MAG-12 21:22:32
note that mag = may.
Now, if I type this query:
select *
from my_table
where my_date <= sysdate
the result is:
9918 10-MAG-12 20:00:00
9915 10-MAG-12 21:00:00
9952 10-MAG-12 22:00:00
9951 10-MAG-12 23:00:00
Note that in my_table I have only these 4 records. Why I see all the records and not the first and second record only? Thanks.
I use Oracle SQL Developer.
Edit: please note that when I insert a record with PL/SQL I type something like:
nCount NUMBER;
myDate DATE;
stringDate VARCHAR2(255);
BEGIN
nCount := 0;
stringDate := substr(to_char(trunc(sysdate)),0,9);
myDate := to_date(stringDate || ' 20:00:00','dd-mm-yyyy hh24:mi:ss');
for t in (a cursor) loop
insert into MY_TABLE(ID,MY_DATE)
values (9918,myDate+(nCount/1440));
nCount := nCount + 60;
end loop;
END;
I suspect that the data being stored in your table does not have a year of 2012. It probably has a year of 0012 (two thousand years ago).
What do you see when you run the query
SELECT id, to_char( my_date, 'dd-mm-yyyy hh24:mi:ss' )
FROM my_table
I expect that the year will be 0012 rather than 2012. The reason for that is that the code you're using to insert the data is incorrectly converting a date to a string without using an explicit format mask then converts the string back to a date using an explicit format mask that happens not to match the session's NLS_DATE_FORMAT. In general, if you ever find yourself converting a date to a string and back to a date, you're probably doing something wrong. If you change your code to simply do date manipulation, it will be more efficient, more robust, and less error-prone.
DECLARE
nCount NUMBER;
myDate DATE;
BEGIN
nCount := 0;
myDate := trunc(sysdate) + interval '20' hour;
for t in (a cursor) loop
insert into MY_TABLE(ID,MY_DATE)
values (9918,myDate+(nCount/1440));
nCount := nCount + 60;
end loop;
END;
Walking through why the original code goes wrong
stringDate := substr(to_char(trunc(sysdate)),0,9);
This takes SYSDATE and truncates it to midnight on the current day. So far, so good. Then, it calls TO_CHAR without an explicit format mask. This causes Oracle to use the session's NLS_DATE_FORMAT, meaning that different users with different settings will get different results. If your session's NLS_DATE_FORMAT happens to be 'dd-mon-rr hh24:mi:ss', which I'm guessing based on the query results you posted, that will mean that the string has a 2-digit year. Your SUBSTR appears to assume that the output has just a two-digit year (if you have a different NLS_DATE_FORMAT, your SUBSTR will generate different bugs such as potentially cutting off the 12 from a year of 2012 leaving a year of just 20).
myDate := to_date(stringDate || ' 20:00:00','dd-mm-yyyy hh24:mi:ss');
Assuming stringDate is something like 10-MAG-12, this next line generates a string 10-MAG-12 20:00:00 and then tries to convert it to a date using the format mask dd-mm-yyyy hh24:mi:ss. This assumes that the string has a 4-digit year so when it only finds 2-digits, it assumes that you meant the year 12, not the year 2012.