MySQL: Between Night and Morning

skij
skij used Ask the Experts™
on
I use the query below to select all timezones where the current local time is between 11 am and 1 pm.
SELECT *, (EXTRACT(HOUR FROM DATE_ADD(UTC_TIMESTAMP(), INTERVAL `utc_offset` HOUR_MINUTE))) AS `local_hour` from `timezones` HAVING `local_hour` BETWEEN 11 AND 13

Open in new window

The database structure and data are attached.

The query above works perfectly on time ranges that are within the same day, however I would like to be able select into the next day.

For example,
BETWEEN 22 AND 2

I want to select all times between 10 pm today and 2 am tomorrow.
hm.timezones.sql.txt
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Senior Developer
Commented:
you need two intervals: [22;23] & [0;2] or an artificial offset +12 hours added on all values:

(EXTRACT(HOUR FROM DATE_ADD(UTC_TIMESTAMP(), INTERVAL `utc_offset` HOUR_MINUTE)))  BETWEEN 22 AND 2;

=>

(EXTRACT(HOUR FROM DATE_ADD(DATE_ADD(UTC_TIMESTAMP(), INTERVAL `utc_offset` HOUR_MINUTE))), INTERVAL`+12`)  BETWEEN 10 AND 14;
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
A bit of a mouthful but it should work
SELECT *,HOUR(DATE_ADD(TIMEDIFF('22:00:00', UTC_TIME()), INTERVAL 4 HOUR)) + MINUTE(DATE_ADD(TIMEDIFF('22:00:00', UTC_TIME()), INTERVAL 4 HOUR))/60 AS DIFF
  FROM timezones 
  WHERE 
    DATE_ADD(UTC_TIME(), INTERVAL utc_offset HOUR) > '22:00:00'
   AND utc_offset < HOUR(DATE_ADD(TIMEDIFF('22:00:00', UTC_TIME()), INTERVAL 4 HOUR)) + MINUTE(DATE_ADD(TIMEDIFF('22:00:00', UTC_TIME()), INTERVAL 4 HOUR))/60 ;

Open in new window

The query basically looks for records with utc_offset added to the current local time that is after 22:00 and the second part which is a bit more involved.

Take the difference between 22:00 and the current time - add 4 hours to get to 2am and then find where utc_offset is less than this value. We have to use fractions because some timezones work on .5 so we take the hour part of the calculation to find the time difference between now and 2am and add the minute part divided by 60 to get the fraction.

Possibly simpler ways to do this ...
Possibly simpler ways to do this ...
Umm... yes... like passing in dates as opposed to just time :)
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Umm... yes... like passing in dates as opposed to just time :)
Agreed except all we have to work with is utc_offsets - so either have to manufacture the dates (which is just as complex) or find a way of working with the second values.

I think this works - definitely simpler than the above

SELECT *
  FROM timezones 
  WHERE 
     TIME_TO_SEC(UTC_TIME()) + (utc_offset * 3600) BETWEEN (22*3600) AND (26*3600);

Open in new window

Works on the principle of adding the offset (in seconds) to the current seconds value of the UTC_TIME and checking if that falls within 22*3600 and 26*3600
But if all time comparisons are made in the same timezone, then it's fine. So if we re-based all the parameters to specific timezone UTC itself, and if we pass in the startTime and endTime also rebased to UTC itself then it's a low easier. The CONVERT_TZ(NOW(), utc_timezone,'-0:00') would help with rebasing timezones. We have all the information we need to accomplish this
ste5anSenior Developer

Commented:
@Julian: UtcOffset is officially defined as [+|-]hh[:]mm. Using a different format/data type using the same name is semantically misleading.

Author

Commented:
I noticed that and so I changed my format from 1.5 to 1:30 for desired results.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
@ste5an - not sure I follow you? I am working off the data provided by the OP? Did you mean to address the OP?

Author

Commented:
@Julian, the data I posted here (hm.timezones.sql.txt) is in a different format than the data I posted in my previous post.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Ahh - sneaky - the danger of assumptions.

Your previous post linked to this one so made the assumption we were talking about the same data ...

Simple change though
SELECT *, UTC_TIME() 
   FROM timezones
   WHERE 
       TIME_TO_SEC(UTC_TIME()) + TIME_TO_SEC(utc_offset) 
    BETWEEN 
      (22*3600) AND 
      (26*3600);

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial