specifying a date/time format with timezone - oracle

Is it possible to display sysdate in the following format?
Wed Oct 16 15:04:44 MDT 2013
This comes out of unix date format.
echo `date`
EDIT: the latest version is missing timezone information. Also, I am not sure if this is the most elegant solution :
SELECT TO_CHAR (sysdate, 'DY') || ' ' || to_char(sysdate, 'MON DD') || ' ' || to_char(sysdate, 'HH24:MM:SS' ) || ' ' || to_char(sysdate, 'YYYY' )
FROM DUAL ;

sysdate returns value of date data type, which does not contain information about timezone. To be able to display abbreviated version of timezone region you need to operate on values of timestamp with time zone data types and use TZD format element in a date time format mask:
select to_char( cast(sysdate as timestamp with local time zone)
, 'Dy Mon dd hh24:mi:ss TZD yyyy') as res
from dual
Result:
RES
-------------------------------
Thu Oct 17 02:14:00 PDT 2013
Edit
Wed Oct 16:12:0 2013 is what i got
Try to explicitly specify exact time zone region for a session. Because there are might be several time zone regions associated with one offset and oracle wont be able to choose one and returns null. So before executing the query execute alter session set time_zone='<<specify_exact_time_zone_region>>'. For example:
SQL> alter session set time_zone='Canada/Mountain';
Session altered.
SQL> select to_char( cast(sysdate as timestamp with local time zone)
2 , 'Dy Mon dd hh24:mi:ss TZD yyyy') as res
3 from dual;
RES
-------------------------------
Thu Oct 17 02:51:14 MDT 2013

Related

Oracle convert from GMT to EST and EDT

I am using Oracle 19c.
I need to convert dates from GMT to EST and EDT.
I am using the following approach:
1. Get the destination time zone abbreviation for the p_date variable:
DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');
SELECT TO_CHAR(FROM_TZ(CAST (&p_date AS TIMESTAMP), 'America/New_York'), 'TZD') INTO v_tzabbrev FROM DUAL;
Where:
p_date: is the date to be converted.
v_tzname: is the time zone name, such as America/New_York
v_tzabbrev: is the time zone abbreviation, such as 'EDT' or "EST" based on whether the date is during Daylight Saving Time or not
2. Convert the p_date using the time zone abbreviation obtained in #1
SELECT NEW_TIME(p_date, 'GMT', v_tzabbrev) INTO v_date FROM DUAL;
This seems to work. But, I believe the flaw is that it is using the GMT date to determine the destination time zone abbreviation, which is inaccurate.
For example, if p_date, in UTC, is '03/11/2013 02:22:21' and I need to convert it to 'America/New_York', Step #1 would return 'EDT', but this date in Eastern was actually "03/10/2013 21:22:21", which was before Daylight Saving started. So, it should actually be converted using "EST".
Daylight saving time in '2013 began at 2 a.m. on Sunday, March 10.
So, it seems that I need a way to take the GMT value and determine its new date in Eastern first, then apply additional logic based on whether that new date is EDT or EST.
Any assistance is appreciated.
You can define p_date directly as UTC time:
DEFINE p_date TO_TIMESTAMP_TZ('03/11/2013 02:22:21 UTC', 'MM/DD/YYYY HH24:MI:SS TZR');
SELECT TO_CHAR((&p_date AT TIME ZONE 'America/New_York'), 'TZD')
INTO v_tzabbrev
FROM DUAL;
Or in the statement:
DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');
SELECT TO_CHAR((FROM_TZ(CAST(&p_date AS TIMESTAMP), 'UTC') AT TIME ZONE 'America/New_York'), 'TZD')
INTO v_tzabbrev
FROM DUAL;
Another possibility is to use SESSIONTIMEZONE implicitly, although I don't recommend this:
DEFINE p_date TO_DATE('03/11/2013 02:22:21', 'MM/DD/YYYY HH24:MI:SS');
ALTER SESSION SET TIME ZONE = 'UTC';
SELECT TO_CHAR((CAST(&p_date AS TIMESTAMP WITH TIME ZONE) AT TIME ZONE 'America/New_York'), 'TZD')
INTO v_tzabbrev
FROM DUAL;
"Daylight saving time in '2013 began at 2 a.m. on Sunday, March 10."
... which is correct, and you can see that happening with the UTC equivalent date/time as:
-- get New York DST start time as UTC
with cte (ts) as (
select timestamp '2013-03-10 01:59:59 America/New_York' from dual
union all
select timestamp '2013-03-10 03:00:00 America/New_York' from dual
)
select ts, to_char(ts, 'TZD') as tzd, ts at time zone 'UTC' as ts_utc
from cte
TS
TZD
TS_UTC
2013-03-10 01:59:59 AMERICA/NEW_YORK
EST
2013-03-10 06:59:59 UTC
2013-03-10 03:00:00 AMERICA/NEW_YORK
EDT
2013-03-10 07:00:00 UTC
but this date in Eastern was actually "03/10/2013 21:22:21", which was before Daylight Saving started.
No, it isn't, it's after DST started.
So, it should actually be converted using "EST".
No, it shouldn't. I'm afraid the premise of your question is wrong.
The conversion you are doing is getting the correct result:
-- get UTC timestamp as New York
with cte (ts) as (
select timestamp '2013-03-11 02:22:21 UTC' from dual
)
select ts as ts_utc, ts at time zone 'America/New_YORK' as ts, to_char(ts at time zone 'America/New_York', 'TZD') as tzd
from cte
TS_UTC
TS
TZD
2013-03-11 02:22:21 UTC
2013-03-10 22:22:21 AMERICA/NEW_YORK
EDT
fiddle
2013-03-11 02:22:21 UTC is after 2013-03-10 01:59:59 America/New_York, as it is the following day in UTC, and 19 hours after the New York DST switch occurred. In other words, 2013-03-11 02:22:21 UTC is 19 hours after 2012-03-10 07:00:00 UTC, which is the UTC equivalent of the EDT start-time from the first query above.
You seem to be confusing the date in your UTC value with the date that DST was applied in the USA that year.
Because the NEW_TIME() function is limited, I would prefer to use FROM_TZ and AT TIME ZONE, as Wernfried showed.

How to convert Time string in UTC to CST in Oracle

I need to convert timestamp String in UTC TZ format to CST TZ format as shown in here "2019-01-02T11:53:59.269-05:00"
So basically i need the output of this query with SYSTIMESTAMP replaced with time String in UTC TZ Format.
select TO_CHAR(SYSTIMESTAMP ,'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') CREATEDTIME from dual;
I tried lot of stuff but getting errors
select TO_CHAR( to_timestamp('2019-01-02 11:53:59.759', 'YYYY-MM-DD HH24:MI:SS.FF3TZH') ,'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') CREATEDTIME from dual
Error
ORA-01821: date format not recognized
Could you please help me write the correct SQL query.
With a TSTZ, you can select at a different time-zone.
Below are some examples for daylight- and standard-time.
Standand-Time:
SELECT TO_CHAR(TO_TIMESTAMP_TZ('2019-01-02T16:53:59.269 UTC',
'YYYY-MM-DD"T"HH24:MI:SS.FF3 TZR') AT TIME ZONE 'AMERICA/CHICAGO',
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM')
AS CENTRAL_TIME
FROM DUAL;
Result:
CENTRAL_TIME
2019-01-02T10:53:59.269-06:00
1 row selected.
And a daylight-savings example:
SELECT TO_CHAR(TO_TIMESTAMP_TZ('2019-04-02T17:35:52.136 UTC',
'YYYY-MM-DD"T"HH24:MI:SS.FF3 TZR') AT TIME ZONE 'AMERICA/CHICAGO',
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM')
AS CENTRAL_TIME
FROM DUAL;
Result:
CENTRAL_TIME
2019-04-02T12:35:52.136-05:00
1 row selected.

How to convert String with timezone to Date

How to convert below string to Date in Oracle
Wed Jan 13 23:01:24 GMT 2016
Tried below and this get's date as
SELECT TO_CHAR(SYSDATE, 'DY MON DD HH24:MM:SS YYYY') FROM dual;
FRI AUG 26 14:08:04 2016
Eventually, Wanted something like this
SELECT TO_CHAR('Wed Jan 13 23:01:24 GMT 2016', 'DY MON DD HH24:MM:SS ??? YYYY') FROM dual;
If the time zone is always a recognised abbreviation you can do:
select to_timestamp_tz('Wed Jan 13 23:01:24 GMT 2016', 'Dy Mon DD HH24:MI:SS TZD YYYY')
from dual;
TO_TIMESTAMP_TZ('WEDJAN1323:01:24GMT2016','DYMONDDHH24:MI:SSTZDYYYY')
---------------------------------------------------------------------
2016-01-13 23:01:24 EUROPE/LONDON
You can't convert directly to a date because the time zone format elements aren't allowed in to_date(). If you had a fixed value - always GMT - you could ignore that by treating it as a literal, but you don't.
If you want it as a timestamp or a date, rather than a timestamp with time zone, you need to decide how to convert it. You can assume it's local time and essentially ignore the time zone by casting it, or you can adjust it to a specific time zone, e.g. UTC. There are various ways, here are a couple with a CTE to provide your sample and one in another zone (well, in summertime anyway so you get a different string):
with t (str) as (
select 'Wed Jan 13 23:01:24 GMT 2016' from dual
union all select 'Fri Aug 26 19:53:27 BST 2016' from dual
)
select to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as tstz,
cast(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as timestamp) as ts,
cast(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as date) as dt,
sys_extract_utc(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY')) as tsutc
from t;
TSTZ TS DT TSUTC
--------------------------------- ------------------- ------------------- -------------------
2016-01-13 23:01:24 EUROPE/LONDON 2016-01-13 23:01:24 2016-01-13 23:01:24 2016-01-13 23:01:24
2016-08-26 19:53:27 EUROPE/LONDON 2016-08-26 19:53:27 2016-08-26 19:53:27 2016-08-26 18:53:27
Exactly how you handle it depends on what you really need, of course.
Unfortunately that doesn't always work with abbreviations; Oracle doesn't necessarily recognise the values you see in Unix date command output, and the ones it does recognise aren't always available. Changing the session time zone can break it:
alter session set time_zone = 'America/Los_Angeles';
select to_timestamp_tz('Wed Jan 13 23:01:24 GMT 2016', 'Dy Mon DD HH24:MI:SS TZD YYYY')
from dual;
ORA-01857: not a valid time zone
You can change the session time zone to one that does recognise it (Europe/London) but that's a hack and won't work for all values anyway. It doesn't help that abbreviations can mean more than one thing.
If you have a list of known expected values and know what they really represent to you, you can swap the abbreviation for a region, but it doesn't really scale:
select to_timestamp_tz(
replace(replace('Wed Jan 13 23:01:24 GMT 2016', 'GMT', 'Europe/London'),
'BST', 'Europe/London'),
'Dy Mon DD HH24:MI:SS TZR YYYY') from dual;
Or with multiple output formats:
with t1 (str) as (
select 'Wed Jan 13 23:01:24 GMT 2016' from dual
union all select 'Fri Aug 26 19:53:27 BST 2016' from dual
),
t2 (adj_str) as (
select replace(replace(str, 'GMT', 'Europe/London'), 'BST', 'Europe/London')
from t1
)
select to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as tstz,
cast(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as timestamp) as ts,
cast(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as date) as dt,
sys_extract_utc(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY')) as tsutc
from t2;
You'd need to have nested replace calls (or regexp_replace to reduce the repetition a little) for each abbreviation you expect; or could have a function that hides that mess away from your main query.
You need to use the TO_TIMESTAMP_TZ function.
The following example converts a character string to a value of TIMESTAMP WITH TIME ZONE:
SELECT TO_TIMESTAMP_TZ('1999-12-01 11:00:00 -8:00',
'YYYY-MM-DD HH:MI:SS TZH:TZM') FROM DUAL;
The -8:00 is the timezone.
https://docs.oracle.com/cd/B12037_01/server.101/b10759/functions179.htm#SQLRF06143

Oracle to_char in query is not working

Im trying to run this below query but its seems to be error
For those data types are varchar
Query
select *
from RP_REPORT_TEMP
where to_char(START_DATE,'FM DD YYYY HH24:MI:SS AM')
>= 'May 01 2016 00:00:00'
and to_char(END_DATE,'FM DD YYYY HH24:MI:SS PM')
<= 'May 31 2016 11:59:00'
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
Table
|RID |START_DATE |END_DATE |
|--------------------|-------------------------- |-----------------------------|
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
|A001 |May 1 2016 12:00:00:000AM |May 31 2016 12:00:00:000PM |
While i tried to execute this query. Query return some error. How can i fix this ?
Error
SQL Error [1722] [42000]: ORA-01722: invalid number
java.sql.SQLSyntaxErrorException: ORA-01722: invalid number
Why don't you use TO_DATE() on the date instead?
select * from RP_REPORT_TEMP
where START_DATE >= to_date('May 01 2016 12:00:00 AM','MON DD YYYY HH:MI:SS AM')
and END_DATE <= to_date('May 31 2016 11:59:00 AM','MON DD YYYY HH24:MI:SS AM')
and lower(rid) like '%a001%'
Assuming that START_DATE and END_DATE are actually dates, I can spot two main issues in your code:
Casting every row to string is slow and also prevents Oracle from using indexes (unless you have a carefully built function-based index).
Lexicographical sort (aka "A to Z") does not render meaningful results with dates with "May 1". Just think of what sense this list has: Apr, Aug, Dec, Feb, Jan, Jul, Jun, Mar, May, Nov, Oct, Sep
My suggestions are:
Avoid converting dates to string, save for display purposes
Use a more solid format when you have to convert from string to date
As a result:
select *
from RP_REPORT_TEMP
where START_DATE
>= TO_DATE('2016-05-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
and END_DATE
<= TO_DATE('2016-05-31 11:59:00', 'YYYY-MM-DD HH24:MI:SS')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
P.S. START_DATE and END_DATE were not dates after all
Try this..
select *
from RP_REPORT_TEMP
where TO_date(START_DATE,'MON DD YYYY HH:MI:SS AM')
>= to_Date('May 01 2016 12:00:00 AM' ,'MON DD YYYY HH:MI:SS AM')
and TO_DATE(END_DATE,'MON DD YYYY HH:MI:SS PM')
<= TO_DATE('May 31 2016 11:59:00 AM' ,'MON DD YYYY HH:MI:SS PM')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
select *
from RP_REPORT_TEMP
where TO_date(START_DATE,'MON DD YYYY HH24:MI:SS')
>= to_Date('May 01 2016 12:00:00' ,'MON DD YYYY HH24:MI:SS')
and TO_DATE(END_DATE,'MON DD YYYY HH24:MI:SS')
<= TO_DATE('May 31 2016 11:59:00' ,'MON DD YYYY HH24:MI:SS')
and lower(rid) like '%a001%'
order by CAST(cid as INTEGER) asc
This is what your query should look like:
select *
from rp_report_temp
where to_date(start_date,'FM Mon DD YYYY HH:MI:SS"FMMon DD YYYY HH:MI:SS":000"AM', 'nls_date_language = english')
>= to_date('01/05/2016 00:00:00', 'dd/mm/yyyy hh24:mi:ss')
and to_date(end_date,'FM Mon DD YYYY HH:MI:SS":000"AM', 'nls_date_language = english')
<= to_date('31/05/2016 23:59:59', 'dd/mm/yyyy hh24:mi:ss')
and lower(rid) like '%a001%'
order by cast(cid as integer) asc;
Here, I have converted your start and end date columns into a date, based on the fact that a sample string in that column looks like "May 1 2016 12:00:00:000AM" - there's an extra ":000" after the seconds; I'm assuming this is always ":000".
Note how I've made your code nls_date_language parameter independent, by specifically setting that value within the to_date(). This means that if someone else's client has that set to something that's not English, the sql statement will still work for them.
You'll note that I didn't need to do that for the values you're testing, since I changed the format of the string to something that used numbers to represent the months.
You have some fundamental data modelling issues here too - by storing everything as varchar2 you have made a rod for your own back - you've lost all the validation available (what happens if someone puts a string of Feb 30 2015 39:99:99 AM in that column? AWOOGA, AWOOGA, error!). You've made your queries have to work harder (now we've got functions all over the place trying to convert data to the correct datatype).
You should store data in the correct datatype. Dates should be stored as DATE, Timestamps as TIMESTAMP, numbers as NUMBER (with or without specific precision and scale), etc etc.
If your data was stored correctly, then your query would be:
select *
from rp_report_temp
where start_date >= to_date('01/05/2016 00:00:00', 'dd/mm/yyyy hh24:mi:ss')
and end_date <= to_date('31/05/2016 23:59:59', 'dd/mm/yyyy hh24:mi:ss')
and lower(rid) like '%a001%'
order by cid asc;

inserting data into Timestamp datatype column is returning ORA-01858: a non-numeric character was found where a numeric was expected

Our application is trying to insert data into Oracle database in the format "Tue Feb 26 15:30:00 EST 2016" into column(FLD_TIMESTAMP) of Timestamp(6) datatype .We are receiving "ORA-01843: not a valid month" .
Wrote a trigger to convert the input data into timestamp format as below :
SQL> create or replace trigger test_wifi before insert on ISG_SESSION_tempfeb15 for each row
2 begin
3 :NEW.fld_timestamp :=to_char(to_timestamp_tz(':NEW.fld_timestamp','Dy Mon DD hh24:mi:ss TZD YYYY'),'DD-MON-YY hh:mi:ss AM');
4 end;
5 /
Trigger created.
While i am trying to insert data , it is still erroring out :
SQL> insert into ISG_SESSION_tempfeb15(isg_session_id,mac_address,nas_ip,fld_timestamp,created_dte)
2 values('5','6','7','Wed Jan 13 16:29:00 EST 2016','16-FEB-16 03:05:00.0000');
values('5','6','7','Wed Jan 13 16:29:00 EST 2016','16-FEB-16 03:05:00.0000')
*
ERROR at line 2:
ORA-01858: a non-numeric character was found where a numeric was expected
Can someone please tell me how to resolve this ? Thanks in Advance .
Why do you have to_char after converting to timestamp?
That's because you can't do the data conversion as part of a trigger like that. The issue is that the insert statement expects the data to be passed in with the correct format.
What you need to do is scrap your trigger and amend your insert statement to something like:
insert into ISG_SESSION_tempfeb15 (isg_session_id,
mac_address,
nas_ip,
fld_timestamp,
created_dte)
values ('5',
'6',
'7',
to_timestamp_tz('Wed Jan 13 16:29:00 EST 2016', 'Dy Mon dd hh24:mi:ss TZR yyyy'),
to_timestamp('16-FEB-2016 03:05:00.0000', 'dd-MON/yyyy hh24:mi:ss.ff4'));
N.B. I have amended the year of the created_dte that you're passing in to have four digits, not two. Y2K isn't a fairy tale!
Also, please note that if your column has a datatype of TIMESTAMP(6) and not TIMESTAMP(6) WITH TIME ZONE, you will lose any information about the timezone of the data.
eg.
create table t1 (col1 timestamp(6),
col2 timestamp(6) with time zone);
insert into t1 values (to_timestamp_tz('Wed Jan 13 16:29:00 EST 2016', 'Dy Mon dd hh24:mi:ss TZR yyyy'),
to_timestamp_tz('Wed Jan 13 16:29:00 EST 2016', 'Dy Mon dd hh24:mi:ss TZR yyyy'));
insert into t1 values (to_timestamp_tz('Wed Jan 13 16:29:00 UTC 2016', 'Dy Mon dd hh24:mi:ss TZR yyyy'),
to_timestamp_tz('Wed Jan 13 16:29:00 UTC 2016', 'Dy Mon dd hh24:mi:ss TZR yyyy'));
commit;
select * from t1;
COL1 COL2
--------------------------- ----------------------------------
13/01/2016 16:29:00.000000 13/01/2016 16:29:00.000000 -05:00
13/01/2016 16:29:00.000000 13/01/2016 16:29:00.000000 +00:00
See how the first column looks like it contains the same value, but the second column reveals that it doesn't?
Try change ':NEW.fld_timestamp' to :NEW.fld_timestamp
:NEW.fld_timestamp :=to_char(to_timestamp_tz(:NEW.fld_timestamp,'Dy Mon DD hh24:mi:ss TZD YYYY'),'DD-MON-YY hh:mi:ss AM');
this is your problem

Resources