Convert varchar into datetime in oracle - sql

My datetime is saved in database as varchar in "o" format.
Example:
2020-10-08T06:58:54.0000000+02:00
What is the appropriate format for this kind of data?
I want convert it to datetime.

Fix your data model! Do not store dates as strings; this is inefficient (you need to convert the string to a date whenever you want to perform artihmetic operation), and unsafe (you cannot guarantee that the values are valid dates).
As for your question: it depends the datatype you want to convert that string to. Assuming that you want timestamp with time zone, which seems like the most relevant option here (it allows fractional seconds and a time zone):
select to_timestamp_tz(
'2020-10-08T06:58:54.0000000+02:00',
'yyyy-mm-dd"T"hh24:mi:ss.ff tzh:tzm'
) as myts
from dual
This returns this timestamp with time zone:
08-OCT-20 06.58.54.000000000 +02:00

Do NOT naively convert date-time values with a time zone to a date-time and ignore the time zone if you wish comparisons of those date-time-timezone values to still be accurate.
Your value has a time zone so the most natural method of storing the data would be TIMESTAMP WITH TIME ZONE and to convert it you can use:
TO_TIMESTAMP_TZ( your_column, 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
However, if you want the value as a DATE data type then this data type does not support time zones and you should convert all the values to a common time zone (typically this would be the UTC time zone) using:
CAST(
TO_TIMESTAMP_TZ( your_column, 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
AT TIME ZONE 'UTC'
AS DATE
)
If you do not use a common time zone then you will find that you can compare values and draw incorrect comparisons.
For example:
SELECT CASE
WHEN TO_TIMESTAMP_TZ( '2020-10-08T06:58:54.0000000+00:00', 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
< TO_TIMESTAMP_TZ( '2020-10-08T07:58:54.0000000+02:00', 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
THEN 1
ELSE 0
END AS comparison
FROM DUAL
and
SELECT CASE
WHEN CAST(
TO_TIMESTAMP_TZ( '2020-10-08T06:58:54.0000000+00:00', 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
AT TIME ZONE 'UTC'
AS DATE
)
<
CAST(
TO_TIMESTAMP_TZ( '2020-10-08T07:58:54.0000000+02:00', 'YYYY-MM-DD"T"HH24:MI:SS.FF7TZH:TZM' )
AT TIME ZONE 'UTC'
AS DATE
)
THEN 1
ELSE 0
END AS comparison
FROM DUAL
Both output:
| COMPARISON |
| ---------: |
| 0 |
However, naively using TO_DATE:
SELECT CASE
WHEN TO_DATE( '2020-10-08T06:58:54.0000000+00:00', 'YYYY-MM-DD"T"HH24:MI:SS##############' )
< TO_DATE( '2020-10-08T07:58:54.0000000+02:00', 'YYYY-MM-DD"T"HH24:MI:SS##############' )
THEN 1
ELSE 0
END AS comparison
FROM DUAL
Outputs:
| COMPARISON |
| ---------: |
| 1 |
db<>fiddle here

If your column is varchar2 and dates are stores in the string then you can use TO_DATE to convert it to date as follows:
SQL> SELECT TO_DATE('2020-10-08T06:58:54.0000000+02:00', 'YYYY-MM-DD"T"HH24:MI:SS.#############')
2 FROM DUAL;
TO_DATE('2020-10-08T
--------------------
08-oct-2020 06:58:54
SQL>
# is used to skip the character. I am ignoring the timezone and millisecond part as while converting to Date(&Time) it is not needed.

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

ORA-01857: not a valid time zone

I am trying to convert from UTC time zone to GMT time zone.
I ran this below query and getting ORA error.
select NEW_TIME(SYSDATE, 'UTC', 'GMT') from dual;
And error is
Error starting at line : 1 in command -
select NEW_TIME(SYSDATE, 'UTC', 'GMT') from dual
Error report -
ORA-01857: not a valid time zone
I googled and find that NEW_TIME function is not accepting UTC time zone.
So, Can you please suggest me alternate solution/any way to convert from UTC to GMT?
UTC is also known as GMT, the latter which NEW_TIME already accepts. So, what you are trying to is equivalent to:
SELECT NEW_TIME(SYSDATE, 'GMT', 'GMT')
FROM dual;
The call to NEW_TIME doesn't make any sense of course. Check here for a list of accepted timezone codes.
Use FROM_TZ from convert a timestamp without a time zone to a timestamp with time zone (i.e. UTC) and then use AT TIME ZONE 'GMT' to convert it from the first time zone to the GMT time zone. You'll need to use CAST in various places as FROM_TZ expects a TIMESTAMP rather than a DATE and then you need to cast back to a DATE at the end (assuming you don't want a TIMESTAMP value):
SELECT CAST(
FROM_TZ(
CAST( SYSDATE AS TIMESTAMP ),
'UTC'
)
AT TIME ZONE 'GMT'
AS DATE
) As gmt_time
FROM DUAL
Output:
| GMT_TIME |
| :------------------ |
| 2019-04-10T14:05:37 |
db<>fiddle here

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.

Issue with date in oracle

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.

Extract time from a column

I've a column like last_located_time which contain values like
2017-05-13T17:33:36.000+0000.
I have tried to remove only time, but no luck.
SELECT USERNAME, TO_DATE(SUBSTR(LAST_LOCATED_TIME,11,17),'HH:MI:SS') "lAST TIME"
FROM Tb_089
How should I extract only time value from the columns for all users?
Thanks in advance!
If you want the time component in the UTC time zone (so all times are being displayed in a common time zone) then:
(assuming you have a TIMESTAMP WITH TIME ZONE data type)
SELECT TO_CHAR(
last_located_time AT TIME ZONE 'UTC',
'HH24:MI:SS'
)
FROM Tb_089;
If you, instead, the column is an ISO 8601 formatted string:
SELECT TO_CHAR(
TO_TIMESTAMP_TZ(
last_located_time,
'YYYY-MM-DD"T"HH24:MI:SS.FFTZHTZM'
) AT TIME ZONE 'UTC',
'HH24:MI:SS'
)
FROM Tb_089;
If you want the time component as an interval:
SELECT CAST( utc_last_located_time AS TIMESTAMP ) - TRUNC( utc_last_located_time )
AS time_interval
FROM (
SELECT TO_TIMESTAMP_TZ(
last_located_time,
'YYYY-MM-DD"T"HH24:MI:SS.FFTZHTZM'
) AT TIME ZONE 'UTC' AS utc_last_located_time
FROM Tb_089
);
If you want the time component of the string (without adjusting for disparate time zones) then you could just do:
SELECT SUBSTR( last_located_time, 12, 8 )
FROM Tb_089
To_Date is used to convert Char and Varchar2 into Date.
You need to use To_Char which is opposite of To_Date
Select To_Char(LAST_LOCATED_TIME, 'HH24:MI:SS') "Last Time" from Tb_089;