Oracle Date to_char Returns Different Results - oracle

I have a database on my local development machine and there is a database on our test server. Basically, the tables on my dev machine were copied over from the test machine.
However, I have found a difference in how the same date is treated by the to_char function. On my development machine if I run the following query:
select test_date, to_char(test_date, 'YYYY-MM-DD')
from test.table
where id = 'C0007784'
I get the following results:
31-DEC-99 1999-12-31
On the test server running the same query against the same schema and data I get the following:
31-DEC-99 1899-12-31
Could this difference in behaviour of to_char be due to a setting being different in the two Oracle instances?
If I run SELECT value FROM v$nls_parameters WHERE parameter ='NLS_DATE_FORMAT'; I get DD-MON-RR for both instances.

So you exported the contents of the table to a csv file using DD-MON-YY format. YY obviously causes ambiguity. I guess that when you were importing the file, 99 was interpreted as 1999 instead of 1899. I don't know the exact mechanism which is used by database to guess the full year, but anyway Oracle strongly recommends YYYY in date format:
Note: Oracle recommends that you use the 4-digit year element (YYYY)
instead of the shorter year elements for these reasons: The 4-digit
year element eliminates ambiguity.
The shorter year elements may affect query optimization because the
year is not known at query compile time and can only be determined at
run time.

Related

Oracle TRUNC function doesn't work in perl

I try to insert the created field in my_table. The created field has a datetime type. In my_table the field my_created has a date format. So I try to TRUNC the created field. However I'm getting the error ORA-01830: date format picture ends before converting entire input stringwhile inserting the truncated value. It seems, that the time is still there but is reset to 00:00. how can I get only the date without time? It happens only in perl. I'm getting only date in toad.
Very simplified code looks like:
my $SQL="SELECT
TRUNC(CREATED),
FROM
DBA_OBJECTS";
my $sth = $db->prepare($SQL);
$sth->execute();
my $date = $sth->fetchrow();
$SQL = "INSERT INTO MY_TABLE
(MY_CREATED)
VALUES (?)";
my $stmt = $dbh_master->prepare($SQL);
$stmt->execute($date);
EDIT:
I found an ugly workaround and I'm executing it like this:
$stmt->execute(substr($date, 0, 10));
However maybe someone has a nicer solution.
How can I get only the date without time?
In Oracle, a DATE is a binary data type that is composed of 7 bytes representing: century, year-of-century, month, day, hour, minute and second. It ALWAYS has those binary components so if you want an Oracle DATE data type then you cannot get it without a time.
The Oracle DATE data type was released with Oracle version 2 in 1979 and predates the ANSI/ISO standard (of 1986, where a DATE does not have a time component) and Oracle has maintained backwards compatibility with their previous data types rather than adopting the ANSI standard.
If you use the TRUNC(date_value, format_model) function then it will set the binary components of the DATE, up to the specified format model, to the minimum (0 for hours, minutes and seconds, 1 for days and months) but it will NOT give you a data type that does not have a time component.
It happens only in perl. I'm getting only date in toad.
No, you are getting the entire 7 byte binary value in Toad; however, the user interface is only choosing to show you the date component. There should be a setting in the preferences that can set the date format in Toad which will let you see the entire date-time components.
Oracle SQL/Plus and SQL Developer use the NLS_DATE_FORMAT session parameter and Toad may also be able to use that.
If you want to get the value as a DATE then it will always have a time component (even if you set that time component to zeros using TRUNC).
If you want to get the date so that it is formatted in a way without a time component then you need to convert it to another data type and can use TO_CHAR to format it as a string:
SELECT TO_CHAR(CREATED, 'YYYY-MM-DD')
FROM DBA_OBJECTS
But then you will be returning a (formatted) string and not a DATE data type.

How to Insert a Timestamp in Oracle in a Specific Format

I am at a loss as how to insert the current time in a different format than the default. Can somebody help explain?
Here is how my table was created:
CREATE TABLE ACTIVITY_LOG
(
TIME TIMESTAMP NOT NULL
, ACTIVITY VARCHAR2(200) NOT NULL
);
My insert command works:
insert into activity_log
values (localtimestamp,'blah');
But how do i insert the localtimestamp value into my table in a different format using the various MM DD YY HH MM SS tags? I've tried the following, but it gives me the ORA-1830: date format picture ends before converting entire input string error.
insert into activity_log
values (to_timestamp(localtimestamp,'YYYY/MM/DD'),'blah');
You don't insert a timestamp in a particular format. Timestamps (and dates) are stored in the database using an internal representation, which is betwen 7 and 11 bytes depending on the type and precision. There is more about that in this question, among others.
Your client or application decides how to display the value in a human-readable string form.
When you do:
to_timestamp(localtimestamp,'YYYY/MM/DD')
you are implicitly converting the localtimestamp to a string, using your session's NLS settings, and then converting it back to a timestamp. That may incidentally change the value - losing precision - but won't change how the value is stored internally. In your case the mismatch between the NLS setting and the format you are supplying is leading to an ORA-01830 error.
So your first insert is correct (assuming you really want the session time, not the server time). If you want to see the stored values in a particular format then either change your client session's NLS settings, or preferably format it explicitly when you query it, e.g.:
select to_char(time, 'YYYY-MM-DD HH24:MI:SS.FF3') from activity_log
You don't seem to provide any indication of what your 'localtimestamp' is - is that pseudocode? A variable name? A column you haven't shown the definition for?
What data type is 'localtimestamp'? What data does it contain? Pertinent questions as other answers point out, because if it truly is a time stamp then oracle will be converting it to a string for you, before passing that string to to_timestamp() in your final query. Your initial stab at it should just work if the variable is a timestamp, containing a timestamp
Ultimately "date format picture ends" means "you passed me a string looking like '2017-05-17 12:45:59', but claimed it was only 'yyyy-mm-dd'. What was I expected to do with the rest of it?"
Your current final comment on your question "I was hoping to look in the table and see a useful looking time" - that's your query tool's problem. Have a look in the setting of your query tool and change the date format it displays. As has been noted, dates in oracle are stored as a decimal number days since a certain moment in time. If 0 represents 01 Jan 1970, then 1.75 represents 6pm on the 2 Jan 1970. It is up to the end program the user is using, to format the date into something you like.. you cannot "insert a timestamp with a different format" because time stamps don't have a format any more than a number like 1.75 has a format. It is what your query does with it when it gets it out, that gives it the format:
To_char(timestampcol, 'yyyy mm did')
To-char(tomestampcol, 'mon dd yyyy')
These use oracles built in date formatter, that turns that decimal number of the date into a string in the given format; you will see a string.. or you can just write "select * from table" and run it in TOAD and toad will show you the dates according to the format in settings, or you can write a c# program and get a load of date objects out and call my date.ToString("yyyy-MM-dd") on them to format them. The idea I'm trying to get across is that you don't pick the date format on the way in, you pick it on the way out, if you don't like what you're looking at, you have to change it on the way out, not the way in

Timestamp variations between oracle and postgres

Currently, I am working on migrating an Oracle database schema to Postgres. As part of it I have to convert a custom utility function in Oracle which generates timestamps based on timezone. But the values obtained from Oracle and Postgres seem to vary by one hour.
Oracle:
SELECT (to_timestamp_tz('20300714 235959 CET','YYYYMMDD HH24MISS TZR') - to_timestamp_tz('19700101 000000 GMT','YYYYMMDD HH24MISS TZR'))
as foo FROM dual;
yields +22109 21:59:59.000000
Postgres:
select ('20300714 235959'::timestamp AT TIME ZONE 'CET') - ('19700101 000000'::timestamp AT TIME ZONE 'GMT') as foo;
yields 22109 days 22:59:59
I guess the reason for this difference is because of daylight saving but I am not sure. Can anyone help me out with this problem.
I am using Postgres v9.6 and Oracle 12c.
Well, I found the mistake I was doing. Postgres seems to handle the abbreviated timezone name and full timezone name differently. In case if you want to incorporate daylight related changes you would have to use full timezone name. In my case using 'Europe/Amsterdam' instead of 'CET' yielded the same result as that of Oracle.
To find the complete list of full timezone names supported by Postgres, I used the query:
select * from pg_timezone_names where abbrev='CET';

Why does CURRENT_DATE contains time in Oracle Mode?

When I connect to
jdbc:hsqldb:mem:lbw;sql.syntax_ora=true
the statement
SELECT CURRENT_DATE FROM dual
results in
2014-01-31 10:35:54
This is in opposite to connections without Oracle syntax mode, where CURRENT_DATE doesn't contain time.
As described in the HSQLDB documentation, DATE is interpreted as TIMESTAMP(0) in Oracle syntax mode. But in Oracle 10g itself, CURRENT_DATE behaves as expected (without time).
This difference seems to include DATE fields in general.
Why does HSQLDB behave this way?
Is there a way to disable the automatic conversion?
From the same HSQLDB documentation you linked to:
Datetime types
HSQLDB fully supports datetime and interval types and operations,
including all relevant optional features, as specified by the SQL
Standard since SQL-92. The two groups of types are complementary.
The DATE type represents a calendar date with YEAR, MONTH and DAY
fields.
The TIME type represents time of day with HOUR, MINUTE and SECOND
fields, plus an optional SECOND FRACTION field.
The TIMESTAMP type represents the combination of DATE and TIME types.
The Oracle compatibility section says:
The DATE type is interpreted as TIMESTAMP(0) in ORA syntax mode.
Oracle's DATE data type "contains the datetime fields YEAR, MONTH, DAY, HOUR, MINUTE, and SECOND". So it's equivalent to an HSQLDB TIMESTAMP(0) data type, and in Oracle mode it is treated as such.
Oracle dates always have a time component, even if it is all zeros for midnight. If your SQL client doesn't show it by default you can see that with select to_char(current_date, 'YYYY-MM-DD HH24:MI:SS'), as others have already pointed out.
In normal non-Oracle mode HSQLDB is just treating the value as an SQL-standard DATE and dropping the time portion; in Oracle mode it preserves the time. There doesn't seem to be any way to selectively enable some aspects of the Oracle mode, so you're stuck with the time - really not sure why that is an issue though since it's just reflecting the data you have in your database. If you want to ignore the time you could always select trunc(current_date), which will take the time back to midnight; but it will still show as 2014-01-31 00:00:00 because it's still going to be treated as TIMESTAMP(0).

Insert a datetime value with GetDate() function to a SQL server (2005) table?

I am working (or fixing bugs) on an application which was developed in VS 2005 C#. The application saves data to a SQL server 2005. One of insert SQL statement tries to insert a time-stamp value to a field with GetDate() TSQL function as date time value.
Insert into table1 (field1, ... fieldDt) values ('value1', ... GetDate());
The reason to use GetDate() function is that the SQL server may be at a remove site, and the date time may be in a difference time zone. Therefore, GetDate() will always get a date from the server. As the function can be verified in SQL Management Studio, this is what I get:
SELECT GetDate(), LEN(GetDate());
-- 2010-06-10 14:04:48.293 19
One thing I realize is that the length is not up to the milliseconds, i.e., 19 is actually for '2010-06-10 14:04:48'. Anyway, the issue I have right now is that after the insert, the fieldDt actually has a date time value up to minutes, for example, '2010-06-10 14:04:00'. I am not sure why. I don't have permission to update or change the table with a trigger to update the field.
My question is that how I can use a INSERT T-SQL to add a new row with a date time value ( SQL server's local date time) with a precision up to milliseconds?
Check your table. My guess is that the FieldDT column has a data type of SmallDateTime which stores date and time, but with a precision to the nearest minute. If my guess is correct, you will not be able to store seconds or milliseconds unless you change the data type of the column.
I would guess that you are not storing the GetDate() value in a DateTime field. If you store the value in a datetime field you will get the maximum precision allowed by the DateTime type. Additionally, DateTime is a binary type (a double actually) so 19 means 19 bytes, not 19 characters.
Try to create a simple table with a Datetime field like this
CREATE TABLE [dbo].[DateTable](
[DateField] [datetime] NOT NULL
)
And add a date with
insert into datetable (datefield) values(getdate())
When you execute a select you will get back a value including milliseconds. The following query
select * from datetable
returns
2010-06-11 00:38:46.660
Maybe this would work instead of getdate -
SYSDATETIME()
look here if you can find what you need -
http://msdn.microsoft.com/en-us/library/ms188383.aspx
As you're on SQL 2005, don't forget the getutcdate() function to ensure that, regardless of where your servers are actually located, you have a constant time reference.
Imagine, you have the server in the UK in winter (i.e. GMT+0), and save a record at 10:30am. You then cut over to a SQL server hosted in California (GMT+8) and 8 hours later save another record.
Using getdate(), both saves record the same time "10:30:00". Using getutcdate(), the first save records at "10:30:00", the second save records "18:30:00".
Not really answering the question, but important in your circumstances.
You can use like this in procedure and If there is no procedure use only getdate().
insert into [dbo].[Tbl_User] (UserId,Uvendoremail,UAddress,Ddob,DMobile,
DEmail,DPassword,DAddress,CreatedDate) values (#userid,#vendoremail#address,#dob,#mobile,#email,#dpassword,#daddress,getdate())

Resources