Date format: Invalid Month

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?
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.
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 indate
columns.– Alex Poole
Oct 16 '13 at 16:10