Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL round timestamp seconds down for a postgres pre-created date with milliseconds

I have a query that unfortunately has to compare 2 timestamps. One timestamp is given to the DB from the PHP date() function, stored as timestamp without time zone, so there's no milliseconds added to this date. The other is a PG timestamp with time zone. So both dates have already been created and inserted into the tables, here is an example of the dates:

timestamp without time zone = 2012-09-19 18:13:26

PG's timestamp with time zone = 2012-09-19 18:13:26.893878-04

I can cast the PG date::timestamp(0) which gets me close but as would be expected the date is rounded up; 2012-09-19 18:13:27

So my question is how can I get the seconds to round down?

like image 352
Anthony Avatar asked Sep 20 '12 00:09

Anthony


People also ask

How to round timestamps in PostgreSQL?

How to Round Timestampsin PostgreSQL Rounding/truncating timestamps are especially useful when you're grouping by time. The function you need here is date_trunc: selectdate_trunc('second', now()) -- or minute, hour, day, month Spread the word Tweet Previous How to Group by Time Next

How to select current date and time in PostgreSQL?

Basically, timestamp data type divided into types with and without a time zone. Below is the function of the timestamp data type is as follows. Now function is used to select the current date and time in PostgreSQL.

What is timestamp without time zone in PostgreSQL?

Without time zone: Below example shows timestamp without time zone in PostgreSQL is as follows. Timestamp uses 8 bytes storage space for storing data into the database; timestamp data type is beneficial in PostgreSQL to store the date and time data into the database.

How much storage space does timestamps use in PostgreSQL?

Timestamp uses 8 bytes storage space for storing data into the database; timestamp data type is beneficial in PostgreSQL to store the date and time data into the database. There are three types of timestamp data types in PostgreSQL, i.e. now (), timeofday () and Current_timestamp.


2 Answers

Comparing timestamps for equality is rarely going to work well. What if the two timestamps were taken at 2012-09-19 18:13:26.99999999 ? Clock jitter, scheduler jitter, execution time differences, etc could and often will push one over into the next second. It doesn't have to be that close to the edge to happen, either. You can try hacks with

Compare with a tight range instead; say 2 seconds:

SET timezone = '+04:00';

SELECT (TIMESTAMP '2012-09-19 18:13:26')::timestamptz 
       BETWEEN TIMESTAMPTZ '2012-09-19 18:13:26.893878-04' - INTERVAL '1' SECOND 
           AND TIMESTAMPTZ '2012-09-19 18:13:26.893878-04' + INTERVAL '1' SECOND;

I'm not sure you can use anything coarser than that because the precision of your PHP timestamp is 1 second.

If you know for sure that PHP always truncates the timestamp (rounds down) rather than rounding to even when it captures the timestamp, you can roughly correct for this by adjusting the bracketing intervals. Eg to attempt a 1 second interval (the narrowest you can test for given your timestamp precision from PHP) try, and assuming PHP always truncates the timestamp down:

SELECT (TIMESTAMP '2012-09-19 18:13:26')::timestamptz 
       BETWEEN TIMESTAMPTZ '2012-09-19 18:13:26.893878-04' - INTERVAL '1' SECOND 
           AND TIMESTAMPTZ '2012-09-19 18:13:26.893878-04';

Personally I'd add at least another 0.1 second each side to be sure:

SELECT (TIMESTAMP '2012-09-19 18:13:26')::timestamptz 
       BETWEEN TIMESTAMPTZ '2012-09-19 18:13:26.893878-04' - INTERVAL '1.1' SECOND 
           AND TIMESTAMPTZ '2012-09-19 18:13:26.893878-04' + INTERVAL '0.1' SECOND;

If you really insist on testing for equality, use:

regress=# SELECT date_trunc('second', TIMESTAMPTZ '2012-09-19 18:13:26.893878-04');
       date_trunc       
------------------------
 2012-09-19 18:13:26-04
(1 row)

but be aware it's dangerous and wrong to test two separately captured timestamps for equality.

like image 24
Craig Ringer Avatar answered Oct 15 '22 10:10

Craig Ringer


To round down to the second, use date_trunc('seconds', :timestamp)

Example:

select date_trunc('seconds', '2012-09-19 18:13:26.893878-04'::timestamp)
  = '2012-09-19 18:13:26'::timestamp;

This yields t (true)

like image 70
Daniel Vérité Avatar answered Oct 15 '22 11:10

Daniel Vérité