On all of my tables I have a modified column of type timestamptz and then a trigger that sets it to CURRENT_TIMESTAMP whenever the table is modified. If I'm running on my local box, which is in the PST timezone, and I make a modification, I see it saying 9:10pm my time. Now I log into a system in the EDT timezone (3 hours ahead) and query that same column. Instead of saying 12:10am it's still saying 9:10pm.
That tells me that it is in fact storing a timzeone and isn't just using the epoch value internally.
What's the right thing to be using to store a UTC time whenever this is updated?
My server side is a PHP back-end which grabs the time() output, which is supposed to be the epoch value, and then sends that back to the client on each call. When I call into the server I pass that specific value, and then my SQL query adds an "where modified > to_timestamp(?)" so that I'm only getting items which have been modified since the last time I talked to the server.
Related
We are moving BackEnd tables from a large MS Access application to postgresql.
In one table we have a field ErZei defined in postgres as
time(0) without time zone DEFAULT ('now'::text)::time(0) without time zone
Inside this field only the time value is stored, the day value has his own field.
The linked table inside Access shows the current day in front of the time value. Using the 24-hour format for displaying time values in Access looks fine. But by entering the field, the current day appears automatically.
If I call the time field by SQL-Query SELECT * from ..., I get the same result: everytime the current day value in front of the time value.
Inside postgres everything works fine.
Also a test with a ODBC query tool shows only the time.
How could I configure MS Access to show only the time value without the day in case of postgres time columns?
I can't find an option in the Access globals.
We use
MS Access 2016
ODBC: PostgreSQL Unicode 10.00.00 PSQLODBC35W.DLL
13.10.2017
PostgreSQL 10.1 as backend on ubuntu
Here is my problem:
I want to calculate how long ago a record was updated in a DB.
The DB is in PostgreSQL, the update_time field is populated by a trigger that uses CURRENT_TIMESTAMP(2). The field is inflated to a DateTime object by DBIx::Class. I get the current time in my code using DateTime->now()
My problem is that when I retrieve the field value, it's off by 1 h (ie it's 1h ahead of DateTime->now()). I am in the CET time zone, so 1h ahead of UTC currently.
The right way to solve the problem is likely at the DB level. I have tried to replace CURRENT_TIMESTAMP with LOCALTIMESTAMP, to no avail.
I think actually a more robust solution (ie one that doesn't rely on getting the DB right) would be to get the current time stamp from the DB itself. I really just need the epoch, since that's what I use to compute the difference.
So the question is: is there a simple way to do this: get the current time from the DB using DBIx::Class?
A different way to get the DB and DateTime to agree on what the current time is would also be OK!
You can use dbh_do from your DBIx::Class::Storage to run arbitrary queries. With that, just SELECT the CURRENT_TIMESTAMP.
my ( $timestamp ) = $schema->storage->dbh_do(
sub {
my ($storage, $dbh) = #_;
$dbh->selectrow_array("SELECT CURRENT_TIMESTAMP");
},
);
I always recommend to do all date/time related things on the app server and not rely on the database server(s). Essentially that means to not use a trigger but pass the datetime on insert/update and make it mandatory (NOT NULL).
Besides that you should store datetimes in UTC and convert to your local or other required timezone in your code.
Your issue likely happens because of an incorrect or missing timezone configuartion in which case DateTime defaults to its floating timezone.
I have a table that I am using to store iso dates with timezones. I realize that dates should "always" be stored as utc but I have an exception to that rule. The timestamps aren't in any way related to the server they are running on. I want to be able to store an iso date like this:
2016-03-06T01:15:52-06:00
And regardless of the time zone of the server or anything else I want the timestamp returned as:
2016-03-06T01:15:52-06:00
Currently if I insert an iso date it automatically converts it to whatever the server timezone is. My above date gets converted to:
2016-03-06 07:15:52+00 (server is utc)
The only thing I can think of is storing the timezone offset in a separate column, storing my date as utc and then converting using the offset column, horribly messy. Surely there is a way to store my date in one column and get it out the way it was originally created?
Your proposed solution is correct. Or more precisely, it is one of several correct implementations. Any of the following would work:
Store the UTC timestamp in one field, store the offset in another.
Store the local timestamp in one field, store the offset in another.
Store the local date in one field, and store a time with time zone in another. (though time with time zone is generally discouraged...)
Store the UTC timestamps in one field and the local timestamp in another.
The easiest by far is the first one, which you already proposed.
I'd avoid against storing timestamps in text fields, as they tend not to be very efficiently searchable.
Also note - if you're coming from a SQL Server background, you might recall its datetimeoffset type, which stores the local datetime and offset in the field, and uses the UTC equivalent during indexing. It's common to think that Postgres and MySQL's timestamp with time zone would have the same behavior, but they don't. They simply use the session time zone to convert to/from UTC. SQL Server has no concept of a session time zone, and thus the discrepancy.
Be sure to read this part of the Postgres docs.
I used to insert timestamp into my PostgreSQL table in local time. Now I started to use UTC and I need to find a way to convert all dates/times already inserted to UTC time. How am I supposed to do that?
Pretty easy, in timestamp with time zone, all times are already stored in UTC, the conversion is done when you insert or select them (hours are added or subtracted).
The safest way to remove the "with time zone" attribute would be to set your timezone to UTC,
create a new field that is timestamp (without time zone) and set the data correctly, then drop the old field, re-create it without time zone, then copy the data back in, dropping the column.
Seems like a lot of work, but you could verify your results along the way, if you needed to do any updates or back out altogether, you'd know that there was no chance for data loss.
PostgreSQL 9.3 / postgresql-9.3-1100-jdbc41.jar
I have a table with a column of type timestamp without time zone, this generates my Object with the applicable java.util.Timestamp property.
What I'm seeing, during insert, is jOOQ's binding process converting a java.util.Timestamp into a date with local timezone offset.
eg for a unix timestamp 1421109419 (13 Jan 2015 00:36:59 GMT) the property is set with new Timestamp(1421109419 * 1000).
from the jOOQ logger I see:
2015-01-13 14:14:31,482 DEBUG [http-bio-8002-exec-4] org.jooq.tools.LoggerListener#debug:255 - -> with bind values : insert into "foo"."bar" ("start_date") values (timestamp '2015-01-13 13:36:59.0') returning "foo"."bar"."id"
2015-01-13 14:14:31,483 TRACE [http-bio-8002-exec-4] org.jooq.impl.DefaultBinding#trace:179 - Binding variable 3 : 2015-01-13 13:36:59.0 (class java.sql.Timestamp)
and sure enough in the record is the value "2015-01-13 13:36:59".
The software is running on a machine in NZDT which explains the +13 offset.
Given the time is being supplied in a TimeZone agnostic container (Timestamp) I would have expected that to be honoured when creating the insert statement.
How can I have jOOQ create timestamps NOT in local time?
Unfortunately you have a few things working against you:
The PostgreSQL JDBC driver sets the timezone to your JVM timezone in the Postgres session. So even if your Database Server is running in UTC a TIMESTAMP field will be inserted using the time zone of your JVM. When you insert or query data the database server will always use the JVM time zone.
You are using TIMESTAMP instead of TIMESTAMPTZ. The description of these types do not reflect their actually usage. TIMESTAMPTZ actually means time zone agnostic. Whatever value you insert it will be adjusted to UTC using the session timezone.
Because of these two issues, if you have two different JVMs -- one using Los Angeles time and the other using New York time -- whenever you write a TIMESTAMP with one JVM it will be a different "UTC time" in the other JVM. TIMESTAMP takes the adjusted value and just uses it as given. If you change your TIMESTAMP columns to be TIMESTAMPTZ then the same time in both JVMs will always be the same UTC time.
If you look at the Postgres JDBC Driver's ConnectionFactoryImpl#openConnectionImp you can see where it sets your local JVM's time zone as the time zone for the database server's session zone.
So the only sane way to deal with this is to only ever use TIMESTAMPTZ instead of TIMESTAMP. Here's some more information on this:
PostgreSQL/JDBC and TIMESTAMP vs. TIMESTAMPTZ
http://justatheory.com/computers/databases/postgresql/use-timestamptz.html
The following (very nasty) code works for me:
eventsRecord.setCreatedOn(new Timestamp(System.currentTimeMillis()
- TimeZone.getDefault().getOffset(new Date().getTime())));
Alas jOOQ simply uses the local timezone when saving into PostgreSQL "timestamp without timezone" or MySQL "datetime" fields. The source code evidence for this travesty is here, it does not specify the timezone nor have any facility for the user to override this functionality and specify a timezone. This renders usage of this very basic datatype from jOOQ completely useless, with a multitude of clients all with different timezones writing data to the same field without recording their timezone nor normalizing the data to UTC.
JDBC provides an extra three-argument setTimestamp where the user can specify what timezone is desired (UTC is basically the only value that makes sense). However jOOQ "abstracts" away from JDBC and does not offer this facility.