Oracle to_date SQL formatting odd behavior - sql

I've trawled the SO website thinking this is pretty obvious but alas I have not found one yet.
Basically the setup is as follows:
I have a string in a table like so:
06/22/2010 00:00:00
I do a select on it:
SELECT To_Date(item, 'MM/DD/YYYY HH24:MI:SS') from that_table
so that effectively I am doing
SELECT To_Date('06/22/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS') from that_table
My database returns:
22.06.2010 00:00:00
Now I know I can do a
to_char(to_Date('06/22/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 'MM/DD/YYYY HH24:MI:SS')
but I need the select to return a date format (MM/DD/YYYY HH24:MI:SS), not a string. How can I do that?
Edit:
Real output:
22.06.2010 00:00:00
Desired output (in Date format):
06/22/2010 00:00:00

A DATE doesn't have a format, it is only formatted when converted to a character string for display purposes. If you are using SQL Plus then when you display a DATE column (without using TO_CHAR to explicitly format it), SQL Plus itself performs a TO_CHAR conversion using the NLS_DATE_FORMAT setting:
SQL> select sysdate from dual;
SYSDATE
---------
23-JUN-10
SQL> alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
Session altered.
SQL> select sysdate from dual;
SYSDATE
-------------------
2010-06-23 15:17:12
If you are not using SQL Plus, then whatever tool you are using will be doing something similar and may have a different way to specify the date format for display.

a Date is a point in time, it has no format (like numbers: they don't have format). When you display the date, obviously it has to get a format: if you don't specifically give Oracle a format, the default format for your session will be used (session parameter NLS_DATE_FORMAT).
In consequence: use the DATE datatype for date arithmetics and storage (no format). Use the to_char function or something equivalent when you need to display the date (in a report or in the GUI).

Related

TO_UTC_TIMESTAMP_TZ not returning Month name [duplicate]

I firstly run the following command, and get the following result:
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(SYSTIMESTAM
-------------------
2018-07-10 10:21:40
This is the format I want to have a TIMESTAMP object stored in.
When I convert it back though, it does not come in the format I want:
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
-------------------------------
10-JUL-18 10.21.40.000000000 AM
In fact, it changes 2018 to be at the end, sets 07 to be "JUL" and the 10 is now at the front. Also the time is separated by dots, has many 0's and an AM.
How can I fix this? I am new to SQL development so I am not sure about the formatting.
Thank you so much
As #Gordon said, timestamps (and dates) are not stored in a format you would recognise Oracle uses an internal representation that you never really need to know about or examine (but it is documented if you're interested in that sort of thing).
When you query a timestamp it is displayed using your client's NLS settings, unless you have a client that overrides those. I can set my session up to match what you are seeing:
alter session set nls_timestamp_format = 'DD-MON-RR HH.MI.SS.FF AM';
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(SYSTIMESTAM
-------------------
2018-07-10 15:37:31
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
-------------------------------
10-JUL-18 03.37.31.000000000 PM
And I can change it see what you want to see:
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS';
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHA
-------------------
2018-07-10 15:37:32
But all you are doing is converting from a timestamp with time zone (which is what systimestamp is) to a string and then back to a timestamp. You are losing the time zone portion, and any fractional seconds; which you could also do with a cast:
select cast(systimestamp as timestamp(0)) from dual;
CAST(SYSTIMESTAMPAS
-------------------
2018-07-10 15:37:32
You can see the timezone and fraction seconds with your default timestamp_tz format:
select systimestamp from dual;
SYSTIMESTAMP
------------------------------------
2018-07-10 15:37:33.776469000 +01:00
and change it with a different alter:
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM';
select systimestamp from dual;
SYSTIMESTAMP
------------------------------
2018-07-10 15:37:34.070 +01:00
Which isn't entirely relevant if you're really talking about storing timestamps in a table, but shows that there are variations.
In your table make the data type timestamp (or timestamp with time zone or timestamp with local time zone), and only worry about formatting the value as a string for presentation to the end user, at the last possible moment.
When you do need to display it, if the display format is important to you then use to_char() with an explicit format mask - do not assume that anyone else running your queries will have the same NLS settings. As you can see, it's easy to change those to modify the output. (Most clients have a way to let you set the defaults so you don't have to do the same alter commands every time you connect; e.g. in SQL Developer, from Tools->Preferences->Database->NLS). If you want to always show the same format then use something like:
select to_char(your_column, 'YYYY-MM-DD HH24:MI:SS') as column_alias
from your_table
where your_column < timestamp '2018-01-01 00:00:00'
which also shows the column value being filtered (as a timestamp still) using a timestamp literal.
This is the format I want to have a TIMESTAMP object stored in.
This is a common misconception - timestamp (and date) data types do not have a format; they are stored in the database as 20 bytes (or 7 bytes for dates) representing:
year (2 bytes),
month, day, hour, minute, integer seconds (1 bytes each),
fractional seconds (4 bytes),
time zone offset hours (1 byte),
time zone offset minutes (1 byte),
other data (including time zone location) (7 bytes)
You can see the bytes using the DUMP function:
SELECT DUMP( your_timestamp_column ) FROM your_table;
The database will operate on these 20 bytes without any format. But that would not be useful to display to you, the user, so the user interface you use to access the database (SQL/Plus, SQL Developer, Toad, Java, C#, etc) will receive those raw bytes from the database and will silently format them into a more intelligible format for you, the user.
What you are actually asking is:
How can I get the application I am using to access the Oracle database to change the default format it uses to display TIMESTAMP data types?
For SQL/Plus (and SQL Developer) you can use the NLS_TIMESTAMP_FORMAT session parameter:
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Then:
SELECT SYSTIMESTAMP FROM DUAL;
Will output:
2018-07-10 16:24:53
However, this only sets the default format for your user's current session; other users can set their own parameters and can change the value during their session so you should not rely on this to provide a consistent formatting.
Instead, if you want to have a TIMESTAMP with a particular format then you should convert it to a datatype which can have a format - a string.
SELECT TO_CHAR( SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS' ) FROM DUAL;
Then it does not matter what the user changes their default timestamp format to - your values will always be formatted how you expect.
So based on your replies above it sounds like you may be trying to do something you don't actually need to do.
As Gordon mentioned, timestamps are stored in an internal format so you can do things with the values. If you have the field stored as a timestamp data type you don't need to care how it's formatted in the database, you just need to care about how it looks for your query at the end. You can display a date field using to_char and still use a date range if you have the query built correctly.
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS')
from dual
WHERE systimestamp <= current_timestamp;
I don't think it is possible to to display the timestamp as you've described without using to_char and losing the data type.

How do I get this timestamp in the format I want, Oracle SQL

I firstly run the following command, and get the following result:
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(SYSTIMESTAM
-------------------
2018-07-10 10:21:40
This is the format I want to have a TIMESTAMP object stored in.
When I convert it back though, it does not come in the format I want:
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
-------------------------------
10-JUL-18 10.21.40.000000000 AM
In fact, it changes 2018 to be at the end, sets 07 to be "JUL" and the 10 is now at the front. Also the time is separated by dots, has many 0's and an AM.
How can I fix this? I am new to SQL development so I am not sure about the formatting.
Thank you so much
As #Gordon said, timestamps (and dates) are not stored in a format you would recognise Oracle uses an internal representation that you never really need to know about or examine (but it is documented if you're interested in that sort of thing).
When you query a timestamp it is displayed using your client's NLS settings, unless you have a client that overrides those. I can set my session up to match what you are seeing:
alter session set nls_timestamp_format = 'DD-MON-RR HH.MI.SS.FF AM';
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_CHAR(SYSTIMESTAM
-------------------
2018-07-10 15:37:31
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHAR(SYSTIMESTA
-------------------------------
10-JUL-18 03.37.31.000000000 PM
And I can change it see what you want to see:
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS';
select to_timestamp(to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS') from dual;
TO_TIMESTAMP(TO_CHA
-------------------
2018-07-10 15:37:32
But all you are doing is converting from a timestamp with time zone (which is what systimestamp is) to a string and then back to a timestamp. You are losing the time zone portion, and any fractional seconds; which you could also do with a cast:
select cast(systimestamp as timestamp(0)) from dual;
CAST(SYSTIMESTAMPAS
-------------------
2018-07-10 15:37:32
You can see the timezone and fraction seconds with your default timestamp_tz format:
select systimestamp from dual;
SYSTIMESTAMP
------------------------------------
2018-07-10 15:37:33.776469000 +01:00
and change it with a different alter:
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM';
select systimestamp from dual;
SYSTIMESTAMP
------------------------------
2018-07-10 15:37:34.070 +01:00
Which isn't entirely relevant if you're really talking about storing timestamps in a table, but shows that there are variations.
In your table make the data type timestamp (or timestamp with time zone or timestamp with local time zone), and only worry about formatting the value as a string for presentation to the end user, at the last possible moment.
When you do need to display it, if the display format is important to you then use to_char() with an explicit format mask - do not assume that anyone else running your queries will have the same NLS settings. As you can see, it's easy to change those to modify the output. (Most clients have a way to let you set the defaults so you don't have to do the same alter commands every time you connect; e.g. in SQL Developer, from Tools->Preferences->Database->NLS). If you want to always show the same format then use something like:
select to_char(your_column, 'YYYY-MM-DD HH24:MI:SS') as column_alias
from your_table
where your_column < timestamp '2018-01-01 00:00:00'
which also shows the column value being filtered (as a timestamp still) using a timestamp literal.
This is the format I want to have a TIMESTAMP object stored in.
This is a common misconception - timestamp (and date) data types do not have a format; they are stored in the database as 20 bytes (or 7 bytes for dates) representing:
year (2 bytes),
month, day, hour, minute, integer seconds (1 bytes each),
fractional seconds (4 bytes),
time zone offset hours (1 byte),
time zone offset minutes (1 byte),
other data (including time zone location) (7 bytes)
You can see the bytes using the DUMP function:
SELECT DUMP( your_timestamp_column ) FROM your_table;
The database will operate on these 20 bytes without any format. But that would not be useful to display to you, the user, so the user interface you use to access the database (SQL/Plus, SQL Developer, Toad, Java, C#, etc) will receive those raw bytes from the database and will silently format them into a more intelligible format for you, the user.
What you are actually asking is:
How can I get the application I am using to access the Oracle database to change the default format it uses to display TIMESTAMP data types?
For SQL/Plus (and SQL Developer) you can use the NLS_TIMESTAMP_FORMAT session parameter:
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Then:
SELECT SYSTIMESTAMP FROM DUAL;
Will output:
2018-07-10 16:24:53
However, this only sets the default format for your user's current session; other users can set their own parameters and can change the value during their session so you should not rely on this to provide a consistent formatting.
Instead, if you want to have a TIMESTAMP with a particular format then you should convert it to a datatype which can have a format - a string.
SELECT TO_CHAR( SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS' ) FROM DUAL;
Then it does not matter what the user changes their default timestamp format to - your values will always be formatted how you expect.
So based on your replies above it sounds like you may be trying to do something you don't actually need to do.
As Gordon mentioned, timestamps are stored in an internal format so you can do things with the values. If you have the field stored as a timestamp data type you don't need to care how it's formatted in the database, you just need to care about how it looks for your query at the end. You can display a date field using to_char and still use a date range if you have the query built correctly.
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS')
from dual
WHERE systimestamp <= current_timestamp;
I don't think it is possible to to display the timestamp as you've described without using to_char and losing the data type.

Oracle, finding data between two different dates

I have a table name as business_details and column name business_date whose data type is varchar2.
Now i have to find out the data between two different dates and date format like : 12-JUN-18 21:15:13
Means, 12 Jun, 2018.
Kindly help me to write a query which can fetch the data between these two dates :12-JUN-18 21:15:13 and 25-JUN-18 18:15:32
I assume that in table business_details you have an column date or something like that.
Than use something like this:
select business_date from business_details
where date between TO_DATE ('12-JUN-18 21:15:13','dd-MM-yy hh:mi:ss')
AND TO_DATE ('25-JUN-18 18:15:32','dd-MM-yy hh:mi:ss');
Assuming your business_date is actually a string in the format you've shown (and it isn't really a date your client is just showing in that format), you need to convert that to a date type, as well as converting the string literals.
select *
from business_details
where to_date(business_date, 'DD-MON-RR HH24:MI:SS')
between to_date('12-JUN-18 21:15:13', 'DD-MON-RR HH24:MI:SS')
and to_date('25-JUN-18 18:15:32', 'DD-MON-RR HH24:MI:SS');
The format model you tried to use in a comment did this:
to_date('12-JUN-18 21:15:13', 'DD-MM-YYYY HH24:MI:SS')
is using MM rather than MON, which works anyway by default - although using month numbers is safer anyway as they aren't dependent on your session language. But more importantly it uses YYYY. If you pass a 2-digit value like 18 and try to convert with YYYY you get the wrong year:
select to_date('12-JUN-18 21:15:13', 'DD-MON-YYYY HH24:MI:SS') form dual;
TO_DATE('12-JUN-182
-------------------
0018-06-12 21:15:13
In your version your business_date was being converted implicitly so would use NLS settings, which are presumably using RR already. But that means you were comparing a date in 2018 with a range in 0018, which is why nothing matched.
You could also use timestamp literals for the fixed values (unless those strings are actually being passed in from somewhere else):
select *
from business_details
where to_date(business_date, 'DD-MON-RR HH24:MI:SS')
between cast(timestamp '2018-06-12 21:15:13' as date)
and cast(timestamp '2018-06-25 18:15:32' as date);

Convert string to date in Oracle SQL

I'm trying to convert string column to date in Oracle SQL.
Here is my an example of value from the data:
'03/12/14 11:00:00'
Here is my query:
select to_date(A,'DD/MM/YY HH24:MI:SS')
from MyTable
Here is an example of the output:
03-DEC-14
Why my query return only the date but not the hour?
Assuming you are using SQL*Plus (or SQL Developer) the default NLS_DATE_FORMAT is applied when a DATE value is displayed. To verify your current format you can run:
select value
from nls_session_parameters
where parameter = 'NLS_DATE_FORMAT';
To adjust this, run:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
Then you should see the time as well.
You are trying to DISPLAY the datetime value. Use TO_CHAR along with proper FORMAT MODEL.
For example,
select to_char(sysdate, 'mm/dd/yyyy hh24:mi:ss') from dual;
A DATE consists of both date and time portions. You just need to make sure you use appropriate format model to display it. Else, you end up with a format which depends on your locale-specific NLS settings.
You can use timestamp
select to_timestamp(A, 'DD/MM/YY HH24:MI:SS') from MyTable
If you want a query that returns the time portion of the date without having to alter the nls_date_format you can convert the date you got from the to_date function to a text representation (the default text representation is dd-Mon-yy as you found out) like this:
select to_char(
to_date(A,'DD/MM/YY HH24:MI:SS'),
''DD/MM/YY HH24:MI:SS')
from MyTable;
Ideally, column A of MyTable should have been defined as a date column instead of a varchar2 column. There are several reasons to do that; data integrity, and better SQL optimization.

How to change the date format from MM/DD/YYYY to YYYY-MM-DD in PL/SQL?

I have a date column in a table stored as MM/DD/YYYY format. I have to select and store the same date in another table in YYYY-MM-DD format i.e. XSD Date Format. But I am not able to do it. I am using this query:
select to_date(date_column,'YYYY-MM-DD') from table;
But still I am not able to do it. Giving me error
ORA-01843 : not a valid month
use
select to_char(date_column,'YYYY-MM-DD') from table;
It sounds like you've got it the wrong way round. If your existing data is in MM/DD/YYYY format, then you want:
select to_date(date_column,'MM/DD/YYYY') from table;
to convert the existing data to DATE values. (I do wonder why they're not stored as dates, to be honest...)
If you want to perform the conversion in one step, you might want:
select to_char(to_date(date_column,'MM/DD/YYYY'), 'YYYY-MM-DD') from table;
In other words, for each row, parse it in MM/DD/YYYY format, then reformat it to YYYY-MM-DD format.
(I'd still suggest trying to keep data in its "natural" type though, rather than storing it as text in the first place.)
I assume that you can use the Oracle SQL Developer, which you can download from here.
You can define the date format which you want to work with:
ALTER SESSION SET nls_date_format='yyyy-mm-dd';
With this, now you can perform a query like this:
SELECT * FROM emp_company WHERE JDate = '2014-02-25'
If you want to be more specific you can define the date format like this:
ALTER SESSION SET nls_date_format='yyyy-mm-dd hh24:mi:ss';
To convert a DATE column to another format, just use TO_CHAR() with the desired format, then convert it back to a DATE type:
SELECT TO_DATE(TO_CHAR(date_column, 'DD-MM-YYYY'), 'DD-MM-YYYY') from my_table
select to_date(to_char(ORDER_DATE,'YYYY/MM/DD'))
from ORDERS;
This might help but, at the end you will get a string not the date. Apparently,
your format problem will get solved for sure .
For military time formatting,
select TO_CHAR(SYSDATE, 'yyyy-mm-dd hh24:mm:ss') from DUAL
--2018-07-10 15:07:15
If you want your date to round DOWN to Month, Day, Hour, Minute, you can try
SELECT TO_CHAR( SYSDATE, 'yyyy-mm-dd hh24:mi:ss') "full-date" --2018-07-11 10:40:26
, TO_CHAR( TRUNC(SYSDATE, 'year'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-year"-- 2018-01-01 00:00:00
, TO_CHAR( TRUNC(SYSDATE, 'month'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-month" -- 2018-07-01 00:00:00
, TO_CHAR( TRUNC(SYSDATE, 'day'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-Sunday" -- 2018-07-08 00:00:00
, TO_CHAR( TRUNC(SYSDATE, 'dd'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-day" -- 2018-07-11 00:00:00
, TO_CHAR( TRUNC(SYSDATE, 'hh'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-hour" -- 2018-07-11 10:00:00
, TO_CHAR( TRUNC(SYSDATE, 'mi'), 'yyyy-mm-dd hh24:mi:ss') "trunc-to-minute" -- 2018-07-11 10:40:00
from DUAL
For formats literals, you can find help in
https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions242.htm#SQLRF52037
You can do this simply by :
select to_char(to_date(date_column, 'MM/DD/YYYY'), 'YYYY-MM-DD') from table
According to the comments, the data-type in the datatable is DATE.
So you should simply use:
"select date_column from table;"
Now if you execute the select you will get back a date data-type, which should be what you need for the .xsd.
Culture-dependent formating of the date should be done in the GUI (most languages have convenient ways to do so), not in the select-statement.
Basically , Data in a Date column in Oracle can be stored in any user defined format or kept as default.
It all depends on NLS parameter.
Current format can be seen by : SELECT SYSDATE FROM DUAL;
If you try to insert a record and insert statement is NOT in THIS format then it will give :
ORA-01843 : not a valid month error.
So first change the database date format before insert statements ( I am assuming you have bulk load of insert statements) and then execute insert script.
Format can be changed by :
ALTER SESSION SET nls_date_format = 'mm/dd/yyyy hh24:mi:ss';
Also You can Change NLS settings from SQL Developer GUI , (Tools > preference> database > NLS)
Ref: http://oracle.ittoolbox.com/groups/technical-functional/oracle-sql-l/how-to-view-current-date-format-1992815
This worked for me! You can convert to datatype you want be it a date or string
to_char(TO_DATE(TO_CHAR(end_date),'MM-DD-YYYY'),'YYYY-MM-DD') AS end_date
Late reply but for.databse-date-type the following line works.
SELECT to_date(t.given_date,'DD/MM/RRRR') response_date FROM Table T
given_date's column type is Date
Just to piggy back off of Yahia, if you have a timestamp you can use this function to cast exclusively as date, removing the timestamps.
TO_CHAR(CAST(DateTimeField AS DATE), 'YYYY-MM-DD') AS TrackerKey__C
Or in my case I need the below format
TO_CHAR(CAST(DateTimeField AS DATE), 'YYYYMMDD') AS TrackerKey__C
SELECT TO_DATE(TO_CHAR(date_column,'MM/DD/YYYY'), 'YYYY-MM-DD')
FROM table;
if you need to change your column output date format just use to_char this well get you a string, not a date.
use
SELECT STR_TO_DATE(date_column,'%Y-%m-%d') from table;
also gothrough
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html