After executing this SQL in oracle 10g:
SELECT SYSDATE, CURRENT_TIMESTAMP FROM DUAL
I receive this strange output:
What is cause of the difference in time?
The server time is equal of SYSDATE value
CURRENT_DATE and CURRENT_TIMESTAMP return the current date and time in the session time zone.
SYSDATE and SYSTIMESTAMP return the system date and time - that is, of the system on which the database resides.
If your client session isn't in the same timezone as the server the database is on (or says it isn't anyway, via your NLS settings), mixing the SYS* and CURRENT_* functions will return different values. They are all correct, they just represent different things. It looks like your server is (or thinks it is) in a +4:00 timezone, while your client session is in a +4:30 timezone.
You might also see small differences in the time if the clocks aren't synchronised, which doesn't seem to be an issue here.
SYSDATE, SYSTIMESTAMP returns the Database's date and timestamp, whereas current_date, current_timestamp returns the date and timestamp of the location from where you work.
For eg. working from India, I access a database located in Paris. at 4:00PM IST:
select sysdate,systimestamp from dual;
This returns me the date and Time of Paris:
RESULT
12-MAY-14 12-MAY-14 12.30.03.283502000 PM +02:00
select current_date,current_timestamp from dual;
This returns me the date and Time of India:
RESULT
12-MAY-14 12-MAY-14 04.00.03.283520000 PM ASIA/CALCUTTA
Please note the 3:30 time difference.
SYSDATE returns the system date, of the system on which the database resides
CURRENT_TIMESTAMP returns the current date and time in the session time zone, in a value of datatype TIMESTAMP WITH TIME ZONE
execute this comman
ALTER SESSION SET TIME_ZONE = '+3:0';
and it will provide you the same result.
SYSDATE provides date and time of a server.
CURRENT_DATE provides date and time of client.(i.e., your system)
CURRENT_TIMESTAMP provides data and timestamp of a clinet.
Note: SYSDATE - returns only the date, i.e., "yyyy-mm-dd" is not correct. SYSDATE returns the system date of the database server including hours, minutes, and seconds. For example:
SELECT SYSDATE FROM DUAL;
will return output similar to the following: 12/15/2017 12:42:39 PM
SYSDATE, systimestamp return datetime of server where database is installed. SYSDATE - returns only date, i.e., "yyyy-mm-dd". systimestamp returns date with time and zone, i.e., "yyyy-mm-dd hh:mm:ss:ms timezone"
now() returns datetime at the time statement execution, i.e., "yyyy-mm-dd hh:mm:ss"
CURRENT_DATE - "yyyy-mm-dd", CURRENT_TIME - "hh:mm:ss", CURRENT_TIMESTAMP - "yyyy-mm-dd hh:mm:ss timezone". These are related to a record insertion time.
Related
Our company's Oracle server is hosted in the east coast of the US and I believe follows a default timezone of EST. I have a stored procedure which logs messages but puts the current timestamp into a field declared as timestamp.
describe log_messages;
Name Null? Type
--------- -------- --------------
ENTRY_ID NOT NULL NUMBER
SEVERITY VARCHAR2(1)
DATE_TIME TIMESTAMP(6)
MESSAGE VARCHAR2(2048)
Usually, I do something like
insert into log_messages(severity,date_time,message)
values('I',current_timestamp,'some message');
If I do select * from log_messages, the time stamps look like this:
28-MAY-20 01.50.15.747963000 AM
However, the above time is actually 4 hours later than my current timezone.
select entry_id,severity,cast(date_time as timestamp with time zone) as date_time, date_time AT TIME ZONE 'EST' AS est,message
from log_messages
order by date_time desc;
In the above, it thinks the timestamp in the timestamp field is in EST time, and then when it converts the other, it subtracts 4 hours from it. Effectively, it is as though it writes the time in UTC, but then reads it in thinking it is EST, and subtracts 4 hours from it. How can I get the real time in my local EST time?
CURRENT_TIMESTAMP returns the current date and time in your session time zone, i.e. location or time zone settings of your Oracle Database server is not relevant.
You can interrogate your session time zone with select SESSIONTIMEZONE from dual; and change it with ALTER SESSION SET TIME_ZONE=...
However, as the data type is TIMESTAMP(6), the time zone information is lost as soon as the data is inserted.
When you run cast(date_time as timestamp with time zone) then Oracle takes your SESSIONTIMEZONE for conversion, actually Oracle runs cast(FROM_TZ(date_time, SESSIONTIMEZONE) as timestamp with time zone)
Unless you don't alter your session time zone, the two queries should return the same value..
See also How to handle Day Light Saving in Oracle database
I have postgresql function that receive date variable, then I trunc day from time, but timezone anyway added to final query.
CREATE OR REPLACE FUNCTION public.request_user_track()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
IF TG_OP = 'INSERT' THEN
PERFORM pg_notify('user_log_added', '{"userID": ' || NEW."userID" || ',"time":"' || NEW.time || '"}');
INSERT INTO "UserTracks"("userID", "day", "requestedAt", "createdAt", "updatedAt")
VALUES(NEW."userID", date_trunc('day', NEW."time" AT TIME ZONE 'UTC'), NOW() + interval '1 second', NOW(), NOW())
ON CONFLICT("userID", "day") DO UPDATE SET "requestedAt" = EXCLUDED."requestedAt"
WHERE "UserTracks"."userID" = NEW."userID" AND "UserTracks".day = date_trunc('day', NEW."time" AT TIME ZONE 'UTC');
END IF;
RETURN NULL;
END;
$function$
;
I try to set timezone, but anyway in final query I have in db: 2019-12-30 03:00:00
Ok, given that the type of day is timestamptz in the db '2019-12-30 03:00:00' stored at MSK (+3) timezone, I believe the database is doing the right thing.
If you think about it, '2019-12-30 03:00:00 +03:00' is the same time as '2019-12-30 00:00:00 +00:00'. Now we just want the same timestamp to be stored at UTC timezone.
I have a hunch, try something like:
INSERT INTO "UserTracks"("userID", "day", ...)
VALUES(NEW."userID", date_trunc('day', NEW."time" AT TIME ZONE 'UTC') AT TIME ZONE 'UTC', ...)
It may be the case the result of date_trune() isn't kept at UTC timezone.
The other thing to note is that if this is deployed to a production server configured to run its OS and PostgreSQL in UTC (generally recommended) these issues won't exist.
You could change your session timezone or simply variable::timestamp or SELECT variable AT TIME ZONE 'desirable_timezone'. If you only want the date, then DATE(variable). It will depend on what you want to achieve, but all methods are valid for querying or modifing your table, with or without date_trunc.
SELECT date_trunc('day',date(now()))
Suppose I have a table foo with the colum changed_colum of type date.
Now i would like to get the local timestamp from that colum, I try the following:
select TO_CHAR(cast (changed_colum as timestamp) at local, 'YYYY-MM-DD HH24:MI:SS TZR') from foo
result--->
2016-07-08 08:48:35 EUROPE/BERLIN
but this print the date of the application server. I need the local date of the session and not of the server.
Any Idea?
According to Oracle's documents at:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions037.htm
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions079.htm#i999873
try this:
SELECT SESSIONTIMEZONE, CURRENT_TIMESTAMP FROM DUAL;
or
this:
SELECT CURRENT_TIMESTAMP, LOCALTIMESTAMP FROM DUAL;
Hope this will help.
Not clear what you are asking... If you know the dates are all "using the server time zone", then you can use
from_tz(cast (changed_column as timestamp), dbtimezone) at time zone sessiontimezone
and then format it as needed.
DATE datatype does not contain any time zone information. What is the time zone of these dates? Unless you don't know this from design of your application you cannot convert.
AT LOCAL is equal to AT TIME ZONE SESSIONTIMEZONE, i.e. the timezone set by your application server at logon (or set by ALTER SESSION SET TIME ZONE = ...). If you like this time zone equal to the timezone of your client then you have to code this at the application server.
Working on the following query.
SELECT MIN(departure_date), ch_invoice.invoice_id
FROM ch_invoice
INNER JOIN ch_trip
ON ch_invoice.invoice_id = ch_trip.invoice_id
WHERE departure_date < SYSDATE
AND service_rendered = 0
AND paid = 1
Group By ch_invoice.invoice_id
Since the database that it is hitting may be in a location where the date hasn't changed yet, and we are using UTC as a standard for our dates, is it possible to replace SYSDATE with something like UTCDATE? I just need to know what day UTC is currently at.
As AntDC suggested, you can use the SYS_EXTRACT_UTC() function. That converts a 'datetime with time zone' from whatever time zone it is in to UTC.
SYSDATE doesn't have a time zone. If you passed that in then it would be implicitly converted to the system time zone, so it would work, but you can use SYSTIMESTAMP instead as that is already zone-aware.
You said in a comment that you want the date, but all Oracle dates have a time component; you can get the result as a date type with the time set to midnight (which makes sense for the comparison you're doing) with TRUNC():
select systimestamp,
sys_extract_utc(systimestamp) as utctime,
trunc(sys_extract_utc(systimestamp)) as utcdate
from dual;
SYSTIMESTAMP UTCTIME UTCDATE
-------------------------------- ------------------------- -------------------
2016-04-08 17:18:27.352 +01:00 2016-04-08 16:18:27.352 2016-04-08 00:00:00
That's running on a server in the UK, so the local time is BST.
Since that doesn't involve a day change, the effect can be demonstrated using the session time instead of the server time:
alter session set time_zone = '+12:00';
select current_timestamp,
sys_extract_utc(current_timestamp) as utctime,
trunc(sys_extract_utc(current_timestamp)) as utcdate
from dual;
CURRENT_TIMESTAMP UTCTIME UTCDATE
-------------------------------- ------------------------- -------------------
2016-04-09 04:23:17.910 +12:00 2016-04-08 16:23:17.910 2016-04-08 00:00:00
My session time is 2016-04-09, but it still finds the UTC date as 2016-04-08.
(To be clear, I am not suggesting you switch to using current_timestamp or current_date; I'm using those instead of systimestamp and sysdate purely as a demo).
SELECT SYS_EXTRACT_UTC(departure_date)UTC_SYS, SYSTIMESTAMP FROM DUAL;
I have a SQL Builder library that direcltly uses ADO.NET. I have a means of creating a select query with a greater-than-or-equal operator, like:
select *
from book
where book.date_created >= {some date}
My issue is that {some date} is going to always be in the UTC time zone, but it's being compared to the book.date_created column which is a TIMESTAMP(6) WITH TIME ZONE column, which will not be in the UTC timezone.
I can execute the query, but my results are off becuaes of timezone comparisons. My query is for all books where the date_created >= x, but some of the results returned are not greater than x because after subtracting 5 hours for the time zone, they are now less than x. The IDataRecord DateTime fields returned are converted to UTC using DateTime.SpecifyKind()
Can I form my query such that it interprets book.date_created in the UTC timezone?
Note: While I'd love to change my Oracle DB columns to not specify timezones, changing table structures is not something I can do.
Edit:
Currently, {some date} is a SQL Parameter. It's backing datatype is a DateTime with UTC as the timezone. As a parameter, it is a TimestampWithTZ. The Value of the parameter is a DateTime with the kind specified as UTC as well.
Update:
The issue seems to be related to my results set from the IDataRecord. When I pull DateTimes off, I use DateTime.SpecifyKind() to put them in UTC mode. The problem is, the date times come out as DateTimeKind.Unspecified. When converting from Unspecified to UTC, it just drops the timezone and declares it is UTC without changing the underlying value. I'm not sure how to have the IDataRecord pull in the TimeZone value.
You need to use the FROM_TZ function that transforms a TIMESTAMP into a TIMESTAMP WITH TIME ZONE. For example, if you know that your variable is in UTC time (+0:00):
SELECT *
FROM book
WHERE date_created >= from_tz(<timestamp>, '+0:00');
Here's a sample script that shows the behaviour you describe (your local time zone should be set to +1:00):
CREATE TABLE t (tz TIMESTAMP(6) WITH TIME ZONE);
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 +1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 -1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
-- This will return two values instead of one
SELECT *
FROM t
WHERE tz >= to_timestamp('20000101 00:00:00', 'yyyymmdd hh24:mi:ss');
-- This query will return only one row
SELECT *
FROM t
WHERE tz >= from_tz (to_timestamp('20000101 00:00:00',
'yyyymmdd hh24:mi:ss'), '+0:00');
below links will help you.
Datetime Datatypes and Time Zone Support
TIMESTAMP WITH TIME ZONE Data Type
Write Time Zone Aware Code in Oracle
ORACLE timezone summary
Oracle Date and Time data types