Convert timezone format in Oracle - oracle

I need to convert below timezone format in the following format:
Input:
2020-10-28T20:12:20.986Z
Output:
28-OCT-20 8:12 PM
I tried below query but I am unable to get timestamp with it. Please help.
select TO_TIMESTAMP(SUBSTR('2020-04-21T13:02:31.259Z',1,(INSTR('2020-04-21T13:02:31.259Z', 'T') - 1)),'YYYY-MM-DD HH24:MI:SS') from dual;

One option might be this
SQL> alter session set nls_timestamp_format = 'dd-MON-YY hh:mi PM' ;
Session altered.
SQL> select to_timestamp('2020-10-28T20:12:20.986Z','yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"') from dual ;
TO_TIMESTAMP('2020-10-28T20:12:20.986Z','YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
---------------------------------------------------------------------------
28-OCT-20 08:12 PM
SQL>
But if you rely better in the to_timestamp function without any session setting, then it is better
SQL> select to_timestamp('2020-10-28T20:12:20.986Z','yyyy-mm-dd"T"hh24:mi:ss.ff3"Z"') from dual ;
TO_TIMESTAMP('2020-10-28T20:12:20.986Z','YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
---------------------------------------------------------------------------
28-OCT-20 08.12.20.986000000 PM

You have a timestamp string with a time zone, use TO_TIMESTAMP_TZ rather than TO_TIMESTAMP and then use TO_CHAR to format it:
SELECT TO_CHAR(
TO_TIMESTAMP_TZ(
'2020-04-21T13:02:31.259Z',
'YYYY-MM-DD"T"HH24:MI:SS.FFTZR'
),
'DD-MON-RR HH12:MI AM',
'NLS_DATE_LANGUAGE=American'
)
FROM DUAL;
db<>fiddle here
Note: DATE, TIMESTAMP and TIMESTAMP WITH TIME ZONE are binary data types and are stored in 7-20 bytes (1 byte each for century, year-of-century, month, day, hour, minute and second then up to 6 optional bytes for fractional seconds for TIMESTAMPs and up to 7-bytes for time zone for TIMESTAMP WITH TIME ZONE). It is never stored in any particular format.
How the DATE/TIMESTAMP data types are displayed is dependent on the client application that you are using to query the database; some may use the NLS settings for the user's session but others do not use that. If you want a particular format then convert the DATE/TIMESTAMP to a string using TO_CHAR.

Related

Why is DATE data type treated like TIMESTAMP(0) data type in Oracle mode in H2?

According to the H2 documentation, in the Oracle compatibility mode:
DATE data type is treated like TIMESTAMP(0) data type.
Meantime, DATE and TIMESTAMP(0) datatypes are not the same in Oracle. Compare:
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual
gives
25-MAR-22 13.07.42.000000000 25-MAR-22
respectively.
In particular, this weird treating of DATE as TIMESTAMP(0) influences on how H2 calculates the difference between two dates.
Again, in Oracle:
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS TIMESTAMP(0)) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS TIMESTAMP(0)) from dual
gives
+04 00:00:00.000000
and
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS DATE) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS DATE) from dual
produces just:
4
Apparently, for H2 both above queries produce the result in nanoseconds and not days as expected.
So, it is an H2 bug or I am missing something?
Meantime, DATE and TIMESTAMP(0) datatypes are not the same in Oracle
Oracle differs from many other RDBMS in that its DATE data type ALWAYS contains both a date and a time component. Its implementation predates the ANSI standard.
In Oracle, if you have the table:
CREATE TABLE table_name (ts TIMESTAMP(0), dt DATE);
and insert the data:
INSERT INTO table_name (ts, dt) VALUES (SYSDATE, SYSDATE);
Then you can look at the binary data being stored using the DUMP function:
SELECT DUMP(ts) AS dump_ts,
DUMP(dt) AS dump_dt
FROM table_name;
Which outputs:
DUMP_TS
DUMP_DT
Typ=180 Len=7: 120,122,3,25,15,13,37
Typ=12 Len=7: 120,122,3,25,15,13,37
Then you can see that they are both stored as 7-byte binary values:
120 = Century + 100
122 = Year-of-century + 100
3 = Month
25 = Day
15 = Hour + 1
13 = Minutes + 1
37 = Seconds + 1
And the binary values are identical (the only difference is in the meta-data Typ where 180 = TIMESTAMP and 12 = DATE).
Effectively, they are stored identically.
db<>fiddle here
However
The side-effects of a TIMESTAMP vs. a DATE data type in Oracle may lead to different effects.
When you subtract a TIMESTAMP and either a TIMESTAMP or a DATE then the return value is an INTERVAL DAY TO SECOND data type.
When you subtract a DATE and a DATE then the default return value is a NUMBER representing the number of days difference.
When you display a TIMESTAMP then the client application you are using may default to using the NLS_TIMESTAMP_FORMAT session parameter to format the timestamp as a string and the default for this parameter will typically show date, time and fractional seconds.
When you display a DATE then the client application you are using may default to using the NLS_DATE_FORMAT session parameter to format the date as a string and the default for this parameter will show date but not time (and there will never be any fractional seconds to show). Just because the client application may chose not to show the time component does not mean that the time component does not exist.
If you set the session parameters using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Then, provided your client application is using those parameters to format them, they will display identically.
The problem you are seeing with the difference in Oracle is due to these side effects.
If the question is
So, it is an H2 bug or I am missing something?
than the the answer would be:
No, it is not a bug, and what you've missed is the fact, that compatibility modes in H2 are just that - attempt to reach with minimal efforts maximum compatibility with different databases.
H2 is not an emulator for any non-standard features (quirks) of those databases.
It that particular case, to achieve identical behaviour would require to introduce new non-standard data type, which goes beyond "minimal effort" level.
The different in the output of the values in the first query is down to the session's NLS settings. These control the display format for dates and timestamps:
sho parameter nls_date_format
NAME TYPE VALUE
--------------- ------ -----------
nls_date_format string DD-MON-YYYY
sho parameter nls_timestamp_format
NAME TYPE VALUE
-------------------- ------ -------------------------
nls_timestamp_format string DD-MON-YYYY HH24.MI.SSXFF
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual;
CAST(SYSDATEASTIMESTAMP(0)) CAST(SYSDAT
------------------------------ -----------
25-MAR-2022 12.18.24.000000000 25-MAR-2022
If you change these to be the same format, both expressions return the same result:
alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS';
alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS';
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual;
CAST(SYSDATEASTIMEST CAST(SYSDATEASDATE)
-------------------- --------------------
25-MAR-2022 12:17:43 25-MAR-2022 12:17:43
So they both contain the full date + time with no fractional seconds.
Note that while date and timestamp(0) have the same precision, as your further examples show they work differently:
Subtracting one date from another returns the number of days between the values as a number
Subtracting a timestamp from a date or timestamp returns an interval
So the result of:
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS DATE) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS DATE) from dual
Is 4 days.

Oracle - how to convert datetime to TZ format?

I have this time format:
2020-09-08 14:00:00
and I want to convert it to following which is from Sydney time to UTC:
2020-09-08T01:00:00Z
First of all, giving the answer considering that your data is actual varchar2:
SQL> SELECT TO_CHAR(CAST(TO_DATE('2020-09-08 14:00:00','YYYY-MM-DD HH24:MI:SS')
2 AS TIMESTAMP) AT TIME ZONE 'Australia/Sydney',
3 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
4 FROM DUAL;
TO_CHAR(CAST(TO_DATE
--------------------
2020-09-08T18:30:00Z
SQL>
Please note that You can also set NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD"T"HH24:MI:SS"Z"' in your session (and don't use the TO_CHAR in your query) as per your requirement. Also, you can use UTC timezone instead of Australia/Sydney if you want to convert your local date to UTC timezone. DB<>Fiddle for UTC conversion.
If the given data is already in date datatype stored in your table, then you just need to use CAST as follows: (TO_DATE is not required)
SELECT TO_CHAR(CAST(YOUR_DATE_COLUMN
AS TIMESTAMP) AT TIME ZONE 'Australia/Sydney',
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
FROM YOUR_TABLE;

Fetch Hours from Created date

I'm just trying to fetch Hour of my table from created date in Oracle 12c Database but it is showing error INVALID EXTRACT FIELD FOR EXTRACT FIELD. kindly guide me to fetch hour of my date my code is here...
SELECT
EXTRACT( HOUR FROM (TO_CHAR(CREATED_DATE,'RRRR-MM-DD HH:MI:SS')) ) HOUR
FROM
INVOICE_V;
my Date is stored as 6/1/2020 4:04:50 PM in this format and Extract function is not accept this function.
Do not store dates as strings.
But, since you have, convert it from a string to a date using TO_DATE:
SELECT EXTRACT( HOUR FROM TO_TIMESTAMP(CREATED_DATE,'DD/MM/YYYY HH12:MI:SS AM') ) AS HOUR
FROM INVOICE_V;
If, however, you meant that its just displaying in that format (and is actually a DATE data type) then CAST the date to a timestamp:
SELECT EXTRACT( HOUR FROM CAST( CREATED_DATE AS TIMESTAMP) ) AS HOUR
FROM INVOICE_V;
An hour can not be used in the EXTRACT function.
The only way to extract hour is to use TO_CHAR or subtract it from TRUNC date as follows:
TO_CHAR(created_date,'HH24') -- OR 'HH' as per your requirement
-- OR
FLOOR(24*(created_date- TRUNC(created_date)))
Please note that Oracle does not store dates in any format. It has its own binary representation. What you see while selecting from the table is based on the NLS_DATE_FORMAT parameter.
You can set it according to your requirement.
ALTER SESSION SET NLS_dATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'; -- like this
If you have a date column (or the-like), then:
select extract(hour from cast(created_date as timestamp)) as hr
from invoice_v
Alternatively:
select to_char(created_date, 'hh24') as hr
from invoice_v
The first expression returns an integer number, while the second produces a string.
Note that hour is a language keyword, hence not a good choice for an identifier (here, you used it as a column alias). I changed that.

Get current timestamp in specific format with seconds to one decimal place

I'm trying to set a value in an Oracle database that resembles the following:
2016-06-21 03:07:25.0
It is a varchar of the current date with one digit after the decimal for seconds. I tried multiple ways to achieve this but to no avail:
SQL> select sysdate from dual;
SYSDATE
--------
21-06-16
From this I tried:
SQL> alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS.F';
ERROR:
ORA-01821: date format not recognized
SQL> alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS.s';
ERROR:
ORA-01821: date format not recognized
Then I tried:
SQL> SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') FROM dual;
TO_CHAR(SYSDATE,'YY
-------------------
2016-06-21 12:58:55
Since that worked up to the seconds I tried the decimal part:
SQL> SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS.SSSS') from dual;
TO_CHAR(SYSDATE,'YYYY-MM
------------------------
2016-06-21 13:23:47.4747
So I can get 4 significant places. Now I try with just 1:
SQL> SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS.S') from dual;
SELECT TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS.S') from dual
*
ERROR at line 1:
ORA-01821: date format not recognized
So how can I get the current timestamp in the abovementioned format with seconds set to one decimal place?
SSSS isn't fractional seconds. It's just repeating the SS value twice; in your example you get 13:23:47.4747 - the 4747 is just 47 displayed twice. Maybe you were thinking of SSSSS, but that is the number of seconds since midnight (i.e. 0-86399) so isn't useful here either. A single S isn't a valid format model element.
Dates don't have fractional second precision. A single F isn't a valid format model element either, but even FF isn't valid for a date.
You need to use systimestamp to get the server time with fractional seconds, rather than sysdate:
select to_char(systimestamp, 'YYYY-MM-DD HH24:MI:SS.FF1') from dual;
TO_CHAR(SYSTIMESTAMP,'YYYY-MM
-----------------------------
2016-06-21 14:42:22.7
Storing a date/time as a string is generally a bad idea. I'd suggest you make the column timestamp(1) which will keep the one-decimal-place precision when you set it from systimestamp. You can see what it would get with cast:
select to_char(cast(systimestamp as timestamp(1)), 'YYYY-MM-DD HH24:MI:SS.FF9') from dual;
TO_CHAR(CAST(SYSTIMESTAMPASTI
-----------------------------
2016-06-21 14:49:09.900000000
Converting a date/time to a string should really only be done for display, not for storage.

datatype date and time for oracle database

Which type of data type are used to insert date and time in this format
(10-Oct-2013, 04:00 PM) for oracle database..
CREATE TABLE OPERATOR (
LASTPSWDCHANGE DATE,
LASTSIGNONDTTM DATE,
LASTUPDDTTM DATE
);
DATE is the correct type to store date/time values.The DATE data type does not in itself specify any particular format when converting to or from a string.
To convert from string (usually VARCHAR2) to DATE use
TO_DATE(<string with date>, <date format>)
To convert from DATE to VARCHAR2 use
TO_CHAR(<date>, <date format>)
There is a default date format which is determined by the locale of the client. In tools like Toad or SQL developer the default format often doesn't include the time part.
DATE has second precision. For higher precision (millisecond, nanosecond etc) use TIMESTAMP.
EDIT:
You can find documentation on the format specifiers on Oracles website.
In your case, use:
TO_DATE('10-Oct-2013, 04:00 PM', 'DD-MON-YYYY, HH:MI PM')
TIMESTAMP data type can be used here
a TIMESTAMP := TIMESTAMP '2013-10-10 16:00:00';
b TIMESTAMP WITH TIME ZONE := TIMESTAMP '2013-10-10 16:00:00.00 +02:00';
Hope this helps.
You can use DATE as datatype. But you can retrieve date in various format using TO_CHAR function.
An example:
SELECT TO_CHAR( LASTPSWDCHANGE ,'DD-Mon-YYYY, HH:MI AM' ),
TO_CHAR( LASTSIGNONDTTM ,'DD-Mon-YYYY, HH:MI AM' ),
TO_CHAR( LASTUPDDTTM , 'DD-Mon-YYYY, HH:MI AM' )
FROM OPERATOR

Resources