How to query for "Yesterday, in my timezone" when all my timestamps are UTC - sql

I am trying to include, in my where clause, a way to automatically pull data for the previous day based on my current timezone. All of my data is stored with a UTC timestamp.
I can change my timestamp from UTC to my timezone ("America/Chicago") and I can automatically pull data for the last X days; for example, for the prior week, without having to manually enter a date. But I cannot figure out how to do both simultaneously in my where clause.
SELECT *
FROM `my-data-set`
WHERE
event_time >= CAST(DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY) AS TIMESTAMP)
AND event_time < CAST(DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY) AS TIMESTAMP)
I would like to be able to look at the previous week or day in my timezone, not the previous UTC day.

You can do specify the timezone:
where date(event_time, 'America/Chicago') = date_add(current_date, interval -1 day)
Note that the parentheses are not needed for current_date.
The key to the logic is converting the UTC timestamp to a date in your local time.

Related

MariaDB Find the First Day of the Month and Convert to UTC

I'm using MariaDB and my records are all stored in UTC however I want to be able to find those records that are within the previous 12 calendar months based on my local timezone.
Here's the steps I took:
SELECT
CURRENT_TIMESTAMP() AS Current_Date_And_Time_In_UTC,
CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland') AS Current_Date_And_Time_In_Auckland,
DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) AS Date_In_Auckland,
LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 1 MONTH) AS Last_Day_Previous_Month_In_Auckland,
LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 1 MONTH) + INTERVAL 1 DAY AS First_Day_Current_Month_In_Auckland,
TIMESTAMP(LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 1 MONTH) + INTERVAL 1 DAY, MAKETIME(0,0,0)) AS First_Day_At_Midnight_Current_Month_In_Auckland,
CONVERT_TZ(TIMESTAMP(LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 1 MONTH) + INTERVAL 1 DAY, MAKETIME(0,0,0)), 'Pacific/Auckland','UTC') AS First_Day_At_Midnight_Current_Month_In_UTC
This lead me to using this as my range:
SELECT
CONVERT_TZ(TIMESTAMP(LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 13 MONTH) + INTERVAL 1 DAY, MAKETIME(0,0,0)), 'Pacific/Auckland','UTC') AS Start_DateTime_In_UTC,
CONVERT_TZ(TIMESTAMP(LAST_DAY(DATE(CONVERT_TZ(CURRENT_TIMESTAMP(),'UTC','Pacific/Auckland')) - INTERVAL 1 MONTH) + INTERVAL 1 DAY, MAKETIME(0,0,0)), 'Pacific/Auckland','UTC') AS End_DateTime_In_UTC
Is there a simpler way to achieve the same result?
If you have a column of timestamp datatype, then no offsetting at all should be necessary.
The documentation states:
If a column uses the TIMESTAMP data type, then any inserted values are converted from the session's time zone to Coordinated Universal Time (UTC) when stored, and converted back to the session's time zone when retrieved.
Assuming that the timezone of your session is set to your local timezone, filtering the column against the last 12 months should be as simple as:
where myts >= date_format(current_date, '%Y-%m-01') - interval 12 month
and myts < date_format(current_date, '%Y-%m-01')

Difference between CURRENT_TIMESTAMP and CURRENT_DATE

I want to get the data from the last 28 days and only include complete days. So what I mean is, when I look at the data today at 10:00 AM, it only includes data from yesterday (the completed day) and 28 days before yesterday.
I am creating a live dashboard with figures like this. So I don't want the numbers to change until the day is finished.
Also, I am willing to understand the difference between CURRENT_DATE and CURRENT_TIMESTAMP
For example, in my code, if I use CURRENT_TIMESTAMP, will I get the data from today 10:00 AM back to 28 days ago 10:00 AM? if not, how can I get data in a way numbers change live according to every time I run the code (the average time that data change in the database is 10 minutes).
My simplified code:
select count(id) from customers
where created_at > CURRENT_DATE - interval '28 days'
Maybe I am using wrong code, can you please give me advice on how to get the date in both formats:
include only complete days(does not include today, until the day is
finished)
include hours, from today morning until 28 days back same
time in the morning.
Assuming created_at is of type timestamptz.
include only complete days(does not include today, until the day is
finished)
Start with now() and use date_trunc():
SELECT count(*)
FROM customers
WHERE created_at < date_trunc('day', now())
AND created_at >= date_trunc('day', now() - interval '28 days');
Or work with CURRENT_DATE ...
WHERE created_at < CURRENT_DATE
AND created_at >= CURRENT_DATE - 28;
The result for both depends on the current timezone setting. The "date" functionally depends on your current time zone. The type timestamp with time zone (timestamptz) does not. But the expression date_trunc('day', now()) introduces the same dependency as the "day" is defined by your current time zone. So you need to define which "days" you mean precisely. Basics:
Ignoring time zones altogether in Rails and PostgreSQL
You can subtract integer values from a date to subtract days:
How do I determine the last day of the previous month using PostgreSQL?
now() is a shorter equivalent of CURRENT_TIMESTAMP. See:
Difference between now() and current_timestamp
count(*) is equivalent to count(id) while id is defined NOT NULL, but a bit faster.
I have different results from query for COUNT('e.id') or COUNT(e.id)
include hours, from today morning until 28 days back same time in the morning.
Simply:
WHERE created_at > now() - interval '28 days'
No dependency on the current time zone.

Getting records relative to current date in timezone GMT+8

I wanted to create a report that generate yesterdays records relative to current date in Manila time. Result of the query is wrong until 8AM in Manila time.
I tried subtracting 1 day in current date and convert it in Asia/Manila timezone.
SELECT *
FROM table
WHERE date_field >= current_date at time zone 'Asia/Manila' - interval '1 day'
AND date_field < current_date at time zone 'Asia/Manila'
If today's current date time in manila is 2019-05-25 1AM
My expected result is records from '2019-05-24 00:00:00' - '2019-05-24 23:59:59'
But what I've got is records from '2019-05-23 00:00:00' - '2019-05-23 23:59:59'
Tried running it again at 8AM same date and the result is correct.
This is a little complicated. The current_date is defined at the UTC date. So, when you are calling it, the UTC date is "yesterday", and you are off by one day.
One way to fix this moves the current time into the time zone and then converts to a date:
WHERE date_field >= (current_timestamp at time zone 'Asia/Manila' - interval '1 day')::date AND
date_field < (current_timestamp at time zone 'Asia/Manila')::date

How to get date of yesterday with the time part 00:00:00 in big query?

In big query how do I get the yesterday date with the time part 00:00:00?
DATE Doesn't have time part
if you want yesterday DateTime with 00:00 as time use:
SELECT DATETIME_TRUNC(DATETIME_SUB(CURRENT_DATETIME(), INTERVAL 1 DAY), DAY) as yesterday;
if you want yesterday date use:
SELECT DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) as yesterday;
If you want a time part, then you want either a TIMESTAMP or DATETIME column.
So, either:
SELECT DATETIME(DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) as yesterday_dt,
TIMESTAMP(DATE_ADD(CURRENT_DATE(), INTERVAL -1 DAY)) as yesterday_ts
This code gets you date
SELECT DATEADD(dd, -1, DATEDIFF(dd, 0, GETDATE()));
For different methods check this link
MS SQL Server - How to get Date only from the datetime value?
Below is yet another option for BigQuery standard SQL
#standardSQL
SELECT
TIMESTAMP_SECONDS(86400 * (UNIX_DATE(CURRENT_DATE()) - 1)) yesterday_as_timestamp,
DATETIME(TIMESTAMP_SECONDS(86400 * (UNIX_DATE(CURRENT_DATE()) - 1))) yesterday_as_datetime
with result (as of answer day - April 02, 2019)
Row yesterday_as_timestamp yesterday_as_datetime
1 2019-04-01 00:00:00 UTC 2019-04-01T00:00:00
Note:
DATETIME Represents a year, month, day, hour, minute, second, and subsecond. Range: 0001-01-01 00:00:00 to 9999-12-31 23:59:59.999999.
TIMESTAMP Represents an absolute point in time, with microsecond precision. Range: 0001-01-01 00:00:00 to 9999-12-31 23:59:59.999999 UTC.
A timestamp represents an absolute point in time, independent of any time zone or convention such as Daylight Savings Time.
TIMESTAMP provides microsecond precision.
Unlike Timestamps, a DATETIME object does not refer to an absolute instance in time. Instead, it is the civil time, or the time that a user would see on a watch or calendar.
You can see more details about DATETIME and TIMESTAMP in Data Types doc

Group by time with timezone conversion in Postgresql

I am working with time data that is currently stores in UTC but I want it to be in PST, which is 8 hours behind. I have a pretty lengthy and involved query, but the only thing I am interested in is the time right now so I have included those parts. I want to convert the times to PST and then group by the date for the last week of data. The query has the following structure:
select
date_trunc('day', time1) AT TIME ZONE 'US/Pacific'
...
where
time1 AT TIME ZONE 'US/Pacific' > now() AT TIME ZONE current_setting('TimeZone') - INTERVAL '168 HOURS'
...
group by date_trunc('day', time1)
This results in the following time groupings. From my understanding, it groups from the 0:00 UTC, which is 16:00 in PST. However, I want the groupby to start at 0:00 PST. How do I do this? Right now, the counts in each group are misleading for each day because they go from 4 pm to 4 pm instead of 12 am to 12 am. For example, Sundays have uncharacteristically high counts because Sunday includes part of Monday's data in the groupby. I would appreciate any input to fix this issue. Thank you.
The answer depends on whether it is a timestamp with time zone or one without:
If it's a timestamp with time zone, you can convert to PST with select time1 AT TIME ZONE 'US/Pacific' and get the date with select date_trunc('day', time1 AT TIME ZONE 'US/Pacific')
If it's a timestamp without time zone stored in UTC that you want to convert, you first have to tell PostgreSQL to interpret it as UTC, then convert it, like so: select (time1 AT TIME ZONE 'Z') AT TIME ZONE 'US/Pacific' and of course you can get the date with select date_trunc('day', (time1 AT TIME ZONE 'Z') AT TIME ZONE 'US/Pacific')
In either case you have to convert time zones before truncating to the day level or you may end up with inaccurate results.