Issue with date in oracle - sql

I am trying to pull date from one table which is in ISO format and then store it in US date format?
Trunc(cast(to_timestamp(ATTRIBUTE_39,'yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"')as date))
Actual output:
4/11/2018 12:00:00 AM
expected output:
4/11/2018

I am trying to pull date from one table which is in ISO format and then store it in US date format?
Dates (and timestamps) do not have a format - they are represented in a table by 7 bytes for a date or 20 bytes for a timestamp.
You can get the value as a DATE data type using TO_TIMESTAMP_TZ and either the TZR or TZH:THM format models to match the time zone region/offset (they will both work with the Zulu time zone region)
SELECT CAST(
TO_TIMESTAMP_TZ(
ATTRIBUTE_39,
'yyyy-mm-dd"T"hh24:mi:ss.ff3TZH:TZM'
) AT TIME ZONE 'UTC' -- Convert to a common time zone
AS DATE
)
FROM your_table;
When you select from the table then whatever client program you are using (typically) will implicitly convert the 7-bytes it uses internally to something you, the user, can read - a string. SQL/Plus and SQL Developer use the NLS_DATE_FORMAT session parameter as the format model when they perform this implicit conversion.
So your query is effectively converted to:
SELECT TO_CHAR(
CAST(
TO_TIMESTAMP_TZ(
ATTRIBUTE_39,
'yyyy-mm-dd"T"hh24:mi:ss.ff3TZR'
) AT TIME ZONE 'UTC'
AS DATE
),
(
SELECT VALUE
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT'
)
)
FROM your_table;
If you want to format a date or a timestamp then you will have to explicitly convert it to a string using TO_CHAR():
SELECT TO_CHAR(
CAST(
TO_TIMESTAMP_TZ(
ATTRIBUTE_39,
'yyyy-mm-dd"T"hh24:mi:ss.ff3TZR'
) AT TIME ZONE 'UTC'
AS DATE
),
'MM/DD/YYYY'
)
FROM your_table;
Or by altering the NLS_DATE_FORMAT session parameter:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
(Be aware that this will only change the format in the current session and will not change it for any other sessions/users.)

Try this:
select to_char(Trunc(cast(to_timestamp('2016-06-29T13:13:00.123','yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"')as date)),'MM/DD/YYYY') from dual
the default date/time formatting depends on your NLS_DATE_FORMAT setting.

Related

Casting Local Time to UTC Formating Incorrect

HIRE_DATE is in a 'DATE' column. The timestamp is local (Los Angeles); I would like to convert it to UTC.
I can't for the life of me fathom why the UTC output is mangled (Last 2 digits of YY is the DD; and vice-versa) -- and the time does not convert to UTC.
HIRE_DATE: 30/04/2019 12:00:00 AM
select from_tz(to_timestamp(HIRE_DATE,'DD-MM-YY HH24:MI:SS'), 'America/Los_Angeles') at time zone 'UTC' from TABLE
OUTPUT: 19/04/2030 12:00:00 AM
If HIRE_DATE is a DATE data type then you don't need TO_TIMESTAMP.
TO_TIMESTAMP is used to convert a string (i.e. VARCHAR2) into a TIMESTAMP value but you have a DATE value.
Just do
select from_tz(CAST(HIRE_DATE AS TIMESTAMP), 'America/Los_Angeles') at time zone 'UTC'
from TABLE
Actually I don't understand why FROM_TZ does not accept DATE values whereas almost any other date/timestamp related function accept either DATE or TIMESTAMP value as input.
Note, the default output display format of this query is defined by current user session NLS_TIMESTAMP_TZ_FORMAT setting. If you are not satisfied with the output format, either change NLS_TIMESTAMP_TZ_FORMAT setting by executing ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = '...' or use TO_CHAR function to set output format explicitly.
Instead of
... AT TIME ZONE 'UTC'
you can also use
SYS_EXTRACT_UTC(...)
The upper returns a TIMESTAMP WITH TIME ZONE value, the second one returns a TIMESTAMP value.
Would this do any good?
SQL> select from_tz(cast (sysdate as timestamp), 'UTC') result from dual;
RESULT
---------------------------------------------------------------------------
27.09.20 10:59:28,000000 UTC
Or, in your case
select from_tz(cast (hire_date as timestamp), 'UTC' from dual
No need to apply any format mask to hire_date as it is a DATE datatype (at least, that's what you said).
You use the word "convert" which can mean one of two things:
change the data type, which is what FROM_TZ does
change the value from one time zone to another, which FROM_TZ does not do.
You didn't give your expected output, so we may misunderstand.
To change the data type:
with data(dte) as (
select date '2019-04-30' + interval '12' hour from dual
)
select from_tz(cast(dte as timestamp), 'America/Los_Angeles') from data
FROM_TZ(CAST(DTEASTIMESTAMP),'AMERICA/LOS_ANGELES')
30-APR-19 12.00.00.000000 PM AMERICA/LOS_ANGELES
To get the simultaneous datetime value in UTC:
with data(dte) as (
select date '2019-04-30' + interval '12' hour from dual
)
select cast(sys_extract_utc(from_tz(cast(dte as timestamp), 'America/Los_Angeles')) as date) from data
CAST(SYS_EXTRACT_UTC(FROM_TZ(CAST(DTEASTIMESTAMP),'AMERICA/LOS_ANGELES'))ASDATE)
2019-04-30 19:00:00

How to convert 2020-08-20T12:02:02Z date into DD-MM-YYYY sql?

I want to convert "2020-08-20T12:02:02Z" date into DD-MM-YYYY in the oracle database. The date should look like 20-08-2020. Please advise.
You can try the below -
select to_char(
to_date('2020-08-20T12:02:02Z','YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'DD-MM-YYYY')
from dual
TL;DR: Use TO_CHAR( column_name, 'DD-MM-YYYY' ) to explicitly format your DATE column.
A DATE column does not have a format; it is stored internally as 7-bytes (century, year-of-century, month, day, hour, minute and second respectively). It is not until a user interface tries to display the date that the displayed value is implicitly formatted based on the NLS_DATE_FORMAT session parameter (and this can be set by any user at any time within their own session so multiple users can have multiple date formats and these implicit formats can be changed mid-session so you should NEVER rely on implicit formatting to give consistent output).
So, if you have a DATE and its value is 2020-08-20T12:02:02Z then all you need to do is to format it when displaying it (using TO_CHAR) to not display the time component:
CREATE TABLE table_name (
column_name DATE
);
INSERT INTO table_name ( column_name )
VALUES ( DATE '2020-08-20' + INTERVAL '12:02:02' HOUR TO SECOND );
Set the implicit format for dates:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD"T"HH24:MI:SS"Z"';
Then:
SELECT column_name AS with_implicit_formatting,
TO_CHAR( column_name, 'DD-MM-YYYY' ) AS with_explicit_formatting
FROM table_name;
Outputs:
WITH_IMPLICIT_FORMATTING | WITH_EXPLICIT_FORMATTING
:----------------------- | :-----------------------
2020-08-20T12:02:02Z | 20-08-2020
db<>fiddle here
Note: the Z format model implies the Zulu (UTC+0) time zone. However, dates do not store time zones; so if you want to store this time-zone information then you should be using a TIMESTAMP WITH TIME ZONE data type rather than a DATE (and you may need to pay extra care when converting date-time values from a local time zone to UTC+0 that you apply the correct time zone offset to convert to UTC+0 and do not just take the date-time component and ignore the local time zone.

to_Char(DATE) with time

I have a DB (Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production). In there is a table (Course) in which I have a Date column (start_dte). I want to format the output to a char so I used:
SELECT start_dte,
to_Char(start_dte) AS start_dte_2,
to_Char(start_dte,'DD.MM.YYYY') AS start_dte_3,
to_Char(start_dte,'DD.MM.YYYY HH24:MI:SS') AS start_dte_4,
to_Char(start_dte,'DD.MM.YYYY HH12:MI:SS') AS start_dte_5,
to_Char(start_dte,'DD.MM.YYYY HH.MI.SSXFF AM') AS start_dte_6,
to_Char(start_dte,'DD.MM.YYYY HH24:MI:SSxFF') AS start_dte_7,
to_Char(start_dte,'DD-MON-YYYY HH24:MI:SSxFF TZH:TZM') AS start_dte_8
FROM Course
The Results:
Number 6,7,8 give me
java.sql.SQLException: ORA-01821: date format not recognized
6 has the same format as:
SELECT value
FROM V$NLS_PARAMETERS
WHERE parameter = 'NLS_TIME_FORMAT'
7 and 8 are taken from the Oracle documentation but this is only for timestamps. So what i am missing? I know the actual datatype should be datetime but I only have read access to that DB. What i would actually like:
Or even better:
A DATE doesn't have any time zone information, so if you want to adjust the displayed time then you'll need to specify which time zone that date nominally represents, and which time zone you want to convert it to.
An an example, if your stored date represents UTC and you want to see the equivalent local time in Paris, you can state that the stored time is UTC by casting it as a plain timestamp and passing that into the from_tz() function; and then specify the target timezone with at:
-- CTE for your sample data
with course (start_dte) as (
select cast(timestamp '2018-10-17 14:00:00' as date) from dual
)
-- actual query
select from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris' as start_timestamp_tz
from course;
START_TIMESTAMP_TZ
------------------------------------------
2018-10-17 16:00:00.000000000 EUROPE/PARIS
Since you're querying this via JDBC you probably want to retrieve that as its native data type, and then choose how to display it locally. (But you could presumably query it as a date and adjust it in Java too...)
If you want to convert it to a string on the DB side, though, just use the format model you already used:
select to_char(from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris', 'DD.MM.YYYY HH24:MI') as start_date
from course;
START_DATE
----------------
17.10.2018 16:00
Getting it into two fields is also simple, and if you don't want to repeat the conversion you can use a CTE or an inline view:
select to_char(start_timestamp_tz, 'DD.MM.YYYY') as start_date,
to_char(start_timestamp_tz, 'HH24:MI') as start_time
from (
select from_tz(cast(start_dte as timestamp), 'UTC')
at time zone 'Europe/Paris' as start_timestamp_tz
from course
);
START_DATE START_TIME
---------- ----------
17.10.2018 16:00
But it sounds like Java should be doing that conversion to strings for display.
What i would actually like:
| START_DATE |
|------------------|
| 17.10.2018 16:00 |
Or even better:
| START_DATE | START_TIME |
|------------|------------|
| 17.10.2018 | 16:00 |
Use:
SELECT to_Char(start_dte,'DD.MM.YYYY') AS start_date,
to_Char(start_dte,'HH24:MI') AS start_time
FROM Course
If your data is stored in the table in one time zone (i.e. UTC) and you want it in another time zone then use:
CAST( date_value AS TIMESTAMP ) to convert it from a DATE data type to a TIMESTAMP data type.
FROM_TZ( timestamp_value, timezone_string ) to convert it from a TIMESTAMP data type to a TIMESTAMP WITH TIME ZONE data type at the given time zone.
timestamp_with_timezone_value AT TIME ZONE timezone_string to convert it from one time zone to another time zone.
Like this:
SELECT TO_CHAR(
FROM_TZ( CAST( start_dte AS TIMESTAMP ), 'UTC' ) AT TIME ZONE 'Europe/Berlin',
'DD.MM.YYYY'
) AS start_date,
TO_CHAR(
FROM_TZ( CAST( start_dte AS TIMESTAMP ), 'UTC' ) AT TIME ZONE 'Europe/Berlin',
'HH24:MI'
) AS start_time
FROM Course
start_dte is a DATE value.
DATE does neither have fractional seconds (i.e. XFF) nor time zone information (i.e. TZH:TZM)
Use TIMESTAMP WITH TIME ZONE is you like to get such output.

String to date conversion in query

i have the following "timestamp" in the column
Mon Aug 10 12:24:46 CDT 2016
so to convert into date, i am doing the following.
select * from
(select TO_DATE(SUBSTR(t.timestamp,9,2) || '-' || SUBSTR(t.timestamp,5,3) ||
'-' || SUBSTR(t.timestamp,27,2), 'DD-MON-YY') from table t where
t.LENGTH(TRIM(t.timestamp)) = 28 as date) where date <= sysdate;
The reason for doing that is, "Oracle sysdate" is returning a current date in the following format
20-SEP-16
So to compare the oracle sysdate, i am using the above approach.
is there any better approach for doing this, i knew this is inefficient using a group of sub-strings inside a select statement and since my "time stamp" value is too long, i am unable to convert to ORACLE date.
I am using oracle 11 as my Database. any help is appreciated.
Here is a proof of concept, assuming the so-called "timestamp" is in fact a string. If it is a proper timestamp with time zone (as it should be), then it's even simpler, you can compare to a date directly.
Note two things: In my mapping I don't have "CDT" for some reason but I do have the standard time zone, CST. I am probably missing a daylight savings time file which I don't care to hunt down and install. And Aug-10-2016 was a Wednesday; Monday won't work, you can't fool Oracle. Wonder why you didn't bother to use an actual, correct date (including the correct day of the week).
Edit: Actually I am not missing any "time zone codes file"; instead, to recognize CDT as a valid time zone, the TZR component in the model below needs to be changed to TZD.
PROOF OF CONCEPT:
select 'x' as col1
from dual
where to_timestamp_tz('Wed Aug 10 12:24:46 CST 2016',
'Dy Mon dd hh24:mi:ss TZR yyyy') <= sysdate
;
COL1
-----
x
1 row selected.
The as date is in the wrong place.
'Aug' is a month name abbreviation in a certain language. Specify that language in to_char to make sure it works independent of your current setting.
Don't only use YY when you have YYYY available.
At last there is the time zone 'CDT'. Is it always 'CDT' or can it be something else? If you need to get from one time zone to another, you'd have to convert to timestamp with timezone first, then move to the other timezone, then convert to date.
Here is the query:
select *
from
(
select
cast(from_tz(cast("date" as timestamp), zone) at time zone 'CDT' as date) as "date"
from
(
select to_date(substr(t.timestamp,9,2) || '-' ||
substr(t.timestamp,5,3) || '-' ||
substr(t.timestamp,25,4),
'DD-MON-YY',
'NLS_DATE_LANGUAGE=AMERICAN') as "date",
substr(t.timestamp,21,3) as zone
from table t
where t.length(trim(t.timestamp)) = 28
)
)
where "date" <= sysdate;
Despite its name from_tz doesn't convert from a timezone, but from a timestamp without timezone to a timestamp with timezone. So we use this to put our timezone information in. timestamp at time zone 'xyz' on the other hand moves the timezone to the one specified (the one we interprete our dates to reside in). cast is used to get from date to timestamp and vice versa.
You can use TO_CHAR function to extract date formate
https://docs.oracle.com/database/121/SQLRF/functions216.htm

SQL- Difference between TIMESTAMP, DATE AND TIMESTAMP WITH TIMEZONE?

What is the difference between TIMESTAMP , DATE AND TIMESTAMP with TIMEZONE?
E.g if I wanted to search for all entries between 01-JAN-1990 and 01-JAN-2000 , how would I do so in each format?
I have been searching for timestamp as:
SELECT COUNT(*) FROM TABLE_NAME WHERE DATE BETWEEN '01-JAN-1990' AND '01-JAN-2000;
But I am not sure what format to use to search for DATE or TIMESTAMP WITH TIMEZONE.
The data types and differences between them are in the documentation. The short version is:
DATE has precision down to a second with no time zone support;
TIMESTAMP has precision down to fractions of a second (up to nine decimal places, but your operating system affects that too), still with no time zone support;
TIMESTAMP WITH TIME ZONE has the same precision as TIMESTAMP but also has time zone support, as the name suggests;
TIMESTAMP WITH LOCAL TIME ZONE adjusts the stored value to and from the creating/querying session's local time zone.
You might find this article interesting too.
Whenever you are comparing datetime values stored in your database you should use values of the same datatype to compare against. You don't want to have to convert every value in the column for comparison, especially if the column is indexed. If you have a DATE column then compare with a DATE - don't compare as a string, and don't rely on implicit conversion of a string. When you do:
WHERE date_col BETWEEN '01-JAN-1990' AND '01-JAN-2000'
you are relying on your NLS_DATE_FORMAT being DD-MON-YYYY and your NLS_DATE_LANGUAGE being English. If someone else runs the same query in another session their settings may cause the query to fail (or in some cases, give wrong results, which can be worse). To avoid the language issue it's better to use month numbers rather than names. If you have a string variable to compare against you should use TO_DATE() to convert the string to a DATE using a fixed known format mask - don't rely on NLS. If you have a fixed value you can do the same, or you can use a date literal, which is shorter and unambiguous.
With the format you used you are also including any rows which have a the column set to midnight on January 1st 2000, but not any later on that day. That may be what you want, but make sure you understand how BETWEEN works. If you're actually looking for dates within that decade, including at any time on December 31st 1999, you can use:
WHERE date_col >= DATE '1990-01-01' AND date_col < DATE '2000-01-01'
For timestamps you can either use TO_TIMESTAMP() or a timestamp literal:
WHERE ts_col >= TIMESTAMP '1990-01-01 00:00:00'
AND ts_col < TIMESTAMP '2000-01-01 00:00:00'
For timestamps with time zones you can either use TO_TIMESTAMP_TZ() or a timestamp literal, with a names time zone region:
WHERE tstz_col >= TIMESTAMP '1990-01-01 00:00:00 America/New_York'
AND tstz_col < TIMESTAMP '2000-01-01 00:00:00 America/New_York'
Don't compare dates with strings. It can work if your session's nls_date_format happens to match the format of the string that you're using. But then your query will immediately fail for someone who has a different configuration. Compare dates with dates, timestamps with timestamps, etc.
For dates, you can use either ANSI date literals
SELECT COUNT(*)
FROM your_table
WHERE date_column BETWEEN date '1900-01-01' AND date '2000-01-01'
or you can use a to_date with an explicit format mask
SELECT COUNT(*)
FROM your_table
WHERE date_column BETWEEN to_date('1900-01-01', 'YYYY-MM-DD')
AND to_date('2000-01-01', 'YYYY-MM-DD')
Note that a date in Oracle always has a day and a time component. If you don't specify a time in your to_date, it will default to midnight. If you use an explicit to_date, you can use a string in any format just so long as it matches the format mask you pass in as the second parameter.
For timestamps, you can either use an ANSI timestamp literal
SELECT COUNT(*)
FROM your_table
WHERE timestamp_column BETWEEN timestamp '1900-01-01 00:00:00.000'
AND timestamp '2000-01-01 00:00:00.000'
or you can use a to_timestamp with an explicit format mask
SELECT COUNT(*)
FROM your_table
WHERE timestamp_column BETWEEN to_timestamp('1900-01-01 00:00:00.000', 'YYYY-MM-DD HH24:MI:SS.FFF')
AND to_timestamp('2000-01-01 00:00:00.000', 'YYYY-MM-DD HH24:MI:SS.FFF')
If you use an explicit to_timestamp, you can use a string in any format just so long as it matches the format mask you pass in as the second parameter.
For timestamps with time zone, as you may have guessed, you can either use an ANSI timestamp literal
SELECT COUNT(*)
FROM your_table
WHERE timestamp_column BETWEEN timestamp '1900-01-01 00:00:00.000 -05:00'
AND timestamp '2000-01-01 00:00:00.000 -05:00'
or you can use the to_timestamp_tz function with an explicit format mask
SELECT COUNT(*)
FROM your_table
WHERE timestamp_column BETWEEN to_timestamp('1900-01-01 00:00:00.000 -05:00', 'YYYY-MM-DD HH24:MI:SS.FFF TZH:TZM')
AND to_timestamp('2000-01-01 00:00:00.000 -05:00', 'YYYY-MM-DD HH24:MI:SS.FFF TZH:TZM')
If you use an explicit to_timestamp_tz, you can use a string in any format just so long as it matches the format mask you pass in as the second parameter.