First time using Oracle SQL (I'm used to MySQL). I'm finding conflicting info on what the default date format is. After several attempts having to use TO_DATE with my INSERT INTO my_table statements, I finally found the database I'm using expects DD-MON-YY (i.e. 25-JAN-18). Yet on various pages here in stackoverflow and elsewhere, I see some that say default is YYYYMMDD or DD/MM/YYYY or YYYY-MM-DD. Why so many conflicting pieces of information?
4 Answers
A DATE has no format - it is stored internally as 7-bytes representing year (2 bytes) and month, day, hour, minute and second (1 byte each).
'25-JAN-18' is not a date - it is a text literal.
When you do:
INSERT INTO table_name ( date_column ) VALUES ( '25-JAN-18' );
Oracle will try to be helpful and perform an implicit cast from a string to a date using the NLS_DATE_FORMAT parameter for the user's session as the format model. So, your statement will be implicitly converted to:
INSERT INTO table_name ( date_column ) VALUES (
TO_DATE(
'25-JAN-18',
( SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT' )
)
);
Any user can set their NLS parameters in their own session (so you should never rely on implicit conversion as each user can have a different settings for their own session and can change the values mid-session). Instead you should:
Use a Date literal:
DATE '2018-01-25'Use a Timestamp literal
TIMESTAMP '2018-01-25 01:23:45'Use
TO_DATE( date_string, format_string [, nls_values] )and explicitly use a format model:TO_DATE( '25-JUN-18', 'DD-MON-RR' )
If you do want to change the NLS_DATE_FORMAT in your session then you can use:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
What the default date format is?
Since a DATE does not have a format, this question does not make sense. Instead if we ask:
What is the default
NLS_DATE_FORMATsession parameter that Oracle uses to convert between strings and dates?
It depends on the NLS_TERRITORY session parameter (so it depends where you are in the world):
SET SERVEROUTPUT ON;
VARIABLE cur REFCURSOR;
DECLARE
territories SYS.ODCIVARCHAR2LIST;
formats SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
select value
BULK COLLECT INTO territories
from v$nls_valid_values
where parameter = 'TERRITORY'
order by value;
formats.EXTEND( territories.COUNT );
FOR i IN 1 .. territories.COUNT LOOP
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_TERRITORY='''||territories(i)||'''';
SELECT value
INTO formats(i)
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT';
END LOOP;
OPEN :cur FOR
SELECT CAST( f.format AS VARCHAR2(12) ) AS format,
LISTAGG( t.territory, ', ' ) WITHIN GROUP ( ORDER BY t.territory ) AS territories
FROM ( SELECT ROWNUM AS rn, COLUMN_VALUE AS territory FROM TABLE( territories ) ) t
INNER JOIN
( SELECT ROWNUM AS rn, COLUMN_VALUE AS format FROM TABLE( formats ) ) f
ON ( f.rn = t.rn )
GROUP BY f.format;
END;
/
PRINT :cur;
Outputs the date format and the list of territories corresponding to that format:
FORMAT TERRITORIES
------------ ------------------------------------------------------------------
DD MON RRRR THAILAND
DD-MM-RR ALGERIA, BAHRAIN, INDIA, MOROCCO, THE NETHERLANDS, TUNISIA
DD-MM-RRRR BANGLADESH, INDONESIA, ROMANIA, VIETNAM
DD-MON-RR AMERICA, CHINA, HONG KONG, IRELAND, ITALY, PAKISTAN, TAIWAN,
UNITED KINGDOM
DD-MON-RRRR ISRAEL
DD.MM.RR AUSTRIA, BELARUS, CIS, CROATIA, CZECH REPUBLIC, CZECHOSLOVAKIA,
GERMANY, RUSSIA, SLOVAKIA, SLOVENIA, SWITZERLAND
DD.MM.RRRR ALBANIA, AZERBAIJAN, ESTONIA, FINLAND, FYR MACEDONIA, ICELAND,
KAZAKHSTAN, MACEDONIA, NORWAY, SERBIA AND MONTENEGRO, UKRAINE,
YUGOSLAVIA
DD.MM.RRRR. MONTENEGRO, SERBIA
DD.fmMM.RRRR ARMENIA
DD/MM/RR AFGHANISTAN, BELGIUM, BRAZIL, CAMEROON, CATALONIA, CHILE, COLOMBIA,
CONGO BRAZZAVILLE, CONGO KINSHASA, COSTA RICA, CYPRUS, DJIBOUTI,
EGYPT, EL SALVADOR, FRANCE, GABON, GREECE, GUATEMALA, HONDURAS,
IRAQ, IVORY COAST, JORDAN, KUWAIT, LEBANON, LIBYA, LUXEMBOURG,
MAURITANIA, MEXICO, NEW ZEALAND, NICARAGUA, OMAN, PANAMA, PERU,
PUERTO RICO, QATAR, SAUDI ARABIA, SINGAPORE, SOMALIA, SPAIN, SUDAN,
SYRIA, UNITED ARAB EMIRATES, URUGUAY, VENEZUELA, YEMEN
DD/MM/RRRR ARGENTINA, BAHAMAS, BERMUDA, ECUADOR, MALAYSIA, SENEGAL, TURKEY,
UGANDA, ZAMBIA
DD/MON/RR AUSTRALIA, SOUTH AFRICA, UZBEKISTAN
DD/fmMM/RRRR LAOS, NIGERIA
MM/DD/RRRR PHILIPPINES
RR-MM-DD CANADA, DENMARK, JAPAN
RR-MON-DD HUNGARY
RR.MM.DD PORTUGAL
RR/MM/DD KOREA, POLAND
RRRR-MM-DD BULGARIA, SWEDEN
RRRR-fmMM-DD CAMBODIA
RRRR.MM.DD LATVIA, LITHUANIA
RRRR/fmMM/fm IRAN, SRI LANKA
fmDD-MM-RR BOLIVIA
fmDD/MM/RR PARAGUAY
fmDD/MM/RRRR BELIZE, ETHIOPIA, MALTA, NEPAL
fmDD/fmMM/RR MALDIVES
fmMM.DD.RRRR BOSNIA AND HERZEGOVINA
fmMM/DD/RRRR KENYA, TANZANIA
Comments
Oracle, as well as other databases, allows you to set the default format. Out of the box, the format is (typically) DD-MON-RR, where "RR" refers to a two-digit year. This is a pretty lousy format, from the perspective of ambiguity (two digit year?) and internationalization (for what countries is that actually the default?). But Oracle has been around a long, long time.
Standard formats are also defined by ISO, the International Standards Organization. They settled on something more like YYYY-MM-DD. Actually, the hyphens are optional, but I think they make the date much more readable.
Oracle accepts constants in this format, if you use DATE:
select DATE '2018-01-25'
This is very handy. First, it is nice to support reasonable standards. Second, the code is safe, regardless of internationalization settings. Oracle documentation of course covers this in detail; here is one place to start.
2 Comments
DD-MON-YY. In some territories it is DD-MON-RR but in others it is something completely different.DD-MON-YY is also bad for scripts running in multiple locales. A script with TO_DATE('01-JAN-01', 'DD-MON-YY'); will only work in English locales & a script with TO_DATE('01-ENE-01', 'DD-MON-YY') will only work in Spanish locales.DATEs are DATEs - the format determines how the DATE will be displayed when you query your data.
If you don't supply a format and use the TO_CHAR function, we will provide the DATE back in the default NLS_DATE_FORMAT - which is defined in the database, but can also be specified for your session.
For your session -
select * from NLS_SESSION_PARAMETERS
where PARAMETER = 'NLS_DATE_FORMAT';
Mine is 'DD-MON-YYYY', so when I query SYSDATE:
SQL> select sysdate from dual;
SYSDATE
-----------
03-MAY-2018
When working with DATEs, it's generally best practice NOT to assume a specific DATE format. So when both INSERT or SELECT data with DATEs, be EXPLICIT. For example.
SQL> drop table JUST_DATES;
Table JUST_DATES dropped.
SQL>
SQL> create table JUST_DATES (
2 DATE1 date
3 );
Table JUST_DATES created.
SQL>
SQL> insert into JUST_DATES values ( to_date('01-01-2018','MM-DD-YYYY') );
1 row inserted.
SQL>
SQL> select to_char(
2 DATE1,
3 'MON/DD/RR'
4 )
5 from JUST_DATES;
TO_CHAR(DATE1,'MON
------------------
JAN/01/18
Now, to answer your question - what's the default? Well, it depends.
It is derived from your NLS_TERRITORY (docs)
But, if you remember best practices, and you never assume what the default is, and you are explicit with your date formats when working with DATEs, you should be ok.
The best guide we have for this topic is our Globalization Support Guide. This is the section of interest to you.
Comments
Only thing you have to take care while inserting date using TO_DATE is how you parse it.
Example:
What will not work
to_date('31-03-2016','dd-mon-yyyy')
What will work
to_date('31-03-2016','dd-mm-yyyy')
to_date('31-Mar-2016','dd-Mon-yyyy')
The date you are passing to to_date and format should match.
31 - dd
Mar - Mon
2016 - yyyy
to_date()without a format mask - or better use ANSI SQL literalsdate '2018-01-25'ortimestamp '2018-05-04 08:06:00'`