Since the data is stored in a TIMESTAMP
column, you cannot automatically convert it. You'll have to write some code that tells Oracle what time zone to treat the data as being stored in the GMT
time zone and tell it that you want it converted to the session's time zone. You would get the automatic behavior you are looking for if you used the TIMESTAMP WITH LOCAL TIME ZONE
data type instead. If you used the TIMESTAMP WITH TIME ZONE
data type, you would avoid having to tell the database what time zone the timestamp comes from when you write the conversion.
Assuming that your session sets its time zone properly
ALTER SESSION SET time_zone = '-8:00'
for example, would tell Oracle that the current session is 8 hours before GMT (currently the Pacific time zone), if the data is stored in a TIMESTAMP
column, you'd need something like
FROM_TZ( ts, 'GMT' ) AT TIME ZONE sessiontimezone
If the data is stored in a TIMESTAMP WITH TIME ZONE
column, you'd just need
ts_tz AT TIME ZONE sessiontimezone
If the data is stored in a TIMESTAMP WITH LOCAL TIME ZONE
column, you would just select that column.
An example
SQL> ed
Wrote file afiedt.buf
1 create table foo(
2 ts timestamp,
3 ts_tz timestamp with time zone,
4* ts_local_tz timestamp with local time zone )
SQL> /
Table created.
SQL> ed
Wrote file afiedt.buf
1 insert into foo
2 values( sys_extract_utc( systimestamp ),
3 systimestamp,
4* systimestamp )
SQL> /
1 row created.
SQL> select from_tz( ts, 'GMT' ) at time zone sessiontimezone ,
2 ts_tz at time zone sessiontimezone,
3 ts_local_tz
4 from foo;
FROM_TZ(TS,'GMT')ATTIMEZONESESSIONTIMEZONE
---------------------------------------------------------------------------
TS_TZATTIMEZONESESSIONTIMEZONE
---------------------------------------------------------------------------
TS_LOCAL_TZ
---------------------------------------------------------------------------
02-MAY-13 01.59.03.171000 PM -08:00
02-MAY-13 01.59.03.171000 PM -08:00
02-MAY-13 01.59.03.171000 PM
In response to the comment below from DylanKlomparens -- you cannot just apply the AT TIME ZONE
to a TIMESTAMP
and expect to get the proper result so I'm not sure that I understand what you are seeing. If you just to an AT TIME ZONE
on a plain TIMESTAMP
, the timestamp is simply treated as having the time zone that you specified. It doesn't change the time. It also doesn't depend on the session time zone. In all these cases, if ts
represents a UTC
time, the PST
version represents the wrong time-- there should be an 8 hour difference between the starting and ending values.
SQL> select ts from foo;
TS
---------------------------------------------------------------------------
02-MAY-13 09.59.03.171000 PM
SQL> select ts at time zone 'PST' from foo;
TSATTIMEZONE'PST'
---------------------------------------------------------------------------
02-MAY-13 09.59.03.171000 PM PST
SQL> alter session set time_zone = '-0:00';
Session altered.
SQL> select ts at time zone 'PST' from foo;
TSATTIMEZONE'PST'
---------------------------------------------------------------------------
02-MAY-13 09.59.03.171000 PM PST
SQL> alter session set time_zone = '-4:00';
Session altered.
SQL> select ts at time zone 'PST' from foo;
TSATTIMEZONE'PST'
---------------------------------------------------------------------------
02-MAY-13 09.59.03.171000 PM PST
In response to Vincent's comment-- A TIMESTAMP WITH LOCAL TIME ZONE
does adjust automatically to the session's time zone regardless of the server's time zone. As I adjust my session's time zone, the results change as well.
SQL> select ts_local_tz from foo;
TS_LOCAL_TZ
---------------------------------------------------------------------------
02-MAY-13 05.59.03.171000 PM
Elapsed: 00:00:00.00
SQL> alter session set time_zone = '-0:00';
Session altered.
Elapsed: 00:00:00.00
SQL> select ts_local_tz from foo;
TS_LOCAL_TZ
---------------------------------------------------------------------------
02-MAY-13 09.59.03.171000 PM
Elapsed: 00:00:00.00
SQL> alter session set time_zone = '+4:00';
Session altered.
Elapsed: 00:00:00.00
SQL> select ts_local_tz from foo;
TS_LOCAL_TZ
---------------------------------------------------------------------------
03-MAY-13 01.59.03.171000 AM
Elapsed: 00:00:00.00
How Connection Pooling works
The issue with connection pool fragmentation is that each connection pool is bound to the exact text of the Connection String, including the SID of the Windows Login when using a Trusted Connection / Integrated Security. The connection pool works because the connection is exactly the same in every way.
Hence, changing the database after connecting doesn't change anything from a security perspective. The advice to change the database after connecting (which can also be done via the SqlConnection.ChangeDatabase
method), is to get around the fact that putting the "Initial Catalog" (or "Database") key/value pair into the Connection String means that those connections aren't using the exact same connection string.
With the above in mind, whether you are using Windows Logins (i.e. Trusted Connection / Integrated Security) or SQL Server Logins (specifying UserID & Password OR using a SqlCredential
),
if the web app connects as the same Login for all requests, then as long as you don't specify the database in the ConnectionString (or at least always specify the same database), and only change the database context after making the connection, then you will get the most re-use out of connection pooling since all connections will be able to use the same pool. Else you will get a pool per Database.
if the web app connects with different Logins, then:
- in the one-database-per-client model (assuming they are only allowed to connect to their database, hence using a different Login per client), you can either always specify the same database for that Login, or not specify any database in the ConnectionString and only change the database context after making the connection, and you will get a pool per Login (or per Database: they are kinda the same thing in this model).
- in the multi-tenant model (assuming the app makes calls to multiple databases), as long as you don't specify the database in the ConnectionString (or at least always specify the same database), and only change the database context after making the connection, then you will get a pool per Login. Of course, if you specify the database in the ConnectionString, then you will get a pool per Login per Database!
What this all means in practical terms
No, you cannot have a single connection pool and "prevent the user from making cross-database queries". The very nature of a connection pool it is that it is the same connection because the connection is not closed. You cannot differentiate permissions when there is nothing to differentiate; the same Login is still logged in, just issuing another command.
Reducing the number of connection pools down to a single pool is at odds with the desire to have different permissions:
If you want to prevent a Login from accessing more than their database, or maybe confined to their database and any "shared" databases, that requires different Logins, and each one will have their own pool. If you go with Contained Databases, you still need to specify either the UserId & Password OR the Initial Catalog in the Connection String, and hence the result will still be one connection pool per each variation.
If you want to have just one connection pool, then you have no choice but to always use the same security credentials (regardless of them being based in Windows or SQL Server). And the same credentials means the same permissions.
The bottom line is, the wording of that MSDN article is a bit confusing / awkward, and you are over-estimating their advice. The issue of Connection Pool Fragmentation really shows up when:
- you are changing both the security credentials AND the "Database" / "Initial Catalog" across connections
- the app is multi-tenant (i.e. not one database per customer) such that each Login can connect to multiple Databases.
Having multiple Logins that connect to multiple Databases will give you more pools that are less frequently reused. Given that the unused connections linger for "approximately 4-8 minutes" (taken from the MSDN page you linked to, the "Removing Connections" section), this creates the inefficient situation of having too many idle connections.
But, having one Connection Pool per-Login OR per-Database is actually just fine.
Please note, however, that even with one Connection Pool per-Login OR per-Database, you can still experience too many idle connections if you have a lot of clients (e.g. Web Apps, back-end processes, etc.) hitting SQL Server from different servers.
Best Answer
To setup the default Time Zone, you can edit the global variable
system_time_zone
(SET GLOBAL). You most likely want to change that on the configuration file so it persists after a reboot.Timezones can be numerical or can use alias if setup properly.
To setup a client custom timezone, the right way is to
SET SESSION time_zone ='<your timezone>';
Details at https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html
Most connection pools will destroy or cleanup the connection after usage and reset to the default, in any case, if they can vary per client, you want to set those up after each connection by running the
SET SESSION
command above.Having said that, I would strongly recommend to handle timezones on application (presentation) layer and work only in a single timezone on server side (on UTC, preferably, or the local timezone only). While MySQL support is not bad, it can be confusing when handling multiple timezones (a 23:59:60 second, daylight saving changes, etc.). It may take a hard one-time conversion but it will be worth in the long term.