We have a machine running 24x7. Every day I report the number of pieces it produced per hour. In our case one working day means '2015-06-16 06:00:00' to '2015-06-17 06:00:00' for example.
Here is my code:
select date_trunc('hour', t_el_eventlog.eventtime at time zone 'CET') as hours,
count (distinct t_el_eventlog.serialnumber) as count
from t_el_eventlog
where eventtime at time zone 'CET' between '2015-06-16 06:00:00'
and '2015-06-17 06:00:00'
and sourceid = '44'
group by hours
order by hours asc
My Postgres version: "PostgreSQL 9.4.1, compiled by Visual C++ build 1800, 32-bit"
The data types of two columns which I am dealing with:
eventtime timestamp without time zone sourceid integer NOT NULL
Time zone is "Europe/Berlin".
With the above query I get the information I want, but I have to change the date every day. Is it possible to use the now()
function as default value for my case instead, so that I don't have to change the date manually everyday?
Answer for
timestamp
You need to understand the nature of the data types
timestamp
(timestamp without time zone
) andtimestamptz
(timestamp with time zone
). If you don't, read this first:The
AT TIME ZONE
construct transforms atimestamp
totimestamptz
, which is almost certainly the wrong move for your case:First, it kills performance. Applying
AT TIME ZONE
to the columneventtime
makes the expression not sargable. Postgres cannot use plain indexes oneventtime
. But even without index, sargable expressions are cheaper. Adjust filter values instead of manipulating every row value.You could compensate with a matching expression index, but it's probably just a misunderstanding and wrong anyway.
What happens in that expression?
AT TIME ZONE 'CET'
transforms thetimestamp
valueeventtime
totimestamptz
by appending the time offset of your current time zone. When using a time zone name (not a numeric offset or an abbreviation), this also takes DST rules (daylight saving time) into account, so you get a different offset for "winter" timestamps. Basically you get the answer to the question:What's corresponding UTC timestamp for the given timestamp in the given time zone?
When displaying the result to the user it is formatted as local timestamp with the according time offset for the current time zone of the session. (May or may not be the same as the one used in the expression).
The string literals on the right side have no data type to them, so the type is derived from the assignment in the expression. Since that's
timestamptz
now, both are cast totimestamptz
, assuming the current time zone of the session.What's the corresponding UTC timestamp for the given timestamp for the time zone setting of the current session.
The offset can vary with DST rules.
Long story short, if you always operate with the same time zone:
CET
or'Europe/Berlin'
- same thing for present-day timestamps, but not for historic or (possibly) future ones, you can just cut the cruft.The second problem with the expression:
is almost always wrong withBETWEEN
timestamp
values. See:now()
is the Postgres implementation of the SQL standardCURRENT_TIMESTAMP
. Both returntimestamptz
(nottimestamp
!). You can use either.now()::date
is equivalent toCURRENT_DATE
. Both depend on the current time zone setting.You should have an index of the form:
Or, to allow index-only scans:
If you operate in different time zones, things get more complicated and you should use
timestamptz
for everything.Alternative for
timestamptz
Before the question update, it seemed like time zones matter. When dealing with different time zones, "today" is a functional dependency of the current time zone. People tend to forget that.
To just work with the current time zone setting of the session, use the same query as above. If executed in a different time zone, the results are wrong in actuality. (Applies to the above as well.)
To guarantee a correct result for a given time zone ('Europe/Berlin' in your case) regardless of the current time zone setting of the session, use this expression instead:
Be aware that the
AT TIME ZONE
construct returnstimestamp
fortimestamptz
input and vice-versa.As mentioned at the outset, all the gory details here: