I was inspecting how are DATEs stored in database. Consider the following statement:
SELECT
CAST (to_timestamp_tz('2018-12-05T10:00:00+01:00', 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE) AS PRAGUE_TIME,
CAST (to_timestamp_tz('2018-12-05T10:00:00+00:00', 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE) AS GMT_TIME
FROM DUAL
Results in:
PRAGUE_TIME GMT_TIME
2018-12-05 10:00:00 2018-12-05 10:00:00
The times are the same, despite one being created from a +1 timezone offset. Just to be sure, I added further conversion to string:
SELECT
TO_CHAR(CAST (to_timestamp_tz('2018-12-05T10:00:00+01:00', 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE),'YYYY-MM-DD HH24:MI:SS') AS PRAGUE_TIME,
TO_CHAR(CAST (to_timestamp_tz('2018-12-05T10:00:00+00:00', 'YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE),'YYYY-MM-DD HH24:MI:SS') AS GMT_TIME
FROM DUAL
PRAGUE_TIME GMT_TIME
2018-12-05 10:00:00 2018-12-05 10:00:00
Same results. So how can I convert TIMESTAMP to DATE without loosing the timezone information?
how can I convert TIMESTAMP to DATE without loosing the timezone information?
You cannot.
A DATE only has year, month, day, hour, minute and second components.
A TIMESTAMP has all those components plus nanoseconds and optionally time zone or time zone offset components.
If you convert from a TIMESTAMP to a DATE then you will lose the information that the DATE cannot store.
What you can do is convert all the TIMESTAMPs to the same time zone using, for example, AT TIME ZONE 'UTC':
SELECT CAST( TIMESTAMP '2018-12-05 10:00:00+01:00' AT TIME ZONE 'UTC' AS DATE )
AS PRAGUE_TIME_AS_UTC,
CAST( TIMESTAMP '2018-12-05 10:00:00+00:00' AT TIME ZONE 'UTC' AS DATE )
AS GMT_TIME_AS_UTC
FROM DUAL
Results:
| PRAGUE_TIME_AS_UTC | GMT_TIME_AS_UTC |
|----------------------|----------------------|
| 2018-12-05T09:00:00Z | 2018-12-05T10:00:00Z |
Related
I am unable to get the date column to respect the where clause. Regardless what I do, it does not filter on date. I have tried all combinations of to_char and to_date in vain.
HAVING TO_CHAR(PAYMASTR.CHECK_DATE,'MM/DD/YYYY') > '01/01/2021'
I have also tried the code below with all combinations of to_char and to_date.
HAVING PAYMASTR.CHECK_DATE >= TO_DATE('01-01-2021 12:00:00 AM',
'MM-DD-YYYY HH:MM:SS AM')
The check_date of of type DATE.
Result set:
|COMPANY|EMPLOYEE|PAY_SUM_GRP|PAY_GRADE RATE|WAGE_AMOUNT|NET_PAY_AMT|GROSS_PAY|CHECK_DATE|
|-------|--------|-----------|--------------|-----------|-----------|---------|----------|
|2|5|REG 09|21.98|175.84|1459.96|2263.19|1/19/2007 12:00:00 AM|
|2|5|REG 09|21.98|175.84|1663.93|2589.43|1/5/2007 12:00:00 AM|
If CHECK_DATE column's datatype is DATE (should be! If it is VARCHAR2, you're doing it wrong!), then
having check_date > date '2021-01-01'
i.e. compare date to date literal.
Second code you posted is almost OK:
HAVING PAYMASTR.CHECK_DATE >= TO_DATE('01-01-2021 12:00:00 AM', 'MM-DD-YYYY HH:MI:SS AM')
--
MI for minutes; MM is for month
I found this article on code project that did the trick for me. I was struggling really hard to get the query to respect the date parameter in the queru. Setting the session to NLS_DATE_FORMAT worked. Not sure what other implications it may have. Will have to talk to the DBA.
Code Project
It's all about how Oracle stores and works with date DATATYPE
The date has seven components
Century, year, month, day, hour, minute, seconds
and all these components take seven bytes of storage.
Whenever you fetch a Date column from a table, the date value is formatted in a more readable form and this format is set in the nls_date_format parameter.
I am assuming you are grouping by CHECK_DATE otherwise you need to add this date filter with the WHERE clause.
So first check the datatype of your column CHECK_DATE
If it is date then
HAVING CHECK_DATE >= TO_DATE('01-01-2021', 'MM-DD-YYYY')
You don't have to provide hours, minutes, and seconds if omitted hours are rounded to 12 AM or 00 if the 24-hour format is used;
Or if you want to have hours as well then you used MM instead of MI for minutes.
HAVING CHECK_DATE >= TO_DATE('01-01-2021 00:00:00', 'MM-DD-YYYY HH24:MI:SS')
And this does not make sense
HAVING TO_CHAR(PAYMASTR.CHECK_DATE,'MM/DD/YYYY') > '01/01/2021'
You want to compare dates not characters and to_char will provide you a character string that has no sense of comparing with another string '01/01/2021'.
So if you are not grouping by CHECK_DATE user filter condition with WHERE clause
or check the datatype of CHECK_DATE if it is not DATE change it to DATE.
I have a requirement to get records from a table that are systimestamp > LAST_UPDATE_TS + 5 minutes interval
Could you please help with query?
ORACLE DB - 11G Version.
I have tried this as below but not working as expected.
SYSTIMESTAMP : 11-MAR-20 06.06.00.070695 AM -05:00
LAST_UPDATE_TS : 11-MAR-20 06.05.50.781167 AM
After applying this condition, systimestamp > LAST_UPDATE_TS + INTERVAL '5' MINUTE,
I expect no data should return, but still i get rows that doesn't satisfy condition.
You are comparing SYSTIMESTAMP which is a TIMESTAMP WITH TIME ZONE data type to a TIMESTAMP(6) data type; this requires a conversion to a time zone.
If you use:
SELECT SESSIONTIMEZONE FROM DUAL;
The you can see the time zone your session is using.
On db<>fiddle, the default is UTC (+00:00) and running:
SELECT DUMMY AS query1
FROM DUAL
WHERE TIMESTAMP '2020-03-11 06:06:00.070695 -05:00' > TIMESTAMP '2020-03-11 06:05:50.781167' + INTERVAL '5' MINUTE
Outputs:
| QUERY1 |
| :----- |
| X |
Since 2020-03-11 06:06:00.070695 -05:00 is greater than 2020-03-11 06:10:50.781167 +00:00.
If you change the session time zone:
ALTER SESSION SET TIME_ZONE = '-05:00';
and run the same query again (a different column alias was used to prevent caching):
SELECT DUMMY AS query2
FROM DUAL
WHERE TIMESTAMP '2020-03-11 06:06:00.070695 -05:00' > TIMESTAMP '2020-03-11 06:05:50.781167' + INTERVAL '5' MINUTE
Then the output has zero rows:
| QUERY2 |
| :----- |
If you want to manually set the timezone in the conversion then you can use the FROM_TZ function:
SELECT DUMMY AS query3
FROM DUAL
WHERE TIMESTAMP '2020-03-11 06:06:00.070695 -05:00' > FROM_TZ( TIMESTAMP '2020-03-11 06:05:50.781167', '-05:00' ) + INTERVAL '5' MINUTE
Which, again, outputs zero rows:
| QUERY3 |
| :----- |
db<>fiddle here
SYSTIMESTAMP returns a TIMESTAMP WITH TIME ZONE value which is compared with a TIMESTAMP value.
Actually Oracle is doing this:
SYSTIMESTAMP > FROM_TZ(LAST_UPDATE_TS + INTERVAL '5' MINUTE, SESSIONTIMEZONE)
Comparison itself is performed on UTC times.
SYSTIMESTAMP is returned in the time zone of database server's operating system. If this time zone is equal to your current SESSIONTIMEZONE then the condition works as expected.
Either change your session time zone to the time zone of database server's operating system or try this one:
LOCALTIMESTAMP > LAST_UPDATE_TS + INTERVAL '5' MINUTE
which does not utilize time zones at all.
After checking few forums and other stackoverflow pages, I tried this and it seams to be working now.
select *
from table
where cast(systimestamp as TIMESTAMP) > (lst_updt_ts + interval '3' minute);
Doing it the old way?
systimestamp -5/(60*24) > LAST_UPDATE_TS
I would like to know how to convert current time to TIMEZONE in oracle
I tried this and worked perfectly
SELECT (select tzname from qct_timezone_config tzc where gmtoffset =
(select usr_time_zone from qct_user_token where resource_id = 11385)) AS TIMEZONE,
TO_CHAR(CAST(SYSTIMESTAMP AS TIMESTAMP WITH TIME ZONE) AT TIME ZONE
(select tzname from qct_timezone_config tzc where gmtoffset =
(select usr_time_zone from qct_user_token where resource_id = 11385)),
'DD-MON-RR HH:MI:SS.FF AM') AS USER_TIME
FROM dual
But what i want to know is what if the time '03-AUG-2017 11.00.00 AM' is sent from the other system (i want to convert this time to a specific TimeZone) and how to rewrite this query.
You already have everthing in you query, to convert a timestamp to a specific timezone you have to use "AT TIME ZONE" precising the timezone you want your timestamp to be converted:
select systimestamp AT TIME ZONE 'America/Los_Angeles' "West Coast Time" from dual;
I'm not sure what you want to accomplish and the timestamp you want to convert needs to include a timezone if you want to convert it to another timezone.
Was wondering if anyone could help with precision time conversion.
Sample: 1501646399999 which is GMT: Wednesday, August 2, 2017 3:59:59.999 AM
I used the below query, but it always rounds off to 02-AUG-17 04:00:00. Can anyone please guide me
select TO_TIMESTAMP('1970-01-01 00:00:00.000', 'YYYY-MM-DD hh24:mi:SS.FF3') + ((1/86400000) * 1501646399999)
from dual;
The problem is that you're adding a number to your fixed timestamp, which is causing that timestamp to be implicitly converted to a date - which doesn't have sub-second precision.
If you add an interval instead then it stays as a timestamp:
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3';
select TO_TIMESTAMP('1970-01-01 00:00:00.000', 'YYYY-MM-DD hh24:mi:SS.FF3')
+ numtodsinterval(1501646399999/1000, 'SECOND')
from dual;
TO_TIMESTAMP('1970-01-0
-----------------------
2017-08-02 03:59:59.999
Incidentally, you could slightly simplify your query with a timestamp literal:
select TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(...)
You may also want to check if you should be declaring that timestamp as being UTC, and converting back to local time zone after adding the epoch value; or leaving it explicitly as UTC but as a timestamp with time zone value. It depends exactly what that number is supposed to represent. (You said it's GMT/UTC, but still...)
I have a date say 2011-09-26T21:00:00Z . I'm not sure what is T and Z in the date meant. This is EET time. I need to convert this to local time 'IST'.
Expected O/P : 2011-09-27T00:30:00Z ( since we have 3 hours 30 minutes difference b/w EET and IST. Even 2011-09-27 00:30:00 or 2011-09-27(at the least case) is ok for me.
I'm trying the below query But getting error as TimeZone region not found
select to_char((from_tz(to_timestamp(to_char('2011-09-26T21:00:00Z','YYYY-MM-DD HH24:MI:SS')
,'YYYY-MM-DD HH:MI:SS PM') ,'EET')
at time zone 'IST'),'YYYY-MM-DD HH:MI:SS PM TZD') as localtime
from dual;
Somebody pls suggest any other ways to convert.
UPDATE:
I have tried the below query. It is giving output. But that is not the desired format.
select TO_TIMESTAMP_TZ(TO_CHAR((to_timestamp('2011-09-26 21:00:00','yyyy/mm/dd hh24:mi:ss')),
'yyyy/mm/dd hh24:mi:ss')||' Europe/Berlin',
'yyyy/mm/dd hh24:mi:ss tzr') AT TIME ZONE 'Asia/Calcutta' ts_eet
from dual;
OUTPUT: 27-SEP-11 12.30.00.000000000 AM ASIA/CALCUTTA . Here i have one problem 1) I dont want SEP in month instead i need only 09 and the format should be same like 2011-09-27
Oracle treats EET as a time zone region name (SELECT tzname, tzabbrev FROM V$TIMEZONE_NAMES WHERE tzname = 'EET', or see the docs) so it handles daylight saving/summer time (EEST/EEDT). On 2011-09-26 the EET region was actually EEST so it was three hours ahead of UTC, not two; and as IST is always +05:30 the offset was actually +02:30. So your result is 'correct'.
Rather than bounce back and forth to a string, you can use the from_tz function to change a plain timestamp into a timestamp with time zone; and then at time zone to get that in a different zone:
select to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') orig_ts,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET') orig_tsz,
sys_extract_utc(from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET')) orig_utc,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'EET') at time zone 'Asia/Calcutta' new_tsz
from dual;
ORIG_TS ORIG_TSZ ORIG_UTC NEW_TSZ
------------------- -------------------------- ------------------- ---------------------------------
2011-09-26 21:00:00 2011-09-26 21:00:00 EET 2011-09-26 18:00:00 2011-09-26 23:30:00 ASIA/CALCUTTA
The 'T' in your original string denotes the time, and the 'Z' denotes (or is supposed to!) that this represents a date/time in UTC; this is the ISO 8601 standard notation. Oracle's conversion functions allow you to embed character literals in the format model to ignore those. Since it has a 'Z' you should be treating it as UTC not EET, so you might want to go back to whoever you're getting these values from.
If you really do expect all the values to be from the EET timezone with no summer time offset then you could use a fixed TZH:TZM rather than a region name:
select to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') orig_ts,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00') orig_tsz,
sys_extract_utc(from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00')) orig_utc,
from_tz(to_timestamp('2011-09-26T21:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"'),
'+02:00') at time zone 'Asia/Calcutta' new_tsz
from dual;
ORIG_TS ORIG_TSZ ORIG_UTC NEW_TSZ
------------------- -------------------------- ------------------- ---------------------------------
2011-09-26 21:00:00 2011-09-26 21:00:00 +02:00 2011-09-26 19:00:00 2011-09-27 00:30:00 ASIA/CALCUTTA
I doubt that is actually what you want but you'll need to clarify your requirements.
Finally to get the converted value back into the original format you need to use to_char:
select to_char(from_tz(to_timestamp('2011-09-26T21:00:00Z',
'YYYY-MM-DD"T"HH24:MI:SS"Z"'), 'EET') at time zone 'Asia/Calcutta',
'YYYY-MM-DD HH24:MI:SS') new_string
from dual;
NEW_STRING
-------------------
2011-09-26 23:30:00
You can embed the 'T' back in with 'YYYY-MM-DD"T"HH24:MI:SS'; adding the 'Z' back onto the end seems wrong though.
If your source time is from Berlin as your question edit suggests (which is CET/CEST, not EET/EEST; gaining you that missing hour) just change the from_tz region:
select to_char(from_tz(to_timestamp('2011-09-26T21:00:00Z',
'YYYY-MM-DD"T"HH24:MI:SS"Z"'), 'Europe/Berlin') at time zone 'Asia/Calcutta',
'YYYY-MM-DD"T"HH24:MI:SS') new_string
from dual;
NEW_STRING
-------------------
2011-09-27T00:30:00