Oracle: Date Format Problems YYYY-MM-DD - oracle

I have a problem that could seems naive (and could actually be naive) but I cannot solve...
The thing is that I'm trying to insert some data from Pentaho to a Oracle DB and in Pentaho I have my Date in format YYYY-MM-DD, but when in Oracle it appears YYYY-MM-DD 00:00:00. The point is that the format of the attribute is Date, and when I manually, through SQL, insert data into the table, it happens the same.
INSERT INTO TABLE1
VALUES(TO_DATE('2012-02-01','yyyy-mm-dd'))
When I visualize the data, I see again 2012-02-01 00:00:00.
I'm using Dbeaver, and when I go to Properties to see the Date format, it appears YYYY-MM-DD, so I don't understand what's happening neither how to solve it.
Thank you!

The date format visualized in the oracle depends on the NLS_DATE_FORMAT parameter. But please note that oracle does not store the Date in any format but it has its own binary representation for dates.
so you can configure how you want to see dates in your session or at the database level or at an instance level.
At session-level, You can alter NLS_DATE_FORMAT as follows:
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';
Session altered.
SQL> SELECT SYSDATE FROM DUAL;
SYSDATE
----------
2020-11-27
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Session altered.
SQL> SELECT SYSDATE FROM DUAL;
SYSDATE
-------------------
2020-11-27 15:17:02
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY';
Session altered.
SQL> SELECT SYSDATE FROM DUAL;
SYSDATE
-----------
27-NOV-2020
SQL>
To check for the current value of NLS_DATE_FORMAT, You can use the following view:
SELECT * FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';
SELECT * FROM NLS_INSTANCE_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';

I would not rely on the NLS_DATE_FORMAT nls parameter (what if you have multiple queries which need to output the dates in different formats?). If you need to view your dates in a specific format, use to_char(), e.g.:
SELECT to_char(date_col, 'dd/mm/yyyy') date_col
FROM table1;

Related

I would like to keep my table's data type as date but I want my table to show date and time format in the same column

I would like to keep my table's data type as date but I want my table to show date and time in the same column.
This is what I have so far. How do I change the format? I use Oracle SQL.
insert into student
values
(001,
to_date('2018-02-02 21:05:18', 'YYYY-MM-DD HH24:MI:SS'),
'Oriel Road Brisbane',
103,
2486675,
760024,
'fdg57690gmig'
);
You don't have to do anything; that column already contains both date and time. It is the front-end that is supposed to display it as you want. Here are some examples:
SQL> create table test (datum date);
Table created.
SQL> insert into test (datum) values (to_date('2018-02-02 21:05:18', 'YYYY-MM-DD HH24:MI:SS'));
1 row created.
SQL> select * from test;
DATUM
--------
02.02.18
SQL> select to_char(datum, 'hh24:mi:ss') only_time,
2 to_char(datum, 'dd-mon-yy') date_format_1,
3 to_char(datum, 'yyyy-mm-dd hh24:mi:ss') date_and_time
4 from test;
ONLY_TIM DATE_FORMAT_1 DATE_AND_TIME
-------- ------------------ -------------------
21:05:18 02-vel-18 2018-02-02 21:05:18
SQL>
Which means: use TO_CHAR with appropriate format mask, if you use SELECT statement. If it is about e.g. Oracle Apex, Forms or Reports, modify item's format mask.
Alternatively, you may talk to DBA to change NLS settings for the whole database, or you can do it for your session:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select datum from test;
DATUM
-------------------
02.02.2018 21:05:18
Oracle's DATE datatype does store the date and time - there is not date-only datatype in Oracle, unlike some other databases, such as MySQL, that has DATE and DATETIME datatypes.
Your code is correctly inserting a date/time value in the table.
When Oracle displays a date, it uses by default the format defined by parameter NLS_DATE_FORMAT (which, for your database, is probably something that does not include the time portion).
You ca either change the setting at session level:
alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
Or you can use to_char() on the date column:
select to_char(mydatecol, 'yyyy-mm-dd hh24:mi:ss') as mydatestring
from mytable

Oracle: Why do I have to use TO_DATE to pull my data?

When trying to filter on EXPIRE_DATE, it seems I have to use TO_DATE. Why do I have to use TO_DATE? The EXPIRE_DATE data type in the database is ALREADY set to date. Here is the code that works.
SELECT * FROM MY_TABLE
WHERE EXPIRE_DATE >= TO_DATE('2020/01/13','yyyy/mm/dd')
AND EXPIRE_DATE <= TO_DATE('2020/04/19','yyyy/mm/dd')
I tried to use BETWEEN without TO_DATE and just use my dates but I received an error.
To recap, even though the data type for this is ALREADY date, it seems I have to use TO_DATE to pull my data when I want to filter. Is there something I am missing? Here is my error when I try filter my data without using TO_DATE.
Apart from some good answers here, I would like to tell you that you do not need TO_DATE to pull the data from your table.
You need to_date or date literal to convert the normal string to date which can be compared to the column data in your table, As the date column must be compared with the date data type variable/constant.
To convert normal string to date, You can use the following:
TO_DATE('2020/01/13','yyyy/mm/dd')
DATE '2020-01-13'
I would not recommend using NLS_DATE_FORMAT just for creating the date.
You don't need to use TO_DATE, instead you can use a DATE literal:
SELECT *
FROM MY_TABLE
WHERE EXPIRE_DATE >= DATE '2020/01/13'
AND EXPIRE_DATE <= DATE '2020/04/19'
Or, if your NLS_DATE_FORMAT session parameter matches YYYY/MM/DD then you can insert the values as strings and rely on implicit string conversion (don't do this though):
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY/MM/DD';
SELECT *
FROM MY_TABLE
WHERE EXPIRE_DATE >= '2020/01/13'
AND EXPIRE_DATE <= '2020/04/19'
But it is not good practice to rely on the NLS_DATE_FORMAT as ANY user can change their own value at ANY time so your query can randomly fail when users start changing these values.
You can use BETWEEN:
Warning: it's better to use always TO_DATE function with proper format string and avoid implicit conversions that in some occasions produces strange behaviors in the results.
Warning: all columns of type DATE have always the hour-minute-second component.
if you forget this you may have fewer records in the result.
Example:
create table my_table
(id number,
expire_date date
);
Some data:
insert into my_table values ( 4,to_date('2011-06-17 10:07:18','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (12,to_date('2010-10-01 17:43:30','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (13,to_date('2011-07-30 08:38:34','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (21,to_date('2010-04-22 07:03:35','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (26,to_date('2011-03-26 02:07:57','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (35,to_date('2010-09-16 17:40:01','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (38,to_date('2011-11-05 17:27:45','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (44,to_date('2011-12-25 04:51:24','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (45,to_date('2011-11-05 03:08:51','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (54,to_date('2011-09-22 18:29:14','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (78,to_date('2010-03-12 20:23:21','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (79,to_date('2011-05-19 17:30:15','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (83,to_date('2011-11-15 10:04:58','yyyy-mm-dd hh24:mi:ss'));
insert into my_table values (96,to_date('2011-03-11 20:14:30','yyyy-mm-dd hh24:mi:ss'));
Set default date format to ISO-8601 international format:
alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
Query using implicit conversion:
SELECT a.*
fROM my_table a
where expire_date between '2010-01-01 00:00:00'
and '2010-12-31 23:59:59';
Answer:
ID EXPIRE_DATE
12 2010-10-01 17:43:30
21 2010-04-22 07:03:35
35 2010-09-16 17:40:01
78 2010-03-12 20:23:21
but using US date format month-day-year:
SELECT a.*
fROM my_table a
where expire_date between '01/01/2010 00:00:00'
and '12/31/2010 23:59:59';
You got error:
ORA-01861: literal does not match format string
Change session date format to US format:
alter session set nls_date_format='MM-DD-YYYY HH24:MI:SS';
you can write dates in US format:
SELECT a.*
fROM my_table a
where expire_date between '01/01/2010 00:00:00'
and '12/31/2010 23:59:59';
And the answer is:
ID EXPIRE_DATE
---------- -------------------
12 10-01-2010 17:43:30
21 04-22-2010 07:03:35
35 09-16-2010 17:40:01
78 03-12-2010 20:23:21

Store time while inserting data into oracle table

In one of my column, I want to store time also in below condition. Here is the query below.
APPROVED_DATE = CASE WHEN PAPPROVED_BY IS NULL THEN NULL ELSE SYSDATE END,
how to add time part in SYSDATE here
It's already there; if you don't see it, it is because your NLS settings. Here's an example of what you might do: ALTER SESSION or use TO_CHAR:
SQL> create table test (approved_Date date);
Table created.
SQL> insert into test values (sysdate);
1 row created.
SQL> select * from test;
APPROVED
--------
05.01.18
SQL> select to_char(approved_Date, 'dd.mm.yyyy hh24:mi:ss') from test;
TO_CHAR(APPROVED_DA
-------------------
05.01.2018 10:37:38
SQL> alter session set nls_date_format = 'dd-mm-yyyy hh:mi:ss am';
Session altered.
SQL> select * from test;
APPROVED_DATE
----------------------
05-01-2018 10:37:38 AM
SQL>
you CASE code is running perfectly fine. you just need to change your display setting as sysdate already have time element in it.
if you are using PL/SQL go to
tools > preference > Date/Time
and change to format as per your requirement.
and while accessing this field use to_char(sysdate , 'DD/MM/YYYY hh24:mi:ss')

Use time in between in oracle for multiple date

Select *
from mytable
where paid_time Between to_date('00:00:00','HH24:MI:SS' ) and to_date('00:59:59','HH24:MI:SS')
and paid_date Between to_date('1/8/2016','DD/MM/RRRR') and
to_date('10/8/2016','DD/MM/RRRR');
Note :
1. I need perticular time period only for 10 days
Error :
1. data is there but returning Zero kindly help to solve this
You need to use the full date and time TO_DATE otherwise there is conflicting WHERE clauses'DD/MM/RRRR hh24:mi:ss'.
SELECT *
FROM mytable
WHERE paid_time BETWEEN TO_DATE('01/08/2016 00:00:00', 'DD/MM/RRRR hh24:mi:ss') AND TO_DATE('10/08/2016 00:59:59', 'DD/MM/RRRR hh24:mi:ss');
If paid_time is a string then your query will only work at all for certain NLS_DATE_FORMAT settings, due to the implicit conversion you are forcing:
alter session set nls_date_format = 'RRRR-MM-DD';
with mytable (paid_date, paid_time) as (
select date '2016-08-02', '00:01:02' from dual
)
Select *
from mytable
where paid_time Between to_date('00:00:00','HH24:MI:SS' ) and to_date('00:59:59','HH24:MI:SS')
and paid_date Between to_date('1/8/2016','DD/MM/RRRR') and
to_date('10/8/2016','DD/MM/RRRR');
no rows selected
alter session set nls_date_format = 'YYYY-MM-DD';
-- same query
ORA-01841: (full) year must be between -4713 and +9999, and not be 0
alter session set nls_date_format = 'DD/MM/RRRR';
-- same query
ORA-01847: day of month must be between 1 and last day of month
... etc.
When you do to_date('00:00:59','HH24:MI:SS') the generated date defaults to the first of the current month, so when run today it will get a September date:
select to_char(to_date('00:00:59','HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(TO_DATE('00
-------------------
2016-09-01 00:00:59
You are then trying to compare your paid_time string with that date, which means the string is implicitly converted to a date using your NLS settings, e.g.:
alter session set nls_date_format = 'RRRR-MM-DD';
select to_char(to_date('00:01:02'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(TO_DATE('00
-------------------
2000-01-02 00:00:00
So your filter is really looking for rows where the time string, incorrectly converted to a date (exactly which date depends on your actual NLS setting, and many values will error whatever the setting), is in the first minute of the first day of the current month. Which is very unlikely to ever match anything.
If it is a string and is always formatted consistently then you can just compare as a string:
with mytable (paid_date, paid_time) as (
select date '2016-08-02', '00:01:02' from dual
)
Select *
from mytable
where paid_time Between '00:00:00' and '00:59:59'
and paid_date Between to_date('1/8/2016','DD/MM/RRRR') and
to_date('10/8/2016','DD/MM/RRRR');
PAID_DATE PAID_TIM
---------- --------
2016-08-02 00:01:02
As mentioned in comments Oracle's data datatype includes the time, so storing the date (at midnight, presumably) and the time in separate columns just adds complexity and inefficiency.

How to get the first day of the week, depending on NLS

I want to get the date of the first day of the week but I want it to be dependant to NLS parameters. Say , when I run it on America it should give me Sundays date, but in Turkey it should give me Monday..
select trunc(to_date(sysdate,'dd-mm-yy'),'iw')from dual;
How can I make it dependant?
According to the documentation, trunc(sysdate, 'IW') gives you:
Same day of the week as the first day of the calendar week as defined by the ISO 8601 standard, which is Monday
As you've seen, that is clearly not NLS-dependent.
You might think using W would give you the non-ISO, NLS-dependent, version, but it does something different - the same day of the week as the first day of the month. So run now, that will give you Monday, regardless of your settings, since July 1st was a Monday.
So you need either D, DY or DAY - they all behave the same:
alter session set nls_territory = 'AMERICA';
select trunc(sysdate, 'D') from dual;
TRUNC(SYS
---------
14-JUL-13
alter session set nls_territory = 'TURKEY';
select trunc(sysdate, 'D') from dual;
TRUNC(SYSD
----------
15/07/2013
Incidentally, your original query is doing to_date(sysdate,'dd-mm-yy'). sysdate is already a date. You're forcing an implcit conversion from that date to a string, which will use your NLS_DATE_FORMAT, and then an explicit conversion back to a date using dd-mm-yy. Not only is that pointless, it would break if your NLS_DATE_FORMAT didn't match (roughly, there is quite a bit of leeway) the dd-mm-yy you use explicitly:
alter session set nls_date_format = 'dd/mm/yyyy';
select to_date(sysdate,'dd-mm-yy') from dual;
TO_DATE(SY
----------
18/07/2013
alter session set nls_date_format = 'dd-mon-rr';
select to_date(sysdate,'dd-mm-yy') from dual;
TO_DATE(S
---------
18-jul-13
alter session set nls_date_format = 'mm/dd/yyyy';
select to_date(sysdate,'dd-mm-yy') from dual;
select to_date(sysdate,'dd-mm-yy') from dual
*
ERROR at line 1:
ORA-01843: not a valid month
alter session set nls_date_format = 'yyyy-mm-dd';
select to_date(sysdate,'dd-mm-yy') from dual;
select to_date(sysdate,'dd-mm-yy') from dual
*
ERROR at line 1:
ORA-01861: literal does not match format string
... etc. And your NLS_DATE_FORMAT is inherited from NLS_TERRITORY by default, so this is likely to be an issue if you're expecting to deal with multiple regions anyway.
When u use iso week, it is same for all territories. It returns always mondays.
Instead of use this;
select sysdate your_date,
trunc(sysdate,'IW') iso_start_of_week,
to_char(sysdate,'D') your_territory_day,
trunc(sysdate)- to_char(sysdate,'D') + 1 this_is_what_u_want
from dual

Resources