Professional Documents
Culture Documents
The oracle DATE datatype column is used for storing point-in-time values (dates and times)
in a table. The DATE datatype stores the year (including the century), the month, the day, the
hours, the minutes, and the seconds (after midnight). Oracle can store dates in the Julian
era, ranging from January 1, 4712 BCE through December 31, 4712 CE (Common Era, or
'AD'). Unless BCE ('BC' in the format mask) is specifically used, CE date entries are the
default.
Oracle uses its own internal format to store dates. Date data is stored in fixed-length
fields of seven bytes each, corresponding to century, year, month, day, hour, minute,
and second. For input and output of dates, the standard Oracle date format is DD-MON-YY,
as follows: ’13-NOV-92’.
After that refreshing bit of technical writing how about we dig into the date field a little
bit. I have found that people have the problems with the DATE field in oracle databases.
The major issue is simply the name “DATE” most people go looking for a TIME
datatype and do not realize that the time is stored in the date field as well. The most
common mistake is people storing dates as a character field in a VARCHAR2 datatype
column. So I will delve into dates a little and hopefully make things a little easier for you
in the future. All examples are done on an Oracle 10gR2 database. From version 9i
onward there is also the TIMESTAMP column which has much more precision as well
the TIMESTAMP column can be created with built in time zone conversions. I will not
touching on the TIMESTAMP datatype at all in this document.
Table dropped.
SQL>
SQL> CREATE TABLE DATETEST
2 (DATECOL DATE)
3 /
Table created.
SQL>
SQL> INSERT INTO DATETEST (DATECOL) VALUES (TO_DATE('01-JAN-2006 08:18:23','DD-
MON-YYYY HH24:MI:SS'));
1 row created.
SQL> COMMIT;
Commit complete.
As the manual says by default the display for a date column is DD-MON-YY. You have
to remember that is just the display of the date, not actually how the date is stored. You
can set your session to show the date format the way you desire. This is done by issuing
For example
DATECOL
---------
01-JAN-06
Session altered.
DATECOL
-----------
01/JAN/2006
The above query shows the default layout of a date via SQL*Plus, as shown you can
change the default layout via database parameters or session parameters.
Alternatively you can use the TO_CHAR function to display the date in a myriad of
formats. This does not show all of the possible format masks available. Please check the
documentation for all of the hundreds of possible combinations.
You can spell the date out in words.
DATECOL
-----------------------------
Sunday , January 1st 2006
DATECOL
-----------------
01-JAN-2006 08 am
DATECOL
----------
01/01/2006
DATECOL
----------
01/01/2006
DATECOL
-----------
01-JAN-2006
When you format the date, you have the capability of putting in almost any delimiter
between the possible formats as you wish.
DATECOL
-------------
2006~!~01$#01
You can ignore the date and simply display the time.
DATECOL
--------
08:18:23
GUI’s such as SQL Navigator and SQL Developer have a default date format that you
want to see. You must take care when setting those as it is possible to have the GUI
override format masks you apply to dates.
When you have a character field you wish to display as a date, the function TO_DATE is
what you need. The quickest way to show this is to create a quick view that converts
characters to a date format.
View created.
SQL> desc text2date
Name Null? Type
----------------------------------------------- -------- -------------------
TEXT2DATE DATE
TEXT2DATE
---------
05-JAN-06
TEXT2DATE
---------
Thursday
You can see that the text field is converted to a true date format in the view and you can
then manipulate it as you see fit. When you are converting text to a date, you must match
the format of TO_DATE function exactly with the text you are passing in. Even a small
mistake will cause an error.
TO_DATE('
---------
09-JAN-06
Elapsed: 00:00:00.00
SQL> select to_date('09-JAN-2006','DD-MON-YY') from dual;
TO_DATE('
---------
09-JAN-06
Date Math
Getting the difference between Dates
Doing math with dates is remarkably easy but seems a little complicated at the beginning.
I need a new base data set, so here it is.
1 row created.
SQL> commit;
Commit complete.
START_DATE END_DATE
-------------------- --------------------
01-OCT-2006 13:00:00 01-OCT-2006 14:00:00
First thing we will work on is finding the difference between two dates
SQL> select end_date-start_date from datemath;
END_DATE-START_DATE
-------------------
.041666667
Since we know that it is the number of days that is shown between to dates and there is
24 hours in a day, multiply the outcome to get the number of hours.
HOURS
----------
1
MINUTES
----------
60
SECONDS
----------
3600
If you want more detail on your date math for periods that are maybe longer than a day,
you can do it very easily but with a fair amount of typing. First thing we need some more
test data.
SQL> commit;
Commit complete.
SQL>
I had to shrink the font on the output so it would all fit on one line. You can see now you
know the exact time between the two dates.
Adding or subtracting time to a date is similar to working out the difference between.
When you add a number to a date, oracle assumes that number is in days, or part thereof.
START_DAT
---------
01-OCT-06
You can easily add or subtract any combination of time you need
Session altered.
SQL> select
2 ,start_date,start_date+(1/24) onehour
3 ,start_date+(1/24/60) oneminute
4 ,start_date+(1/24/60/60) onesecond
5 from datemath;
The common question is “Why use a date field? We only want to store a date for a day,
VARCHAR makes more sense”.
Admittedly at first glance using a VARCHAR field to store just a date looks pretty darn
attractive. You don’t have to worry about formatting during queries or reports and not
standard configuration on the client end won’t cause data problems, for example if the
GUI was configured to read the date formatting of the local windows PC. I will do some
very simple tests to show why there is a problem with using VARCHAR2 as a date field.
That means we get to create a new test table! Don’t you feel excited? I do!
SQL> CREATE TABLE DATETEST
2 (ID NUMBER PRIMARY KEY
3 ,TEXT_DATE VARCHAR2(17)
4 ,REAL_DATE DATE
5 );
Table created.
61 rows created.
SQL> COMMIT;
Now we have two months worth of data with a random time entry for every day of each
month. Now to start with a simple query on the table and order by the TEXT_DATE
column.
ID TEXT_DATE REAL_DATE
---------- ----------------- ---------
31 01-JUL-2006 13:03 01-JUL-06
1 01-JUN-2006 13:14 01-JUN-06
32 02-JUL-2006 04:36 02-JUL-06
2 02-JUN-2006 15:43 02-JUN-06
33 03-JUL-2006 08:03 03-JUL-06
3 03-JUN-2006 11:05 03-JUN-06
<results removed>
59 29-JUL-2006 21:42 29-JUL-06
29 29-JUN-2006 17:21 29-JUN-06
60 30-JUL-2006 14:16 30-JUL-06
30 30-JUN-2006 02:07 30-JUN-06
61 31-JUL-2006 04:08 31-JUL-06
61 rows selected.
That is very interesting, according to our query the 1st of July comes before the 1st of
June. Must be a calendar I am unfamiliar with. This outcome was to be expected
because as we all know, text sorts differently than date. Now some of you may be saying
“you chose that date format on purpose to fail”. Well, no not really, eventually they all
fail unless you choose MMDDYYYYHH24MISS format then the readability and not to
format the output benefits.
ID TEXT_DATE REAL_DATE
---------- ----------------- ---------
1 01-JUN-2006 13:14 01-JUN-06
2 02-JUN-2006 15:43 02-JUN-06
3 03-JUN-2006 11:05 03-JUN-06
4 04-JUN-2006 10:54 04-JUN-06
5 05-JUN-2006 09:44 05-JUN-06
6 06-JUN-2006 01:15 06-JUN-06
<results removed>
58 28-JUL-2006 15:44 28-JUL-06
59 29-JUL-2006 21:42 29-JUL-06
60 30-JUL-2006 14:16 30-JUL-06
61 31-JUL-2006 04:08 31-JUL-06
61 rows selected.
Now if we use a predicate to find the data, first on the TEXT_DATE column.
no rows selected
ID TEXT_DATE REAL_DATE
---------- ----------------- ---------
10 10-JUN-2006 03:28 10-JUN-06
11 11-JUN-2006 11:40 11-JUN-06
12 12-JUN-2006 16:18 12-JUN-06
<results removed>
29 29-JUN-2006 17:21 29-JUN-06
30 30-JUN-2006 02:07 30-JUN-06
31 01-JUL-2006 13:03 01-JUL-06
22 rows selected.
Conclusion
The DATE datatype is very easy to work with once you understand the basics and you
can quickly and efficiently manipulate the DATE field in the output format you desire
and do calculations between 2 dates. Use DATE columns to store dates and times
because generally the DATE column is much more efficient and easier to work with than
using VARCHAR2 or NUMBER fields to store a date . There are probably some
particular cases that can devised when using a VARCHAR2 field to store a date value, or
even using a NUMBER field to choose a date value may be more efficient that a DATE
field but those examples would be the exceptions to the rule.