Date format: Invalid Month

Multi tool use
Multi tool use


Date format: Invalid Month



I have below data format



10/29/2003



10/21/2003 7:26:00 AM in a table



and I want to compare dates in between '07-14-2013' and '09-15-2013'. I have written code as



to_char(to_date(a.TEXT_VALUE, 'DD-MM-YYYY HH:MI:SS AM'),'dd-mm-YYYY') between '07-14-2013 00:00:00 AM' and '09-15-2013 00:00:00 AM'



this is not working. Can anyone suggest what should I do to get dates between these 2 dates?





How varied are the values in your text field? Do you have a mix of just dates, dates with times in 12-hour format (with AM/PM), and dates with times in 24-hour format? How sure are you that all the dates are in the same MM/DD/YYYY format? This is why dates should never be stored in varchar2 columns, but always in date columns.
– Alex Poole
Oct 16 '13 at 16:10


varchar2


date





i have only these formats..
– user1465978
Oct 16 '13 at 16:13





you assume (or hope) you only have these formats. An application can stick anything in a varchar field
– tbone
Oct 16 '13 at 16:20





So can u please help me how should my query look like I have chekced the query the out put is only like in these 2 formats? 10/29/2003 , 10/21/2003 7:26:00 AM in a table
– user1465978
Oct 16 '13 at 16:25





3 Answers
3



You have your days and months reversed.
Americans (and possibly other countries too) use a notation of MM-DD-YYYY:


to_char(to_date(a.TEXT_VALUE, 'MM-DD-YYYY HH:MI:SS AM'),'mm-dd-YYYY')
between '07-14-2013 00:00:00 AM' and '09-15-2013 00:00:00 AM'





Now it says HOur must be between 1 and 12 and if I keep HH24 it says Hh24 precludes use of meridian indicator
– user1465978
Oct 16 '13 at 15:55





@user1465978, you need an ALTER SESSION SET NLS_DATE_FORMAT = 'MM-DD-YYYY HH:MI:SS AM';
– ajmalmhd04
Oct 16 '13 at 16:01






So i need to add it after to_char(to_date(a.TEXT_VALUE, 'MM-DD-YYYY HH24:MI:SS AM'),'mm-dd-YYYY') between '07-14-2013' and '09-15-2013' Please tell me exactly
– user1465978
Oct 16 '13 at 16:06






@ajmalmhd04 - you don't need an alter session, the to_char() and to_date() both have explicit date format models, so the query is not relying on NLS_DATE_FORMAT (which is good). But, comparing date strings like that won't work properly, they need to be YYYY-MM-DD for a text comparison. More importantly it sounds like the text field has varying formats which need to be handled - exactly why dates should not be stored as strings in the first place...
– Alex Poole
Oct 16 '13 at 16:08


alter session


to_char()


to_date()


NLS_DATE_FORMAT


YYYY-MM-DD





@AlexPoole, Thanks for the info
– ajmalmhd04
Oct 16 '13 at 16:10



As others have also said, you really don't know whats in that varchar field, and dates should be stored as dates (so you can do all the wonderful things with dates, like compare them, subtract them, get date ranges, etc...).



So, if you have even 1 record that has an invalid date, the to_date will break. But, you say that you only want to grab records within a date range, you might ignore the time portion of the date using substr (and still hope the days are valid):


with date_strings as
(
select 1 as id, '01/31/2013' as dte_str from dual
union
select 2 as id, '02/01/2013 13:55:01' as dte_str from dual
union
select 3 as id, '02/28/2013 10:30:01 AM' as dte_str from dual
union
select 4 as id, '03/01/2013 11:15:01 AM' as dte_str from dual
)
select
id, dte_str, to_date(substr(dte_str, 1, 10), 'MM/DD/YYYY') as dte
from date_strings
where to_date(substr(dte_str, 1, 10), 'MM/DD/YYYY') between
to_date('02/01/2013', 'MM/DD/YYYY') and to_date('03/01/2013', 'MM/DD/YYYY')-1;



This example grabs rows that have a date that falls somewhere in Feb of 2013 (or fails if you have even 1 row where the MM/DD/YYYY part of the string is invalid, like 02/29/2013 for example). But at least you can probably ignore the variations in the time formats.



You've said that you have dates with format MM/DD/YYYY and MM/DD/YYYY HH:MI:SS AM, and none with MM/DD/YYYY HH24:MI:SS. The error messages you're getting indicate that you are mistaken; the 'hour must be between 1 and 12' means that you have at least one row with the time in 24-hour format. Or, potentially, with something that isn't a recognisable time at all.


MM/DD/YYYY


MM/DD/YYYY HH:MI:SS AM


MM/DD/YYYY HH24:MI:SS



The problem with storing structured data - a date in this case - in a free-text field as a varchar2 instead of as a proper data type is that you can get any old rubbish in there, and you are relying on your application validate data as it is entered - which is doesn't seem to be doing based on what you're seeing now. Well, one of the major problems, there are others, including performance implications.


date


varchar2



The only way to try to salvage your data is to write a function that tries multiple conversions and only returns when it has something valid - or runs out of options. Something like this perhaps:


create or replace function clean_date(text_value varchar2) return date is
begin
begin
return to_date(text_value, 'MM/DD/YYYY HH24:MI:SS');
exception
when others then
null;
end;

begin
return to_date(text_value, 'MM/DD/YYYY HH:MI:SS AM');
exception
when others then
null;
end;

return null;
end clean_date;
/



This is only trying two formats but you can add more as your data needs - any row that gets a null back couldn't be converted by any of the formats it tried. You need to be a bit careful about the order you test them though, to avoid the potential for incorrect matches. Each begin/exception/end sub-block is testing one format; catching other isn't ideal but the alternative is to declare all possible date format exceptions which would be painful and error-prone. If there is no exception then that date value is returned; if there is any exception then it does nothing but moves on to the next block to try the next format.


null


begin


exception


end


other



This also won't help you if you have something really unexpected, and won't always error if you have a date in UK format as DD/MM/YYYY for example - if both the day and month are less than 13 it's impossible to tell which is which.


DD/MM/YYYY



Anyway, with this your filter could become:


where trunc(clean_date(a.text_value))
between date '2013-07-14' and date '2013-09-15'



You could convert it back to a string if you prefer, but still use a sensible date format for the comparison:


where to_char(clean_date(a.text_value), 'YYYY-MM-DD')
between '2013-07-14' and '2013-09-15'






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

I2Y kn6IFcL 9CVQsZ
YiPQ gkrAOLTiQyfv9bAWd,60NW0qOf43 dZdJSpnVPmJC 7BjnkmZNwGTY

Popular posts from this blog

Rothschild family

Cinema of Italy