When I do a SELECT statement that outputs a TIMESTAMP WITH TIME ZONE column, it doesn't include the time zone in the output. It just outputs the date and time without the timezone, after converting it to my local timezone.
I have 2 questions:
How to get all TIMESTAMP WITH TIME ZONE columns to always display their time zones in the output, rather than the default of omitting it?
How to get all TIMESTAMP WITH TIME ZONE columns to output with a default time zone of UTC? I know there's ways to do this on a per-query basis, but I'd like to do it in every case with needing to modify any queries. So a server setting maybe?
for one column:
SELECT colname AT TIME ZONE 'UTC' FROM tablename;
for all
SET TIMEZONE TO 'UTC';
see also ALTER ... SET ...
Related
I ran the same statements in two different databases: my Local DB and Oracle Live SQL.
CREATE TABLE test(
timestamp TIMESTAMP DEFAULT SYSDATE,
timestamp_tmz TIMESTAMP WITH TIME ZONE DEFAULT SYSDATE,
timestamp_local_tmz TIMESTAMP WITH LOCAL TIME ZONE DEFAULT SYSDATE
);
INSERT INTO test VALUES (DEFAULT, DEFAULT, DEFAULT);
SELECT * FROM test;
(all statements were executed at approximately the same time - 09:35 AM CET)
Results from my Local DB:
TIMESTAMP: 10-JAN-23 09.35.32.000000000 AM
TIMESTAMP WITH TIME ZONE: 10-JAN-23 09.35.32.000000000 AM EUROPE/BERLIN
TIMESTAMP WITH LOCAL TIME ZONE: 10-JAN-23 09.35.32.000000000 AM
Results from Oracle Live:
TIMESTAMP: 10-JAN-23 08.35.44.000000 AM
TIMESTAMP WITH TIME ZONE: 10-JAN-23 08.35.44.000000 AM US/PACIFIC
TIMESTAMP WITH LOCAL TIME ZONE: 10-JAN-23 08.35.44.000000 AM
After seeing the results, my questions are:
Why is Oracle Live's TIMESTAMP showing date in a different time zone (8.35 AM instead of 9.35 AM)?
Why does Oracle Live's TIMESTAMP WITH TIME ZONE return US/PACIFIC as time zone?
Is there any difference between TIMESTAMP and TIME STAMP WITH LOCAL TIME ZONE?
The different data types are described in the documentation.
The TIMESTAMP data type is an extension of the DATE data type. It stores year, month, day, hour, minute, and second values. It also stores fractional seconds, which are not stored by the DATE data type.
TIMESTAMP WITH TIME ZONE is a variant of TIMESTAMP that includes a time zone region name or time zone offset in its value.
TIMESTAMP WITH LOCAL TIME ZONE is another variant of TIMESTAMP. It differs from TIMESTAMP WITH TIME ZONE as follows: data stored in the database is normalized to the database time zone, and the time zone offset is not stored as part of the column data. When users retrieve the data, Oracle Database returns it in the users' local session time zone.
You are seeing a difference because you have different timezones, and you are defaulting the values to SYSDATE, which is the system DATE.
In your local database the system time zone (select dbtimezone from dual) seems to be based on CET, while the Live SQL database seems to be based on UTC, as Oracle recommends. As CET is an hour ahead of UTC/GMT, that explains the one-hour difference.
The TIMESTAMP value is just a simple cast, i.e. cast(SYSDATE as TIMESTAMP), so you get the same value you would if you queried SYSDATE directly, with zero fractional seconds added.
For the TIMESTAMP WITH TIME ZONE it has to store a time zone, and it has to get that from somewhere, and by default it uses your session time zone, not the database time zone. In your local DB that also seems to be CET, but Live SQL is defaulting the session time zone to US Pacific time - not unreasonable, given where Oracle is based. So now it's effectively doing from_tz(cast(SYSDATE as TIMESTAMP), SESSIONTIMEZONE) for that value, where for you SESSIONTIMEZONE is CET in one database and US/Pacific in the other.
For the TIMESTAMP WITH LOCAL TIME ZONE it is doing the same, but then normalising that back to the database time zone for storage (effectively cast(from_tz(cast(SYSDATE as TIMESTAMP), SESSIONTIMEZONE) at time zone DBTIMEZONE as TIMESTAMP) - not actually that internally, but gives you the idea), and converting back from the database time zone to your session time zone again when it is queried.
In both databases, if you alter session set time_zone = ... before inserting, and again to a different value before querying, then you'll see different results - the displayed time portion will stay the same for the first two columns, but the time zone will change for the WITH TIME ZONE, and the time will change for the WITH LOCAL TIME ZONE.
fiddle with different session time zones.
You can read more about all of this behaviour in the documentation I already linked to above.
If you use SYSTIMESTAMP instead of SYSDATE as the default for all of your columns then you will avoid the implicit conversion to your session time zone for the WITH TIME ZONE value, and that will always show the database time zone. The LOCAL column will still display in your session time zone, but they will all represent the same time. You will also still see the one-hour difference between the two databases, because they have different database time zones. You could consider defaulting the plain timestamp to sys_extract_utc(SYSTIMESTAMP), or defaulting them all (or at least the first two) to SYSTIMESTAMP at time zone 'UTC'.
fiddle with UTC-normalised values.
I am having some trouble understanding how to deal in Postgres with time zone semantic:
Consider this table
TABLE MyTable (
MyDate TIMESTAMP NOT NULL,
// other columns
);
And this query
SELECT *
FROM MyTable
WHERE // conditions
AND tstzrange(#{start} ::timestamp with time zone, #{end} ::timestamp with time zone] #> MyDate::timestamp without time zone at time zone 'CET'
I understand that Postgres only stores the epoch value i.e. no time zone info is ever stored, so I understand the need to specify timezone for start and end as they are formatted strings that Postgres needs to calculate the epoch for.
What I don't really understand is:
MyDate::timestamp without time zone at time zone 'CET'
Postgres knows the epoch for MyDate since it's their values are stored, why the need to "convert" to a time zone ?
What are we actually saying here and can this be simplified ?
Postgres never stores timezone information in timestamp or timestamptz. In the timestamptz case the timestamp being stored is rotated to a UTC value using either the timezone information in the presented timestamp or the value of the setting TimeZone and then stored. In the timestamp case that is not done. On output a timestamptz is rotated back from UTC to whatever the TimeZone setting is or what via at time zone <some_tz>. In the timestamp case the retrieved value is assumed to be the setting of TimeZone unless you override with at time zone <some_tz>. Best practices is that you use timestamptz.
I have a Java application that inserts data into a database using prepared statements. In the preparedStamement date is set in UTC format.
preparedStatement.setDate(index, new java.sql.Date(date.getTime()), UTC);
I want to be sure that when read and write operations execute on the table, the response should ALWAYS be in UTC format. At the below query, when the data is read it will be converted to the client's timezone. I don't want TIME_COLUMN to be converted to any time zone. It should remain in the UTC time zone. How can I define TIME_COLUMN in that way?
Notes: I cannot edit the DB timezone. I cannot edit select queries using At time zone.
"TIME_COLUMN" TIMESTAMPTZ default (now() at time zone 'utc'),
You could set the timezone of your RDBMS to UTC, see https://medium.com/building-the-system/how-to-store-dates-and-times-in-postgresql-269bda8d6403
When that's done, whatever dates you store, they will be in UTC. Converting from UTC into something else can be done either in queries, like
select created_at at time zone 'utc' at time zone 'america/los_angeles'
from users;
Taken from https://popsql.com/learn-sql/postgresql/how-to-convert-utc-to-local-time-zone-in-postgresql
Or, you can convert the timezone at application level.
I am quite new to SQL, and trying to pull a data table from the database (flight) using the following command:
select
flight.FLT_NBR,
flight.LEG_NBR,
flight.LEG_TAIL_NBR,
flight.LEG_IATA_ORIG_CD as FLT_SCHD_ORIG_ARPT_CD,
flight.LEG_IATA_DEST_CD as FLT_SCHD_DEST_ARPT_CD,
flight.SCHD_ARR_TMSTP as Scheduled_Arrival,
flight.ACTL_ARR_TMSTP AS Actual_Arrival,
flight.SCHD_DPRT_TMSTP as Scheduled_Departure,
flight.ACTL_DPRT_TMSTP AS Actual_Departure,
from home/tulips/FT_FLIGHT_LEG flight
Now the problem is there are multiple country origin and destination with different times. How do I incorporate same time zone for all the countries? I tried using the command as time zone 'UTC' such as below but it didn't work... May be I am adding it in a wrong place?
select
flight.FLT_NBR,
flight.LEG_NBR,
flight.LEG_TAIL_NBR,
flight.LEG_IATA_ORIG_CD as FLT_SCHD_ORIG_ARPT_CD,
flight.LEG_IATA_DEST_CD as FLT_SCHD_DEST_ARPT_CD,
flight.SCHD_ARR_TMSTP as Scheduled_Arrival as time zone 'UTC',
flight.ACTL_ARR_TMSTP AS Actual_Arrival as time zone 'UTC',
flight.SCHD_DPRT_TMSTP as Scheduled_Departure as time zone 'UTC',
flight.ACTL_DPRT_TMSTP AS Actual_Departure as time zone 'UTC',
from home/tulips/FT_FLIGHT_LEG flight
Please help me a way to have one time zone for all the Scheduled_Arrival,Actual_Arrival,Scheduled_Departure and Actual_Departure
The expression you want is at time zone, not as time zone.
In order to use it, you need to know what time zone the original datetime value represents. For example, I have a SQL server in Sydney Australia, so getdate() will return my local date and time. However, to convert it to UTC I must first inform SQL of the fact that the value starts off in AUS Eastern Standard Time, and then ask it to convert it to UTC, by chaining at time zone expressions together. Like this:
select getdate() at time zone 'AUS Eastern Standard Time' at time zone 'UTC'
If you don't know the time zone of the original datetime value, there is no way for SQL to know how to change it to a different time zone's value.
Instead of always writing:
select my_column at time zone 'UTC' at time zone 'Europe/Paris' from my_table;
I would prefer doing:
select dtz(my_column, 'Europe/Paris') from my_table;
UTC is system-wide (server time zone), and could even be hardcoded in dtz().
Can someone share an efficient implementation of such a function?
Edit
select my_column at time zone 'UTC' at time zone 'Europe/Paris' from my_table;
Can be shortened a very very little bit like this:
select timezone('UTC', my_column) at time zone 'Europe/Paris' from my_table;
Its really dificult to see what you are having trouble with on this.
I don't believe the server timezone helps you here. As I understand it, it's the SQL client timezone than affects this.
You're not going to get a function more efficient than (IMMUTABLE):
RETURN arg1 AT TIME ZONE 'UTC' AT TIME ZONE arg2;
But this will always be less efficient than writing it inline in your SQL.
Ideally your timestamp should be TIMESTAMP WITH TIMEZONE instead of TIMESTAMP WITHOUT TIMEZONE since it's being used to store absolute timestamps not local timestamps. This would prevent the need for two conversions (into UTC and out of it). But that does mean you would need to add the AT TIME ZONE 'UTC' into your INSERT and UPDATE statements.