Oracle date conversion outputs 2000s instead of required 1990s - sql

During execution of below query, the output is 2090.
select to_char(to_date('10-OCT-90', 'DD-MON-YY'), 'YYYY') from dual;
Required output is 1990, the date in the snippet is Birth Date.
EDIT:
The input date is fetched from a table, so the date is in DD-MON-YY format.

For alternative resolving the double-digit years in strings, Oracle has the RR format element. Thus, your query would be
select to_char(to_date('10-OCT-90', 'DD-MON-RR'), 'YYYY') from dual;
From the referenced Oracle doc:
The RR datetime format element is similar to the YY datetime format element, but it provides additional flexibility for storing date values in other centuries. The RR datetime format element lets you store 20th century dates in the 21st century by specifying only the last two digits of the year.

Use RR instead of YY. See here: https://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#SQLRF00215

Try to use RR like this:
select to_char(to_date('10-OCT-90', 'DD-MON-RR'), 'YYYY') from dual;
SQL FIDDLE DEMO
Also note that you should store the dates in YYYY format as it will be confusing to make the correct assumption as to the birth year is in 2000 or 1900 or 1800 or... ;)
The Oracle docs says:
YY allows you to retrieve just two digits of a year, for example, the
99 in 1999. The other digits (19) are automatically assigned to the
current century. RR converts two-digit years into four-digit years by
rounding.
50-99 are stored as 1950-1999, and dates ending in 00-49 are stored as
2000-2049. RRRR accepts a four-digit input (although not required),
and converts two-digit dates as RR does. YYYY accepts 4-digit inputs
butdoesn't do any date converting

I had the same issue for my Date column (DOB) if DOB is 27-08-1947. I use below conversion format to get correct year to calculate age.
TO_DATE(TO_CHAR(DOB,'DD-MON-YYYY'), 'DD-MON-YYYY')
TO_DATE(TO_CHAR(DOB,'DD-MM-YYYY'), 'DD-MM-YYYY')

SELECT TRUNC(SYSDATE) TODAY,
TO_DATE(BIRTH_DATE,'DD-MON-RR') DOB,
BIRTH_DATE
FROM TM_DM_CLIENT
WHERE CLIENT_NO IN ('22943179')
output
Today DOB BIRTH_DATE
10/1/2019 1/1/2041 1/1/1941

Related

AWS Athena (Trino SQL) Convert birthdate string (mm/dd/yy) to date -- need twentieth century

AWS Athena (Trino) Convert birthdate string (mm/dd/yy) to date -- need twentieth century
I have found similar questions, but they either aren't specific to Athena, or to this two-digit to date format for a birthdate (e.g. 56 should map to 1956)
An example of similar question (this one is 4-year date is):
Amazon Athena Convert String to Date
For example, cast( date_parse(trim("date of birth"),'%m/%d/%Y') as date ) as our_date_of_birth gives the laughable: 0094-01-04 instead of a date in 1994
However, if I use:
cast( date_parse(trim("date of birth"),'%m/%d/%y') as date ) as our_date_of_birth,
it sometimes gives me correct date, but sometimes something like: 2062-07-31 instead of 1962
Finally, just plain:
cast( trim("date of birth") as date ) as our_date_of_birth
gives an error: INVALID_CAST_ARGUMENT: Value cannot be cast to date: 10/11/78
Is there a way to get twentieth century birthdates from these casts in Athena Trino?
Obviously there would be edge cases such as 01/01/20 which could map to either 1920 or 2020, but dates like 01/01/50 should definitely map to 1950.
Sample data and outputs:
01/01/56 -- output would be 1956-01-01 as date
01/01/08 -- output would be 2008-01-01 as date
01/01/21 -- output would be 2021-01-01 as date (* some would want 1921 here)
07/01/21 -- output would be 1921-07-01 as date (since as of posting 07/01/2021 would be in future)
**The outuput format isn't crucial, it could be 01/01/1956, just so it is a true 'date' in Athena Trino.**
One way would be to subtract 100 years whenever the parsed date is in the future. For example:
select case when
parse_datetime(birthdate, 'MM/dd/yy') > current_timestamp then
parse_datetime(birthdate, 'MM/dd/yy') - interval '100' year
else parse_datetime(birthdate, 'MM/dd/yy')
end as birthdate
Note that this would work only until the next century.
The parse_datetime function returns a timestamp object, see the docs: https://prestodb.io/docs/current/functions/datetime.html
parse_datetime uses java's DateFormat conventions. From the docs:
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
For parsing with the abbreviated year pattern ("y" or "yy"), SimpleDateFormat must interpret the abbreviated year relative to some century. It does this by adjusting dates to be within 80 years before and 20 years after the time the SimpleDateFormat instance is created.

Date_Trunc and To_Date Questions SQL

Can we use date_trunc for a date (not date-time) that we are trying to "truncate" (not sure if the term can be applied here) to e.g. the start of the week? So if I have date_trunc(week, 28/10/2020) and I want to get the start of the week that 28th of October lies in (so 26th of October)? I tried this in my SQL command line but I get error messages.
If I am doing: SELECT to_date ('02 Oct 2001', 'DD Mon YYYY'); How can I ensure the resulting format is in a date format I specify (rather than the default date format)? For example if I want it in format DD-MM-YYYY?
select to_char(date '2017-06-02', 'MM') < in this example, why do we need "date" for this to work? The general format for to_char should be TO_CHAR (timestamp_expression, 'format'). I don't see in this general format that we need "day".
if I have a WHERE filter like to_char(order_date, '20-10-2020'), and there are indeed some rows with this order date, will these rows still show in my results (after running query) if these rows are in DATE format (so 20 Oct is in date format) as opposed to string (which is what I am filtering by as I am doing to_char). I know there would be no need to use to_char in this case but just asking..
yes, you can use date in text form but you have to cast it to a correct type
these queries will work
select date_trunc('week', '2020-10-28'::date);
select date_trunc('week', '10/28/2020'::date);
-- as well as
select date_trunc('week', '2020-10-28'::datetime);
and return timestamp 2020-10-26 00:00:00.000000
note, next query
select date_trunc('week', '28/10/2020'::date);
will fail with error date/time field value out of range: "28/10/2020";
You can use to_char, it returns text, if you need a date format you have to case it again
select to_char( to_date ('02 Oct 2001', 'DD Mon YYYY'), 'DD-MM-YYYY')::date;
select to_char('02 Oct 2001'::date, 'DD-MM-YYYY')::date;
'2017-06-02' is a text and it can't be automatically converted to timestamp. Actually I don't know a text format which can.
No, you need to explicitly cast into date type to use it as a filter
where order_date = date_stored_as_a_text::date
I am answering the questions in a different order as there are some wrong assumptions:
Question 3
There is a general difference between '2017-06-02' and date '2017-06-02' - the first one is just a varchar, a string, NOT handled as a date by Redshift, the 2nd one tells Redshift to handle the string as date and therefore works.
Question 2
A date data type column has no format - you may an sql client that can display date columns in different formats, however, this is not a functionality of redshift. SELECT to_date ('02 Oct 2001', 'DD Mon YYYY'); tells redshift to convert the string '02 Oct 2001' to date.
Question 1
DATE_TRUNC('datepart', timestamp) also supports week as datepart - see Date parts for date or timestamp function (Also shown in the example of AWS). You should also be able to provide a date instead of a timestamp.
Question 4
to_char(order_date, '20-10-2020')is not a filter and you are using it wrong.
AWS TO_CHAR
TO_CHAR converts a timestamp or numeric expression to a character-string data format.
I guess you are rather looking for:
where to_char(order_date, 'YYYY-MM-DD') = '20-10-2020'

HOW TO FETCH DATA BETWEEN 2 DATES IN ORACLE SQL DEVELOPER

I'm new to oracle sql . I want to fetch data between 2 dates .
Date is in this format in db : 13-DEC-10
This is the query I have written but its giving me error . How to proceed next
select sum(TOTAL_AMOUNT) from table a
where trn_date between
TO_DATE(01-APR-17, 'DD-MON-YYYY') AND TO_DATE(31-MAR-17, 'DD-MON-YYYY') ;
A date does not have a format - it is stored internally to the database as 7-bytes (representing year, month, day, hour, minute and second) and it is not until whatever user interface you are using (i.e. SQL/Plus, SQL Developer, Java, etc) tries to display it to you, the user, and converts it into something you would find meaningful (usually a string) that the date has a format.
To fix your query you just need to surround the date string in single quotes and to use YY to match the 2-digit year format (otherwise Oracle will assume that 17 in the format YYYY is the year 0017 and the century will not be as you expect):
select sum(TOTAL_AMOUNT)
from table a
where trn_date between TO_DATE('01-APR-17', 'DD-MON-YY')
AND TO_DATE('31-MAR-17', 'DD-MON-YY');
However, you can also use date literals (and skip having to match the date format model):
select sum(TOTAL_AMOUNT)
from table a
where trn_date between DATE '2017-04-01'
AND DATE '2017-05-31';
Alternatively you may use the year format of RR format against centurial problems, Don't forget to keep quotes for date values, and you may prefer calling sql with bind variables :
select sum(TOTAL_AMOUNT)
from table a
where trn_date between
TO_DATE('&date_1', 'DD-MON-RR') AND TO_DATE('&date_2', 'DD-MON-RR') ; -- where date_1 is 31-MAR-17 and date_2 is 01-APR-17, in your case.
What I mentioned by centurial problems :
The RR Datetime Format Element
The RR datetime format element is similar to the YY datetime format
element, but it provides additional flexibility for storing date
values in other centuries. The RR datetime format element lets you
store 20th century dates in the 21st century by specifying only the
last two digits of the year.
If you use the TO_DATE function with the YY datetime format element,
then the year returned always has the same first 2 digits as the
current year. If you use the RR datetime format element instead, then
the century of the return value varies according to the specified
two-digit year and the last two digits of the current year.
That is:
If the specified two-digit year is 00 to 49, then
If the last two digits of the current year are 00 to 49, then the
returned year has the same first two digits as the current year.
If the last two digits of the current year are 50 to 99, then the
first 2 digits of the returned year are 1 greater than the first 2
digits of the current year.
If the specified two-digit year is 50 to 99, then
If the last two digits of the current year are 00 to 49, then the
first 2 digits of the returned year are 1 less than the first 2 digits
of the current year.
If the last two digits of the current year are 50 to 99, then the
returned year has the same first two digits as the current year.

how to get the exact year from the given date in oracle if it has a minimal format to base from?

how to get the exact "year" from oracle data if the given data is in this format?
02-FEB-84
I want to get the year, but when I do something like this
case
when dob is not null then to_date(dob,'YYYY')
when dob is null then '""'
end
as yearofbirth
I am getting the value of
2084
when I was expecting
1984
how to solve this?, because my query is not smart enough to determine if the year is from the 19th century or 20th century
Assuming DOB is varchar2() having date in format DD-MON-YY,
You might be looking for
TO_CHAR(TO_DATE(DOB,'DD-MON-RR'),'YYYY')
Conversion using YY format! Current century is 20** so, 84 -> 2084
SQL> SELECT TO_CHAR(TO_DATE('02-FEB-84','DD-MON-YY'),'YYYY') FROM DUAL;
TO_C
----
2084
Conversion using RR format! Current century is 20** and year is < 2050 so, 84 -> 1984
SQL> SELECT TO_CHAR(TO_DATE('02-FEB-84','DD-MON-RR'),'YYYY') FROM DUAL;
TO_C
----
1984
One more condition to your case statement should do it.
case
when to_date(dob) > sysdate then to_date(dob,'YYYY') - 100
when dob is not null then to_date(dob,'YYYY')
when dob is null then '""'
end
as yearofbirth
It's tricky, for example:
TO_DATE('16/06/66','DD/MM/RRRR')
16/06/1966
TO_DATE('16/06/16','DD/MM/RRRR')
16/06/2016
TO_DATE('16/06/16','DD/MM/RRRR')
16/06/1916
For the RRRR mask a value between 0-49 will return a 20xx year. A value between 50-99 will return a 19xx year.
You just hit the Y2K bug. You need to use the 'RR' format to get the proper YEAR result in 2 digits.
If you have used 'RR' format than it understands it as 1984 and if you have use 'YY' format it understands as 2084.
In general A value between 0-49 will return a 20xx year.
A value between 50-99 will return a 19xx year.
select to_date('84','RR') from dual
Always, remember, an year must be YYYY(4 digits) and not YY. The world has already spent too much time fixing the Y2K bug.
You can read more about 'RR' format here http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#SQLRF00215
Update : You need to use to_char if you want to display the year using 'RR' format.
Select to_char(dob,'RR') from table
I assume your dob column is DATE data type. A date must always be DATE data type and NOT string. Else, you need to first convert the literal into date and use to_char over it with 'RR' format.
TO_CHAR(YOUR_TABLE_DATA_COLUMN,'YYYY')

Formatting value of year from SYSDATE

I want to insert the current date into one of the columns of my table. I am using the following:
to_date(SYSDATE, 'yyyy-mm-dd'));
This is working great, but it is displaying the year as '0014'. Is there some way that I can get the year to display as '2014'?
Inserting it as TRUNC(sysdate) would do. Date actually doesn't have a format internally as it is DataType itself. TRUNC() actualy will just trim the time element in the current date time and return today's date with time as 00:00:00
To explain what happened in your case.
say ur NLS_DATE_FORMAT="YY-MM-DD"
The Processing will be like below
select to_date(to_char(sysdate,'YY-MM-DD'),'YYYY-MM-DD') from dual;
Output:
TO_DATE(TO_CHAR(SYSDATE,'YY-MM-DD'),'YYYY-MM-DD')
January, 22 0014 00:00:00+0000
2014 - gets reduced to '14' in first to_char() and later while converted again as YYYY.. it wil be treated as 0014 as the current century detail is last!
to_date is used to convert a string to a date ... try to_char(SYSDATE, 'yyyy-mm-dd') to convert a date to a string.
The to_date function converts a string to a date. SYSDATE is already a date, so what this will do is to first convert SYSDATE to a string, using the session's date format as specified by NLS settings, and then convert that string back to date, using your specified date format (yyyy-mm-dd). That may or may not give correct results, depending on the session's NLS date settings.
The simple and correct solution is to skip the to_date from this and use SYSDATE directly.
Try this to_date(SYSDATE, 'dd-mm-yy')