How can i insert timestamp with timezone in postgresql with prepared statement? - postgresql

I am trying to insert to a timestamp with timezone field of my DB a string which includes date, time and timezone using prepared statement.
The problem is that Timestamp.valueof function does not take into consideration the time zone that the string inludes so it causes an error.
The accepted format is yyyy-[m]m-[d]d hh:mm:ss[.f...] which does not mention timezone.
That is the exact code that causes the error:
pst.setTimestamp(2,Timestamp.valueOf("2012-08-24 14:00:00 +02:00"))
Is there any way that i can overcome it??
Thanks in advance!

The basic problem is that a java.sql.Timestamp does not contain timezone information. I think it is always assumed to be "local timezone".
On solution I can think of is to not use a parameter in a PreparedStatement, but a timezone literal in SQL:
update foo
set ts_col = timestamp with time zone '2012-08-24 14:00:00 +02:00'`;
Another possible solution could be to pass a properly formatted String to a PrepareStatement that uses to_timestamp():
String sql = "update foo set ts_col = to_timestamp(?, 'yyyy-mm-dd hh24:mi:ss')";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, "2012-08-24 14:00:00 +02:00");

I believe that you could use one more field in your database, which would include the time zone. And calculate the time manually after you get these two fields

Related

Knex saves date incorrectly

I have a date field set with table.date('day'); in knex schema. When I insert it with knex('table_name').insert({ someOtherData, day: '2016-08-14'}) and then use knex.select('day').from('table_name') I get [Date: 2016-08-13T22:00:00.000Z]. It seems as if it saves it as '2016-08-14T00:00:00.000Z' and then subtracts 2 hours to conver it into UTC.
This issue may be because of time zone conversion. Have you tried using timestamp?
table.timestamp('response_deadline')
It will convert date datatype to timestamp with time zone.
the docs on schema building seems vague however try to deliver this date string to a js date constructor, i'm pretty sure it will deliver you the correct date.
it tries to represent every date as the specs recommends, that's why you're seeing the date this way.

Postgresql: Convert a date string '2016-01-01 00:00:00' to a datetime with specific timezone

I'm in a tricky situation. A client's database timezone was configured for America/Chicago instead of UTC.
From the app, we ask customers to enter useful dates, and sadly those dates are stored 'as-is', so if they entered '2001-01-01 00:00:00' in the text input, that same value will be stored in the DB, and we are ignoring the customer's timezone. We save that info separately.
The table column is of type TIMEZONETZ. So Postgresql will add the America/Chicago timezone offset at the end: Eg '2001-01-01 00:00:00-02'.
Naturally, most of the customers are not in Chicago.
The difficult part, is that, even knowing the customer's timezone, it's really hard to run calculations on the DB given that the datetime was not correctly pre-processed before storing it into the DB.
My attempted solution, is finding a way to extract the datetime string from the column value, and re-convert it to a date with the right timezone. Eg (pseudo-code):
// This is psuedo code
SELECT DATETIME((SELECT date_string(mycolumn) FROM mytable),
TIMEZONE('America/Managua'));
Which would be equivalent in PHP:
$customerInput = '2016-01-01 00:00:00';
$format = 'Y-m-d H:i:s';
$wrongDateStoredInDb = DateTime::createFromFormat($format, $customerInput, new DateTimezone('America/Chicago'));
// In order to fix that date, I'd extract the dateString and create a new DateTime but passing the correct timezone info.
$customerTimezone = new Timezone('America/Bogota');
$customerInput = $wrongDateStoredInDb->format($format); // Assuming we didn't have it already.
$actualDateTime = DateTime::createFromFormat($format, $customerInput, $customerTimezone);
With that kind of information, I'd be able to run calculations on date ranges, with the correct values, eg:
// Pseudo-code
SELECT * FROM myTable WHERE fix_date_time(columnWithInvalidDate, `correctTimezone`)::timestamp > `sometimestamp`;
I've read the Postgresql docs, and I've tried everything I could, but nothing seems to work.
Any suggestion is more than welcomed!
So you say that you have a timestamptz column. That is not stored as a string, but as an "instant" in microseconds since the epoch. But when you do an INSERT and give a string, Postgres converts your string into a time value automatically, before storing it. It's been assuming the strings you give it are in Chicago time, since that's the default timezone.
Now you want to reinterpret those times as being in the user's time zone instead. To do that, you can put them back into strings (in Chicago time), and then parse them again but with a different time zone.
Suppose you have data like this:
CREATE TABLE t (id int primary key, ts timestamptz, tz text);
SET TIMEZONE='America/Chicago';
INSERT INTO t
VALUES
(1, '2015-01-01 12:00:00', 'America/Managua'),
(2, '2015-01-01 12:00:00', 'America/Los_Angeles')
;
Then this will give you new times that are what the user really meant:
SET TIMEZONE='America/Chicago';
SELECT ts::text::timestamp AT TIME ZONE tz FROM t;
To break it down: ts::text stringifies the value into Chicago time, then we re-parse it, but into a bare timestamp with no timezone information yet. Then we attach a time zone---not Chicago time, but the user's own timezone.
From here you should be able to handle fixing the bad rows (and not the new ones, if you've already changed the server's default timezone).
One caveat is that if a user entered a time and then changed their timezone, there is no way to recover that, so this will interpret that old time incorrectly.

postgresql numeric to timestamp conversion timezone issue

I am trying to convert a numeric to timestamp in postgresql. However, it always converts it in EST timezone. Before running the query, I try the following.
set time zone 'UTC+10';
select to_timestamp(r.date/1000) as current_email_timestamp
FROM email;
However, It the timestamp always seem to be in US timezone. The emails are mostly sent during working hours but when I change the numeric back to timestamp with above query, it shows all the emails at night time
Could it be that the timestamp in numeric was stored in US timezone, or could it be that when converting back from numeric to timestamp, it is not coverting the timezone correctly.
Can someone please tell me how to fix this
Regards
Arif
You can use the at time zone modifier:
select to_timestamp(1411738200),
to_timestamp(1411738200) at time zone 'America/Chicago',
to_timestamp(1411738200) at time zone 'UTC+10'
Your postgres installation probably defaults to EST.

How to pass string with ' ' (timestamp) in prepared statement?

I am trying to execute the following query
INSERT INTO hotspot(timestamp) VALUES
(timestamp with time zone '2012-10-25 14:00:00 +05:00' at time zone 'EET');
and i want to pass the timestamp as a variable.
My timestamp column is type of timestamp with time zone.
Do you have any idea how this can be done?
When i do... (Java, Postgresql)
String stm= "INSERT INTO hotspot(timestamp) VALUES(timestamp with time zone ? at time zone 'EET')";
pst = con.prepareStatement(stm);
pst.setString(1, "2012-08-24 14:00:00 +05:00");
pst.executeUpdate();
I get a syntax error at or near "$1"
Is there anyway i can overcome this error??
Thank you in advance!!
Update: I tried to use the setTimestamp by the following way...
Calendar c=Calendar.getInstance(TimeZone.getTimeZone("GMT+05:00"));
String stm= "INSERT INTO hotspot(timestamp) VALUES(?)";
pst = con.prepareStatement(stm);
pst.setTimestamp(1,Timestamp.valueOf("2012-01-05 14:00:00"), c );
pst.executeUpdate();
I suppose that the correct value in the DB should be (regarding that my local time zone is EET (+02))
2012-01-05 11:00:00 +02
but using pgadmin i check the value and i get
2012-01-05 14:00:00 +02
Any suggestions?
Consider using the setTimestamp() method instead of setString() method. Check this link in order to understand how to use PreparedStatement.
Edit: As I explained in the comment, check the API reference for setTimestamp() with three parameters:
Sets the designated parameter to the given java.sql.Timestamp value,
using the given Calendar object. The driver uses the Calendar object
to construct an SQL TIMESTAMP value, which the driver then sends to
the database. With a Calendar object, the driver can calculate the
timestamp taking into account a custom timezone. If no Calendar object
is specified, the driver uses the default timezone, which is that of
the virtual machine running the application.
Federico Cristina is quite right that setTimestamp is the correct way to do this.
The reason for the syntax error is that you can't specify the type with a leading type-specifier when passing a parameter. The INTEGER '4' style is only valid for literals, not parameters.
Your code will be PREPAREd then EXECUTEd at the protocol level. Here's what happens if I PREPARE it:
regress=> PREPARE blah(timestamptz) AS INSERT INTO hotspot(timestamp) VALUES(timestamp with time zone $1 at time zone 'EET');
ERROR: syntax error at or near "$1"
LINE 1: ...otspot(timestamp) VALUES(timestamp with time zone $1 at time...
Since the data type is specified in the query parameter you can omit it, writing instead:
String stm= "INSERT INTO hotspot(\"timestamp\") VALUES(? at time zone 'EET')";
Note that I've double-quoted "timestamp" as well, because it's a reserved word. It'll work without quotes in some contexts but not others. Choosing a data type name or reserved word as a column name is generally a bad idea.

How do extract just the date (without the time) from an integer field in SQLite3?

I have a small SQLite3 DB that has an integer field called "dt". It stores date and time.
I am having trouble extracting just the date from the field. However, doing a "select date(dt) from log2" returns nothing. I've tried strftime() as well, but no cigar.
Please help. This is driving me insane.
Thanks.
if the Date in dt is wellformed then the result shoeld be the date from a datetime column
select date('2011-01-01 23:55:55');
should receive
2011-01-01
but
select date('2011-01-01 23:55:5');
would receive nothing
so the dt coloum have to be wellformed