Convert Mon yyyy to yyyy-mm-dd format in oracle - oracle

I am sending date (August 2022) from java as a string to oracle plsql and i want to change the format from August 2022 to 01-08-22 in plsql. how can i do it ?
below is a part of code:
PROCEDURE CHECK_DUMMY
(
IN_SL_NO IN SIGN.SL_NO%TYPE,
IN_MONTH IN SIGN.MONTH%TYPE
)
AS
V_MON DATE := TO_DATE(IN_MONTH , 'DD-MM-YYYY');

You want to use the format model Month YYYY and specify the language you are using:
CREATE PROCEDURE CHECK_DUMMY
(
IN_SL_NO IN SIGN.SL_NO%TYPE,
IN_MONTH IN SIGN.MONTH%TYPE
)
AS
V_MON DATE := TO_DATE(IN_MONTH , 'Month YYYY', 'NLS_DATE_LANGUAGE=English');
BEGIN
-- Do Something
DBMS_OUTPUT.PUT_LINE( v_mon );
END;
/
Then:
BEGIN
CHECK_DUMMY(1, 'August 2022');
END;
/
Outputs:
2022-08-01 00:00:00
Note: In Oracle, a DATE is a binary data type comprising of 7 bytes that represent century, year-of-century, month, day, hours, minutes and seconds and always has those 7 components and is never stored with any particular format. If you want to output 01-08-22 for display purposes then use TO_CHAR(v_mon, 'DD-MM-YY') to convert the date to a formatted string.
fiddle

Related

create pl sql trigger

I am trying to write a Trigger for before insert to validate a case date.
The case date should be between 5 years before and 7 years after current date.
For example, in 2018 the case date should be from year 2013 to 2025. If the date is out of range the trigger should stop inserting data.
CREATE OR REPLACE TRIGGER ch
BEFORE INSERT
on CASE
FOR EACH ROW
DECLARE
CASN number;
BEGIN
SELECT COUNT(*)
INTO CASN
FROM CASE
WHERE :new.STARTDATE > SYSDATE;
IF (CASN > 0) THEN
RAISE_APPLICATION_ERROR(-20000,'Start DATE CANNOT Be GREATER than today's
date');
END IF;
END;
Here STARTDATE is column of CASE table
This trigger starts when start date is greater than today's date but I need it to run when it's out range as given above.
How do I add an specified interval to the sysdate, so that it could work for the above condition?
The logic you are using in your Trigger is completely wrong. You don't need to get the count from the table using :NEW.STARTDATE. This is something what you are looking for.
CREATE OR replace TRIGGER ch
BEFORE INSERT ON cases
FOR EACH ROW
BEGIN
IF ( :NEW.casedate < SYSDATE - INTERVAL '5' year
OR :NEW.casedate > SYSDATE + INTERVAL '7' year ) THEN
RAISE_APPLICATION_ERROR(-20000,
'CASE DATE should be in range: current date - 5 years and current date + 7 years')
;
END IF;
END;
/
EDIT : I have not added TRUNC on the dates because I'm not sure if you want to consider time component as well while considering date range.If you are ok with just considering days, you may use TRUNC(SYSDATE) in place of just SYSDATE. Modify it accordingly as per your business needs.
Another option is to use CHECK constraint. Although Oracle does not allow you to have
use SYSDATE in a check constraint definition, you may create another column( or reuse existing) that defaults to SYSDATE and apply check constraint on that.
ALTER TABLE CASES ADD ( CURR_DATE DATE DEFAULT SYSDATE );
ALTER TABLE CASES ADD CONSTRAINT
RANGE_CHECK CHECK( casedate > CURR_DATE - INTERVAL '5' YEAR
AND casedate < CURR_DATE + INTERVAL '7' YEAR) ENABLE;
Date arithmetic. Oracle Database enables you to perform arithmetic operations on dates and time stamps in several ways:
Add a numeric value to or subtract it from a date, as in SYSDATE + 7; Oracle Database treats the number as the number of days.
Add one date to or subtract it from another, as in l_hiredate - SYSDATE.
Use a built-in function to “move” a date by a specified number of months or to another date in a week.
Here are some examples of date arithmetic with a date and a number (assume in all cases that the l_date variable has been declared as DATE):
Set a local variable to tomorrow’s date:
l_date := SYSDATE + 1;
Move back one hour:
l_date := SYSDATE - 1/24;
Move ahead 10 seconds:
l_date := SYSDATE + 10 / (60 * 60 * 24);
When you add one date to or subtract it from another, the result is the number of days between the two. As a result, executing this block:
DECLARE
l_date1 DATE := SYSDATE;
l_date2 DATE := SYSDATE + 10;
BEGIN
DBMS_OUTPUT.put_line (
l_date2 - l_date1);
DBMS_OUTPUT.put_line (
l_date1 - l_date2);
END;
returns the following output:
10
-10

How to convert YY to YYYY ORACLE

How to convert YY to YYYY, example below, if I run example below I will receive for year '0007':
DECLARE
lv_promcode_txt VARCHAR(6) := 'A0807X';
lv_prommth_txt VARCHAR2(7);
lv_promyear_txt VARCHAR2(7);
BEGIN
lv_prommth_txt := SUBSTR(lv_promcode_txt, 2,2);
DBMS_OUTPUT.PUT_LINE('Month of promo code is: '||
TO_(TO_DATE(lv_prommth_TXT,'MM'), 'MONTH'));
lv_promyear_txt := SUBSTR(lv_promcode_txt, 4,2);
DBMS_OUTPUT.PUT_LINE('Year of promo code is: '||TO_CHAR(TO_DATE
(lv_promyear_txt, 'YYYY'),'YYYY'));
END;
Your format mask is wrong. Example:
select TO_CHAR(TO_DATE (SUBSTR('A0807X', 4,2), 'YY'),'YYYY') from dual
returns 2007
Replace your last DBMS_OUTPUT.PUT_LINE part of the code with
DBMS_OUTPUT.PUT_LINE('Year of promo code is ( Style 1 ) : '||TO_CHAR(TO_DATE(lv_promyear_txt, 'YYYY'),'YYYY'));
DBMS_OUTPUT.PUT_LINE('Year of promo code is ( Style 2 ) : '||TO_CHAR(TO_DATE(lv_promyear_txt, 'RRRR'),'YYYY'));
Just changing YYYY literal RRRR is enough in TO_DATE function.
This concept is related to year 2k problem.
For a date TO_DATE('18', 'RRRR') gives the result 2018 as year ( for
the current century, and the last two digits of years are between 00-49 ),
while
For a date TO_DATE('74', 'RRRR') gives the result 1974 as year ( for
the previous century, and the last two digits of years are between 50-99 )

Oracle PLSQL get difference between 2 datetime fields ignoring days

I would like to find the simplest way of calculating the difference in hours between 2 dates from Oracle datetime fields whilst ignoring the days, months & years portion. For example:
Datetime 1 (DATE variable) = 10/05/2017 16:00:00
Datetime 2 (DATE variable) = 15/05/2017 19:34:23
Required result (NUMBER output) = 3.576 hours
This is formula will be used in a PLSQL procedure, the output needs to be a number as above. I would imagine some combination of TO_DATE & TRUNC might work. Any help would be most appriciated and apologies if this is a duplicate question.
Use the sssss date mask to get just the time element as the number of seconds since midnight. Then it's just a matter of simple arithmentic:
select (to_number(to_char(datetime2, 'sssss'))
- to_number(to_char(datetime1, 'sssss')) / 3600 as diff_hours
from dual;
PL/SQL version is the same....
declare
Datetime1 DATE := to_date('10/05/2017 16:00:00', 'dd/mm/yyyy hh24:mi:ss');
Datetime2 DATE := to_date('15/05/2017 19:34:23', 'dd/mm/yyyy hh24:mi:ss');
hours_diff number;
begin
hours_diff := (to_number(to_char(datetime2, 'sssss'))
- to_number(to_char(datetime1, 'sssss'))) / 3600 ;
dbms_output.put_line(hours_diff);
end;

Convert multiple date varchar2 to date format in Oracle 11g

I am having an issue trying to convert multiple dates to one defined format. We are receiving the multiple dates from another DB source so I do not have control of the formatting until it reaches ours.
Here are all the formats:
YYYYMMDD
YYYY-MM-DD HH:MM:SS
MM/DD/YYYY
MM-DD-YYYY
Abrieviated Day Month DD HH:MM:SS TimeZone YYYY ('Thu Feb 02 20:49:59 MSK 2012')
Fully written Day, Month DD, YYYY HH:MM:SS AM/PM
My requirement is to set them all to the standard MM/DD/YYYY format or null. Any ideas?
Thank you.
You may define a transformation function, basically processing sequentially each format:
create or replace function translate_date(i_date_string VARCHAR2) return date as
begin
-- you may optimize to not to go in all blocks based on the string format
-- order the blocks on the expected frequency
begin
return to_date(i_date_string,'yyyymmdd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy/mm/dd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy-mm-dd');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'yyyy-mm-dd hh24:mi:ss');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
-- transform to local timestamp and than to date
return cast(cast(to_timestamp_tz(i_date_string,'dy month dd hh24:mi:ss tzr yyyy') as TIMESTAMP WITH LOCAL TIME ZONE) as date);
EXCEPTION
WHEN OTHERS THEN NULL;
end;
begin
return to_date(i_date_string,'dy, month dd, yyyy hh:mi:ss am');
EXCEPTION
WHEN OTHERS THEN NULL;
end;
return NULL;
end;
/
for example for sample data
TSTMP
------------------------
20150101
2015-01-01 23:59:59
2015/01/01
2015-01-01
Thu Feb 02 20:49:59 Europe/Moscow 2012
Thu, Feb 02, 2012 10:49:59 AM
Thu, Feb 02, 2012 10:49:59 PM
you get
TSTMP RESULT_DATE
------------------------------------------ -------------------
20150101 01.01.2015 00:00:00
2015-01-01 23:59:59 01.01.2015 23:59:59
2015/01/01 01.01.2015 00:00:00
2015-01-01 01.01.2015 00:00:00
Thu Feb 02 20:49:59 Europe/Moscow 2012 02.02.2012 17:49:59
Thu, Feb 02, 2012 10:49:59 AM 02.02.2012 10:49:59
Thu, Feb 02, 2012 10:49:59 PM 02.02.2012 22:49:59
Note that I skipped the case with time zone abbraviation (MSK), see possible solution in the answer from #Sentinel, but check Conversion of String with Abbreviated Timezone to Timestamp that this may be ambiguous.
I'd suggest using a case statement with regexp_like conditions to detect likely formats and return dates using the appropriate date mask in the then clauses e.g.:
with tz as (
SELECT distinct tzabbrev
, first_value(min(tzname)) over (partition by tzabbrev order by count(*) desc) tzname
FROM v$timezone_names
group by tzabbrev
, TZ_OFFSET(tzname)
), dta as (
select yt.install_date
, regexp_replace(yt.install_date,tzabbrev,tzname,1,1,'i') install_date2
from your_table yt
left join tz
on regexp_like(install_date, tz.TZABBREV,'i')
)
select install_date, install_date2
, to_timestamp_tz( install_date2
, case
when regexp_like(install_date2,'^[A-Z]{3,} [A-Z]{3,} [0-9]{1,2} [0-9]{1,2}(:[0-9]{2}){1,2} [[:print:]]{5,} [0-9]{2,4}','i') then 'DY MON DD HH24:MI:SS TZR YYYY'
when regexp_like(install_date2,'^[A-Z]{4,},? [A-Z]{3,},? [0-9]{1,2},? [0-9]{2,4}','i') then 'DAY MONTH DD YYYY'
when regexp_like(install_date2,'^[A-Z]{3},? [A-Z]{3,},? [0-9]{1,2},? [0-9]{2,4}','i') then 'DY MONTH DD YYYY'
when regexp_like(install_date2,'^[0-9]{1,2}[-/][0-9]{1,2}[-/]([0-9]{2}){1,2}') then 'MM-DD-RRRR'
when regexp_like(install_date2,'^[0-9]{1,2}[-/ ][A-Z]{3,}[-/ ]([0-9]{2}){1,2}','i') then 'DD-MON-RRRR'
when regexp_like(install_date2,'^[A-Z]{3,}[-/ ][0-9]{1,2},?[-/ ]([0-9]{2}){1,2}','i') then 'MON-DD-RRRR'
when regexp_like(install_date2,'^(19|20)[0-9]{6}') then 'RRRRMMDD'
when regexp_like(install_date2,'^[23][0-9]{5}') then 'DDMMRR'
when regexp_like(install_date2,'^[0-9]{6}') then 'MMDDRR'
when regexp_like(install_date2,'^[01][0-9]{7}') then 'MMDDRRRR'
when regexp_like(install_date2,'^[23][0-9]{7}') then 'DDMMRRRR'
ELSE NULL
end
||case
when regexp_like(install_date2, '[0-9]{1,2}(:[0-9]{2}){1,2}$') then ' HH24:MI:SS'
when regexp_like(install_date2, '[0-9]{1,2}(:[0-9]{2}){1,2} ?(am|pm)$','i') then ' HH:MI:SS AM'
else null
end
)
Install_Time_Stamp
from dta;
I had issues with the time zone abbreviations so I added a step to replace them with time zone regions first.
The function can be simplified a little bit as to_date tolerates minor deviations (different separators, missing separators, missing time components, 2/4-digit year). For instance to_date(:str,'rrrr-mm-dd hh24:mi:ss') will cover
2020/09/18 01.02
2020.09.18 01
20200918010203
2020-0901
202009-01
20/09/18
To_timestamp_tz will also tolerate missing milliseconds and time zone (including missing TZ elements TZM and TZD).
So we basically need to take care of major variations only like hh24/hh, mm/mon, elements order, "T" separator in ISO 8601 (2020-01-01T01:02:03), TZ designators (UTC offset TZH:TZM / region name TZR), and day of week (DY).

date difference between two date datetype variable in HH:MM:SI in Oracle [duplicate]

This question already has answers here:
In Oracle, is there a function that calculates the difference between two Dates?
(5 answers)
Closed 8 years ago.
I am facing an issue where I have to take the difference between two date datetype variables in HH:MM:SS AM. For example if date1 stores 23-DEC-2014 02:00:00 PM and date2 stores 24-DEC-2014 02:00:00 PM then date2 - date1 should return 24:00:00.
I tried different to_char and likewise methods.
Can you please suggest what I should do to resolve this issue.
As you have plain DATE, the difference between two dates is expressed in fractional days. Some little arythmetics as explained in the related questions might help.
One other approach would be to cast the difference to an INTERVAL using NUMTODSINTERVAL. However, this does not work out-of-the-box, as (of 11g at least), the TO_CHAR function does not supports correctly INTERVAL.
However, as a workaround that is not provided in the related answers (or do I missed it?), you can cast to INTERVAL DAY TO SECOND using the right precision to achieve (more or less) what you are looking for:
Here is an example
with testdata as (select to_date('12/12/2014 09:00:00','DD/MM/YYYY HH:MI:SS') a,
to_date('10/11/2014 11:30:14','DD/MM/YYYY HH:MI:SS') b from dual)
select a-b "days",
numtodsinterval(a-b, 'DAY') "ds interval",
CAST(numtodsinterval(a-b, 'DAY') AS INTERVAL DAY(3) TO SECOND(0))
-- ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- cast to 3 digit days interval -- no fractional seconds
from testdata
Producing (formatted as rows for display purpose):
days
31.8956712962962962962962962962962962963
ds interval
+000000031 21:29:46.000000000
CAST(NUMTODSINTERVAL(A-B,'DAY') AS INTERVAL DAY(3) TO SECOND(0))
+031 21:29:46
I don't know if/how you can get rid of the leading sign though
Maybe this helps:
CREATE OR REPLACE FUNCTION get_date_diff(p_date1 IN DATE,
p_date2 IN DATE) RETURN VARCHAR2
IS
v_seconds NUMBER;
v_minutes NUMBER;
v_hours NUMBER;
v_time VARCHAR2(20);
BEGIN
v_seconds := (p_date2 - p_date1) * 24 * 60 * 60;
v_hours := FLOOR(v_seconds / 3600);
v_minutes := FLOOR((v_seconds - (v_hours * 3600)) / 60);
v_seconds := FLOOR(v_seconds - (v_hours * 3600) - (v_minutes * 60));
v_time := CASE WHEN v_hours < 100
THEN LPAD(TO_CHAR(v_hours), 2, '0')
ELSE TO_CHAR(v_hours)
END || ':' ||
LPAD(TO_CHAR(v_minutes), 2, '0') || ':' ||
LPAD(TO_CHAR(v_seconds), 2, '0');
RETURN v_time;
END;
/
SAMPLE INPUT
p_date1:=to_date('20/11/2014 11:30:45','DD/MM/YYYY HH:MI:SS')
p_date2 :=to_date('15/12/2014 09:00:00','DD/MM/YYYY HH:MI:SS')
SAMPLE OUTPUT
597:29:15

Resources