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.
Related
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.
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
I would like to achieve the following.
I have a datetime column that i calculated with the following functions.
to_char(to_date(f_sta_date, 'YYYYMMDD') + (f_sta_time)/86400), 'YYYY-MM-DD HH24:MI:SS')
to_char(to_date(f_sta_date, 'YYYYMMDD') + (f_sta_time)/86400), 'YYYY-MM-DD HH24:MI:SS')
T1
f_sta_date f__sta_time f_sto_date f_sto_time DT_sta DT_sto
20191001 6689 20191001 7185 2019-10-01 01:54:49 2019-10-01 01:59:45
Desired table
T1
f_sta_date f_sta_time_id f_sto_date f_sto_time_id DT_sta DT_sto DT_sta_UTC DT_sto_UTC
20191001 6689 20191001 7185 2019-10-01 01:54:49 2019-10-01 01:59:45
What function could i add to the functions above to achieve the desired result?
To start with: to_char() returns a string from a date. So if you want a date, don't use it, ie replace this:
to_char(to_date(f_sta_date, 'YYYYMMDD') + (f_sta_time)/86400), 'YYYY-MM-DD HH24:MI:SS')
To:
to_date(f_sta_date, 'YYYYMMDD') + f_sta_time/86400
Then: when it comes to managing timezones, you need to use the timestamp with time zone datatype instead of date. To convert your date in localtime (ie the time zone of your session, that is defined by SESSIONTIMEZONE) to a timestamp and get the corresponding date/time at UTC, you can do:
cast(to_date(f_sta_date, 'YYYYMMDD') + f_sta_time/86400 as timestamp with time zone)
at time zone 'UTC'
Your query:
select
to_date(f_sta_date, 'YYYYMMDD') + f_sta_time/86400 dt_sta,
to_date(f_sto_date, 'YYYYMMDD') + f_sto_time/86400 dt_sto,
cast(to_date(f_sta_date, 'YYYYMMDD') + f_sta_time/86400 as timestamp)
at time zone 'UTC' dt_sta_utc,
cast(to_date(f_sto_date, 'YYYYMMDD') + f_sto_time/86400 as timestamp)
at time zone 'UTC' dt_sto_utc
from t
From the discussion in comments under your post, it appears that your date-time (which you are already able to calculate) should instead be a timestamp with time zone, specifically "at time zone CET". Perhaps for your purposes date with time zone would suffice (in Oracle, "date" always means date-time); alas, Oracle doesn't have such a data type, we must use timestamp with time zone.
Below I show how to calculate that, in the WITH clause. (Note that I use a different approach for computing even the date-time - I convert your "time" component to seconds directly, using the Oracle function specifically designed for that, instead of arithmetic operations. Also, while Oracle usually allows you to use a number - your date component - as if it were a string, in some cases it doesn't. For example, you can do that in TO_DATE, but you can't in TO_TIMESTAMP. In any case, you should never rely on such implicit conversions; always make them explicit in your code.)
I show how I created the table for testing; then, in the query, in the WITH clause I do a preliminary computation (computing your DT_STA and DT_STO, but as timestamps with time zone); then in the main query I show how to convert to a different time zone.
create table t1 (
f_sta_date number,
f_sta_time number,
f_sto_date number,
f_sto_time number
);
insert into t1 values (20191001, 6689, 20191001, 7185);
commit;
with
prep (f_sta_date, f_sta_time, f_sto_date, f_sto_time, dt_sta, dt_sto) as (
select f_sta_date, f_sta_time, f_sto_date, f_sto_time,
from_tz(to_timestamp(to_char(f_sta_date), 'yyyymmdd')
+ numtodsinterval(f_sta_time, 'second'), 'CET'),
from_tz(to_timestamp(to_char(f_sto_date), 'yyyymmdd')
+ numtodsinterval(f_sto_time, 'second'), 'CET')
from t1
)
select f_sta_date, f_sta_time, f_sto_date, f_sto_time, dt_sta, dt_sto,
dt_sta at time zone 'UTC' as dt_sta_utc,
dt_sto at time zone 'UTC' as dt_sto_utc
from prep
;
F_STA_DATE F_STA_TIME F_STO_DATE F_STO_TIME DT_STA DT_STO DT_STA_UTC DT_STO_UTC
---------- ---------- ---------- ---------- ----------------------- ----------------------- ----------------------- -----------------------
20191001 6689 20191001 7185 2019-10-01 01:51:29 CET 2019-10-01 01:59:45 CET 2019-09-30 23:51:29 UTC 2019-09-30 23:59:45 UTC
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
I just wanted to know whether the following SQL is good to convert US server time to Thailand date. As we have 12 hours difference in the time, and TH time is ahead of U.S time
SELECT TO_DATE(
TO_CHAR(
SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok', 'yyyy-mm-dd',
'NLS_DATE_LANGUAGE = american'), 'yyyy-mm-dd') AS TODAY
FROM dual;
It works perfectly fine. But are there any other better way to convert timestamp of server from one timezone to another as I need to compare today's date based on this result in my outer SQL.
You could CAST the timestamp to your desired timezone.
For example,
SQL> WITH data AS (
2 SELECT SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok' tm_bangkok FROM dual
3 )
4 SELECT tm_bangkok,
5 CAST(tm_bangkok AT TIME ZONE 'EST' AS TIMESTAMP) tm_est
6 FROM data;
TM_BANGKOK TM_EST
--------------------------------------------- ----------------------------
03-NOV-15 12.54.18.951000 PM ASIA/BANGKOK 03-NOV-15 12.54.18.951000 AM
There is no reason to cast a TIMESTAMP to CHAR and then back to TIMESTAMP again. Simply do
SELECT SYSTIMESTAMP AT TIME ZONE 'Asia/Bangkok' AS TODAY
FROM dual;