I'm using an Oracle DB and I'm trying to fetch data from its tables using PHP. One of the tables contains a date column which behaves strange to me.
When I open the table in my DB client (I'm using Navicat Lite) I see dates like "2007-11-29 10:15:42" but when I retrieve them with PHP and display the date it says "29-NOV-07". I use a simple SQL query and standard PHP functions (oci_parse, oci_execute, oci_fetch_array).
Why is the value from the DB converted to this (useless) format? How can I get the date just like it is stored in the DB? Thanks for your tips!
Oracle DATE datatype is a point in time, it has no format attached. When you transform a date to a string (to display if for example), the format applied to the date will be dependent upon your session parameters (implicit conversion). From what I remember of PHP, the retrieval functions will convert the date to a string automatically, using the NLS_DATE_FORMAT session parameter.
Either:
change the NLS_DATE_FORMAT beforehand with:
ALTER SESSION SET NLS_DATE_FORMAT='yyyy-mm-dd hh24:mi:ss'
or, if you want to specify another format in your query, you should explicitely ask for it:
SELECT to_char(my_date, 'yyyy-mm-dd hh24:mi:ss') ...
Update
Thanks to ThinkJet for the link to the PHP documentation:
DATE columns are returned as strings formatted to the current date format. The default format can be changed with Oracle environment variables such as NLS_LANG or by a previously executed ALTER SESSION SET NLS_DATE_FORMAT command.
Related
I have a requirement where I have to insert date fields into a varchar column. I am directly inserting the record into the table without any typecast. In one environment it's inserting as 29-AUG-16, and in the other environment it's storing as 29-08-2016. Hence, my subsequent processing of the data is getting failed. I am expecting data as DD-MON-RR in both environment. In both environment nls format is DD-MON-RR in the nls session parameters table. What is the reason for the difference in two environment?
I tried typecast using TO_CHAR(DATECOL, 'DD-MON-RR' ) But still data is inserted as dd-mm-yyyy format
You can use TO_CHAR function to convert date into character and insert it into varchar column.
Instead of simply writing date_column , you should use something like this in your insert query
INSERT INTO date_tab VALUES(TO_CHAR(date_col, 'DD-MON-YY'))
NLS values are set per session depending on server defaults, client defaults and explicit session settings. So if you want a standard format for all sessions you have to set desired NLS at operation level to override all possible (almost unpredictible) NLS resulting combinations. In to_char function you should set the third parameter (NLS) to your selected NLS date format.
The date format in Oracle SQL Developer looks like DD-MON-YY.
For example 17-OCT-03.
The date format in APEX looks like MM/DD/YYYY.
For example 12/17/1980.
Why are they different?
This might cause the same SQL query not to work on both applications.
I know that I can avoid such problem by using TO_DATE and TO_CHAR functions but I want to understand the logic behind this problem.
Does every application use its own default date format?
Yes, every application has it's own date format.
And even every application can have more than one session, each with a different session format specified for DATEs and TIMESTAMPs.
SQL Developer has it's application level settings defined in the Preferences, Database, NLS page. This is how DATEs will appear unless you issue an ALTER SESSION SET... in your SQL Worksheet.
Or, if you always want a specific format regardless of this setting, build it into your query.
select to_char(sysdate, 'DAY') today from dual;
It's been my experience as well... YES, every Oracle application/tool can have its own default date format, but most just use the default display format set at the database level:
SQL> select name, value from v$parameter where name = 'nls_date_format';
NAME VALUE
--------------------- ---------------------
nls_date_format DD-Mon-YY
1 row selected.
But I would not characterize this as "a problem"... it is a valuable feature that provides lots of flexibility in displaying and entering dates in Oracle-based applications.
For sure though, if developers don't understand how Oracle dates work and write code such as this:
-- BAD Coding
DECLARE
ld_holiday_date DATE;
BEGIN
-- Set a date type variable to a string value and
-- hope that Oracle can figure out what I mean.
ld_holiday_date := '01-JAN-2022';
END;
they are writing environment specific code which will definitely not work in another database (or session) that has a different NLS_DATE_FORMAT from the one they wrote their code in. Furthermore, the code above is having to do an implicit data type conversion (from string to date) which is leaving it up to Oracle to try and figure out what format is in the string.
To write more deterministic code with regard to Oracle dates, developers should definitely use the TO_DATE function. Here's the bullet proof version of the code snippet above:
-- Good Coding
DECLARE
ld_holiday_date DATE;
BEGIN
-- I do not care what the NLS date format is in this
-- database... this code will work everywhere.
ld_holiday_date := TO_DATE ('01-JAN-2022', 'DD-MON-YYYY');
END;
I have DATETIME set as
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); in my getDateTime() method in my DTO class and this method returns a date with time. This is further used to create a CSV(Excel) file but when I run INSERT/UPDATE query in SQL developer, it throws an error if I use the format as YYYY:MM:DD HH:MM'. ForDD:MM:YYYY HH:MMit runs successfully. Also in some cases while creating CSV, the date field gets missed. I have also checked DB table and the format for DATE is set as DATE in there. Can anyone suggest the possible reason for
Error in SQL Dev while Updating/Inserting date as yyyy-MM-dd HH:mm
What the DATE field's format should be in SQL if my code has format as above. Or DATE should work just fine.
We are using Oracle as RDBMS. For running queries we use SQL Developer.
Take a look in your Tools => Preferences => Databases => NLS section in SQL Developer. It nominates the default date format (amongst other things) that the tool will expect. You can alter this to suit your needs.
There are a lot of misconceptions in the question:
I have DATETIME
Oracle does not have a DATETIME data type - it has DATE or TIMESTAMP both of which have a time component.
set as DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
A DATE (or TIMESTAMP) column does not have a format; Oracle stores DATE data types as 7-bytes (and similar for TIMESTAMP data types) and it is not until it is passed to a client program (i.e. SQL/Plus, SQL Developer, Toad, Java, Python, etc) and that client program formats it according to whatever rules it has that the date gets a format.
The default string format for dates in SQL/Plus or SQL Developer is set by the NLS_DATE_FORMAT session parameter. Other clients will typically have parameters that you can set for the default date format (if they don't also use the NLS settings). However, beware that the NLS_DATE_FORMAT is a session parameter so it belongs to the user's session and multiple users can each have a different value for the parameter corresponding to how they have set it.
If you have overridden the default date format settings in the SQL Developer IDE then you can change it in "Tools" > "Preferences" > "Database" > "NLS".
For DD:MM:YYYY HH:MM it runs successfully.
The format model MM (and mm as it is not case sensitive) is for month and HH is a 12-hour clock so you are specifying:
day:month:year hours-on-12-hour-clock:month
If you want to give a date a specific format then you will need to convert it to a string:
SELECT TO_CHAR( SYSDATE, 'MM/DD/YYYY HH24:MI' )
FROM DUAL;
or if you want to convert a string to a date then use:
SELECT TO_DATE( your_string, 'MM/DD/YYYY HH24:MI' )
FROM DUAL;
Also in some cases while creating CSV, the date field gets missed.
It probably is not missed - it is probably just NULL and gets formatted as an empty string.
I want to insert a datetime into a date field in oracle. I have up until now used sysdate, which works perfectly, however I need to use the same timestamp for something else.
Does anyone know how I can create a datetime variable that is compatible with oracle's date field? Everything I try causes errors.
I have tried variations along the lines of this:
Dim timestamp As DateTime = CDate(Now.ToString("yyyy/MM/dd HH:mm:ss"))
.......more code....
insertBuilder.Append("date = to_date(" & timestamp & ")")
First, you seem to be confused about the difference between a DateTime object and the formatted String representation of that DateTime object. Now, or even better, DateTime.Now is already a DateTime object, so it makes no sense to format it as a string and then parse the string to get it back into a DateTime value again. So, you can simply do this to accomplish the same thing:
Dim timestamp As Date = Date.Now
Note that in VB.NET, Date is a keyword that is short for DateTime, just as Integer is "short" for Int32.
Second, you should not be appending DateTime values directly into the SQL command string. You should be using a parameterized query. When you append the DateTime value to the SQL string, you must make sure it is formatted properly (by calling timestamp.ToString(...)). Unfortunately, however, which format is proper will depend entirely on the culture settings of the server. So, it is far better to use a DB parameter, set the parameter value equal to the actual DateTime object, and then let the DB provider do the conversion for you.
A parameterised query is a good start because you can pass a native .Net DateTime object into Enterprise Library (for example) and specify that it is of DbType.DateTime and let EL worry about it. However if you cannot do that because you aren't using EL or something similar and are stuck with using SQL strings as posted in your question then you need to be aware of how Oracle treats dates internally, particularly with regards to format.
Using SQL Developer or SQLPlus, execute the following:
Select To_Char(sysdate) from Dual;
The format which is displayed is the format which your Oracle instance expects dates to be in if you use To_Date and which Oracle will use in To_Char. If you deviate from that format in either call then you will get problems. However, regardless of the default format being used you can override it by specifying it in the call:
Select To_Char(sysdate, 'YYYY/MM/DD HH:MI:SS') from Dual;
Select To_Date('2013/02/26 05:03:27', 'YYYY/MM/DD HH:MI:SS') from Dual;
You can set the default you want Oracle to use implicitly by setting the NLS_DATE_FORMAT parameter:
ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD HH:MI:SS';
Note that the previous statement only alters the default for the session in which it is executed. We use a custom format in our Oracle systems and to ensure that we get it on all sessions we use an after logon trigger:
create or replace TRIGGER NLS_Parameters_OnLogon AFTER LOGON ON SCHEMA BEGIN
-- This makes the database case insensitive for sorting and searching and sets the default date format for TO_CHAR and TO_DATE
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_COMP=LINGUISTIC';
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_SORT=BINARY_CI';
EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''YYYY/MM/DD HH:MI:SS''';
End;
It is possible to change the default date format for the whole Oracle server by editing some of the Oracle config files but since we have to deploy to client servers over which we have no control we use this method instead.
This article covers the same sort of ground I just have with a little more in the way of examples.
I am saving date with time into DB and using SQL Developer which by default shows just date. I know its matter of client config but I have seen query in Oracle that returned time component of date when one was present. Something like convert (HH:MM:SS). I am just interested in this one.
To show the time element of all dates as a one-off exercise use this DDL statement.
ALTER SESSION set nls_date_format = 'DD-MON-YYYY HH24:MI:SS'
/
or whatever date mask takes your fancy.
To set this permanently in SQL Developer, set parameters in
Tools -> Preferences -> Database -> NLS Parameters
I you understand that it's a matter of client config and want to see time portion of date for some special purpose you can query it converting to char like this:
select to_char(sysdate, 'yyyy.mm.dd hh24:mi:ss') from dual;
More info on date format can be found here or in official docs