Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, nag.

Asked: September 23, 2001 - 11:40 am UTC

Last updated: April 27, 2020 - 4:14 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Tom

I had been getting some weird errors

My function p accepts a date parameter. When ever Iam passing dates in the format dd-mon-yy , I am having no problems. But when Iam sending it in any other format Iam getting the error 'invalid month'.


FUNCTION fnc_get_date(
current_date date,
prior_date date
)
RETURN date;
vc_date date;
vp_date date;
temp_date date;
v_counting number;
begin


vc_date := TRUNC( current_date );


v_counting := 0;
temp_date := TRUNC( prior_date );
while v_counting < 1 loop

if (( to_char( temp_date, 'DY') = 'SAT') or
( to_char( temp_date, 'DY') = 'SUN') or
( Rcp_util.nf_date_is_holidayday( temp_date,21) = 2 ))
then
temp_date := temp_date - 1;
else
v_counting := 1;
end if;
end loop;

return temp_date;

end;


and Tom said...

Well, there can only be ONE date format in effect at any point in time. The default date mask is dd-mon-rr. If you send in some arbitrary format -- we will not "guess" what the date is (eg: is 10-11-01 October 11'th 2001, is is November 10'th 2001, is it perhaps the first of November on 2010 - and so on).


The invoker of this function should use the TO_DATE function with the format for that type of date they are sending (even the callers that use dd-mon-rr should use TO_DATE -- in the event your application is ever used on a database with a DIFFERENT default).

They should be calling:

begin
? := fnc_get_date( to_date( ?, 'dd/mm/yyyy' ), to_date( ?, 'dd/mm/yyyy' ) );
end;

for example if they use a date in dd/mm/yyyy format.



Rating

  (11 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

How do we set the data format for a database

A reader, September 23, 2001 - 1:05 pm UTC

and

the scripts which you write , return date with time as well by deafault , how is that made possible.

Tom Kyte
September 23, 2001 - 1:45 pm UTC

I either use to_char( dt_field, 'dd-mon-yyyy hh24:mi:ss' )

or I've issued:

alter session set nls_date_format = 'dd-mon-yyyy hh24:mi:ss';

in my session before selecting a date.

A reader, July 09, 2003 - 9:13 pm UTC

Hi Tom,

I have a procedure that fetchs data from a cursor in which one of its columns is a varchar2(9) datatype, which contains values in the format 'dd-mon-yy' or the word 'null'.

The default value for the parameter nls_date_format is 'dd-mon-rr'

If I set nls_date_format to 'mm/dd/yyyy' on a sql*plus session and then run the procedure, I get an error 6502 PL/SQL: numeric or value error, when the cursor tries to fetch values in the format 'dd-mon-yy'.

But If I leave the nls_date_format in its default value (dd-mon-rr) or if I set it to 'mm/dd/yy', the procedure runs without any problem on sql*plus for any kind of value ('dd-mon-yy' or the word null).

1-Can you tell me why I am getting this error if I change the nls_date_format to 'mm/dd/yyyy'?
2-Due to I have a mix of words and dates in a varchar2 datatype column, shouldn't I receive the error no matter what the setting is for the nls_Date_format parameter?

Thanks in advance for any help on this.

Tom Kyte
July 10, 2003 - 7:43 am UTC

1) because apparently you've done the worst thing you can do, you stored dates as strings -- meaning that all implicit conversions will be problematic performance wise and error wise forever.

In addition to storing a date in a string -- which is really bad -- you've forgotten that it takes a MINIMUM of 4 characters to store a century/year. Tell me, what is 12-jan-40. ugh.

create the view as

select ...., decode( c, 'null', to_date(null), to_date(c,'dd-mon-rr') ) c

and that'll solve your implicit conversion problem -- but not your "i've no idea what year this data is really for" problem.

2) no, the date formats are forgiving in that fashion to a point. But that also points out why you never never (as in never) want to rely on implicit conversions. what if someone sticks in 01-11-10 is that the 1st of november 2010, the 11th of jan 1910, what?

what do you recommend

dwl, March 03, 2004 - 6:54 am UTC

So i am just wondering what you believe is best practice for writing code in applications (apart from moving all the sql into the database!)??

If we have a java app using jdbc to oracle 8.1.7.4.

1) Then should any sql that references and compares dates in the app code, do an explicit TO_DATE on each date??

ie WHERE mydatefield = TO_DATE('01/01/2001', 'DD/MM/RRRR');

Obviously this makes a call to the TO_DATE function, so is this the most efficient way i.e. more efficient than forcing all jdbc clients to use a certain nls_date_format eg using a logon trigger or env variable and then coding eg:

WHERE mydatefield = '01/01/2001';

ie no call to TO_DATE. or is this so neglible that i shouldn't worry about it? I'm mainly thinking about some app which may run some sql code hundreds or thousands of times a day, so calling TO_DATE a lot!

2) If the client either odbc or jdbc connects to the database without any registry settings or environmental settings for nls_date_format, then which format would it pick up, the nls_instance_parameter settings??
What if NLS_LANG is set in the registry but not the nls_date_format??

3) How can i use sqlplus to emulate the jdbc/odbc clients. ie i want to test some sql using the same nls settings that the client would use. At the moment i issues an explicit allter session set nls_date_format in my glogin.sql script but if i want sqlplus to use the nls_instance_parameters what should i do, delete the glogin script??


Thanks for your help.

Tom Kyte
March 03, 2004 - 9:59 am UTC

1) yes, use to_date. else you introduce unavoidable ambiguities into the code.

2) odbc is almost always on windows, windows ALWAYS has registry settings. The problem is some clients will get it from the db, some from the client, some set on their own -- you cannot control it. that is why i like #1

3) yes, just don't alter and sqlplus will do what the client would do.

April 2005 has more than 30 days ;-)

A reader, April 28, 2005 - 12:34 pm UTC

SQL>select to_char(sysdate,'day dddth month yyyy') from dual;

TO_CHAR(SYSDATE,'DAYDDDTHMONTH
------------------------------
thursday  118th april     2005

SQL>select to_char(sysdate,'day ddddth month yyyy') from dual;

TO_CHAR(SYSDATE,'DAYDDDDTHMONTH
-------------------------------
thursday  1185th april     2005

Having a good laugh after a bad day :-) 

date query

ian gallacher, September 17, 2005 - 4:15 pm UTC

Hi

Have always had problems with dates in my app since (rightly or wrongly) the app passes parameters from one form to another via globals! This give me a headache since dates are passed in this manner and thus become character strings giving problems especially when using DDMMYY. I get round this be using some sql to make sure I am getting the correct century. However I have noticed a peculiarity with the year 50 !

My code :-

/* forgot problem with using 6 digit dates
if key in 010150 routine comes back with 01012050
if key in 311249 routine comes back with 31121949
*/

BEGIN
/* will decode DDMMYY DDMMYYYY */
select
to_date(to_char(to_date(ON_SET,'ddmmrrrr'),'ddmmrrrr'),'ddmmrrrr')
into CHECK_DATE
from dual;
if check_date is not null then
if check_date > sysdate then
check_date := add_months(check_date,-100*12);
end if;
D_DATE := to_char(CHECK_DATE,'DD/MM/YYYY 00:00:00');
return;
end if;
exception when others then null;
END;
What is special for 50 to Oracle ?

Have also hit problems when using dates > year 2050 !

Any comments would be appreciated

Thanks




Tom Kyte
September 17, 2005 - 11:47 pm UTC

you are using the rr format - have you read about the rr format.

YY would say "just take what you got and use it", if you give me 50 and the year is 2005 - we'll have 2050. If you give me 50 and the year is 1999, we'll have 1950 -- we'll use the century from the current year.

RR creates a window of plus or minus 50 years from the current century (1950ish-2050ish). In 1999 and 2005 - the year "50" is the same thing.


You have a pretty serious BUG in your application - it uses two characters where ONLY FOUR can work.

You don't have problems with years > 2050, you have *ambiguity* - you don't *know* because someone won't tell you.

problem with date formats

ian gallacher, September 18, 2005 - 9:47 am UTC

Hi

Thanks for your response

Just a follow up on my BUG !

Dates are entered into my via forms using ddmmrr after 2000
Prior to that were using ddmmyy
Transaction dates started around 1993/94

Date mask of dd/mm/yyyy is used for Dates of Birth

Only time hit a bit of hassle is when date is passed to a global or entered into a char field

Current example are when “dates” are entered into character fields when an exact date is not known – “date” of onset of clinical condition
i.e may-1994, 1955, 01/01/1994, 01011994, 01/01/93,12/94 etc which is more of a narrative than proper dates

Do you think sql for processing “global” dates in previous post handles dates ok from 1990 - future ?

Thanks


Tom Kyte
September 18, 2005 - 11:30 am UTC

Only you can answer that last question, does it meet your end users expected outcome


And are your end users willing to live with the fact that what they typed in might not be what gets stored since you lose the century and have to put it back later and can only "guess" what the most likely century is?

I'd look at this as a "priority 1++ bug" and acutally fixed the underlying cause - find the globals and have them store the data in a lossless format.

Can SQL call a function within a "C" DLL file??

Thom, April 01, 2006 - 12:09 am UTC

Does anyone know how to call a function from within SQL?? Hum? If you can call a "C" DLL function within an SQL program, Please let me now how! I might be able to offer a solution on all your mentioned date format problems.

Thom.

Tom Kyte
April 01, 2006 - 9:53 am UTC

yes you can (we call them external procedures) but trust me - if you can "fix" this in C, we can do it in PLSQL just as easily.


So, tell us the algorithm you would use to "fix" this :)

problem with NLS_DATE_FORMAT resolution

olivier, June 21, 2007 - 11:01 am UTC

Tom,

I have a problem with related to dates conversions with a software package working on oracle 9.2.0.6.0 : after working fine for a while, some process start crashing all the time because of date conversions issues (there are implicit conversions somewhere in the code).
After some investigation, we found out that oracle seems not to resolve the right NLS_DATE_FORMAT parameter. I mean it uses the DATABASE level parameter instead of the SESSION level parameter set with an ALTER SESSION command :

Here is what i found :

SELECT * FROM NLS_DATABASE_PARAMETERS where parameter = 'NLS_DATE_FORMAT';
---------------------------------------------
PARAMETER VALUE
NLS_DATE_FORMAT DD-MON-RR

SELECT * FROM NLS_SESSION_PARAMETERS where parameter = 'NLS_DATE_FORMAT';
---------------------------------------------
PARAMETER VALUE
YYYYMMDD:HH24MISS 21-JUN-07


Select sysdate from dual;
---------------------------------------------
Sysdate
21-JUN-07

As you can see, the default date format defers from the session level NLS_DATE_FORMAT.

I saw on some website that there could be a bug for the format resolution on oracle 7xxxx, but nothing about it for later versions of oracle.

What do you think ?

Regards,
Olivier

Tom Kyte
June 21, 2007 - 11:20 am UTC

I think I would like to see an entire test case with the necessary steps to see what you see.

ORA-01858

yasser, April 24, 2020 - 8:32 am UTC

Hi there,

I have this inserting query in Proc program :

INSERT INTO ORDER (DATEORDER)
VALUES (to_date(decode(:ecddenlev,'-1',null,:ecddenlev),'DD/MM/RR HH24:MI')).

And also, I have the variable :ecddenlev = '-1'.

When I launch the Proc program, I receive this error message :

ORA-01858: a non-numeric character was found where a numeric was expected.

Any Idea please.
Thanks in advance.

Best Regards
Yasser
Chris Saxon
April 27, 2020 - 4:14 pm UTC

What's the full code that runs this SQL?

Appear to be a data issue...

J. Laurindo Chiappa, April 27, 2020 - 6:40 pm UTC

Could be some issue wuth your data - please make SURE the bind variable ecddenlev REALLY is a string and it contains OR '-1', without ANY spaces or any extra characters, OR it contains a VALID data string in the given format... Example :

SYSTEM@O11GR2:SQL> create table ORDER (DATEORDER date);

Table created.

SYSTEM@O11GR2:SQL> variable ecddenlev varchar2(40);
SYSTEM@O11GR2:SQL> exec :ecddenlev := '-1';

PL/SQL procedure successfully completed.

SYSTEM@O11GR2:SQL> print ecddenlev

ECDDENLEV
--------------------------------------------------------------------------------------------------------------------------------
-1

==> Now I try your code :

SYSTEM@O11GR2:SQL> Begin
2 INSERT INTO ORDER (DATEORDER)
3 VALUES (to_date(decode(:ecddenlev,'-1',null,:ecddenlev),'DD/MM/RR HH24:MI'));
4 END;
5 /

SYSTEM@O11GR2:SQL> select * from ORDER;

DATEORDE
--------


1 linha selecionada.

=> ok, a record with NULL date was inserted, as expected... Now let´s put a valid date string using the given format in the variable :

SYSTEM@O11GR2:SQL> exec :ecddenlev := '01/01/20 13:14';

PL/SQL procedure successfully completed.

SYSTEM@O11GR2:SQL> print ecddenlev

ECDDENLEV
--------------------------------------------------------------------------------------------------------------------------------
01/01/20 13:14

SYSTEM@O11GR2:SQL> Begin
2 INSERT INTO ORDER (DATEORDER)
3 VALUES (to_date(decode(:ecddenlev,'-1',null,:ecddenlev),'DD/MM/RR HH24:MI'));
4 END;
5 /

PL/SQL procedure successfully completed.

SYSTEM@O11GR2:SQL> select * from ORDER;

DATEORDE
--------

01/01/20

2 rows selected.

=> Now I will put an extra space in the -1 string :

SYSTEM@O11GR2:SQL> exec :ecddenlev := '-1 ';

PL/SQL procedure successfully completed.

=> As expected, I got an conversion error because the DECODE tried to pass the string to the TO_DATE function :

SYSTEM@O11GR2:SQL> Begin
2 INSERT INTO ORDER (DATEORDER)
3 VALUES (to_date(decode(:ecddenlev,'-1',null,:ecddenlev),'DD/MM/RR HH24:MI'));
4 END;
5 /

BEGIN
*
ERROR at line 1:
ORA-01847: day of month must be between 1 and last day of month
ORA-06512: at line 2


SYSTEM@O11GR2:SQL>

=> So, my first react is : CONFIRM that in your proc the variable ecddenlev REALLY is a string AND it contains '-1', without ANY spaces or any extra characters, OR it contains a VALID data string in the given format...

Regards,

Chiappa

Just to add....

J. Laurindo Chiappa, April 27, 2020 - 10:06 pm UTC

For an Example with the bind variable containing a date string in incorrect format, see :

SYSTEM@O11GR2:SQL> exec :ecddenlev := 'may/05/2020 14:00 ';

PL/SQL procedure successfully completed.

SYSTEM@O11GR2:SQL> print ecddenlev

ECDDENLEV
--------------------------------------------------------------------------------------------------------------------------------
may/05/2020 14:00

SYSTEM@O11GR2:SQL> ed
Wrote file afiedt.buf

1 Begin
2 INSERT INTO ORDERS (DATEORDER)
3 VALUES (to_date(decode(:ecddenlev,'-1',null,:ecddenlev),'DD/MM/RR HH24:MI'));
4* END;
SYSTEM@O11GR2:SQL> /
Begin
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected
ORA-06512: at line 2


SYSTEM@O11GR2:SQL>

We got the same error message reported by you, okdoc ?? Maybe this is your issue....

Regards,

Chiappa