1

I am storing time using a unix timestamp integer for each booking in my database. I am having a problem where my query is not selecting things properly, and seems to be a day off.

For example, on my website I have a calendar table which shows each day of the month. I use the following code in order to populate products for each day:

    $sql = "select b.*, p.name as p_name, p.color as p_color
            from `bookings` as b
            left join `products` as p on (p.id = b.id_product)
            where date_format(from_unixtime(b.timestamp), '%M %e %Y') = date_format(from_unixtime(:timestamp), '%M %e %Y')
            order by b.timestamp asc";
    $stm = $this->app->db->prepare($sql);
    $stm->bindParam(':timestamp', $this->timestamp);
    $stm->execute();
    $res = $stm->fetchAll();

Now, it is showing bookings I made for January 24th on the 25th day in my calendar.

The problem seems to lie with this part of the query:

            where date_format(from_unixtime(b.timestamp), '%M %e %Y') = date_format(from_unixtime(:timestamp), '%M %e %Y')

For example, when $this->timestamp = '1453698000' (the 25th) and b.timestamp = '1453618800' (the 24th), it is showing this record on the 25th in my calendar.

I have absolutely no idea why this is happening. I've tried changing the date_format query to use '%d-%m-%Y', I've tried adding '00:00:00', I've tried manually setting the timezone in the PDO construct, I've made sure all my time zones are lining up correctly (which they are) by echoing the timestamps using the PHP date() function.

Why is this happening? Any help would be greatly appreciated.

kjdion84
  • 9,552
  • 8
  • 60
  • 87

1 Answers1

1

First off, you can debug this more thoroughly by running:

SELECT date_format(from_unixtime(1453698000), '%M %e %Y')

and

SELECT date_format(from_unixtime(1453618800), '%M %e %Y')

and seeing what comes out of each. This should reveal the problem.

I don't know how you thought you set the timezone when passing in a unix timestamp, but I don't think this is possible. The timezone is used to calculate the local time and date from the generic timestamp.

It doesn't matter what timezone PHP thinks each timestamp is in, which is why your PHP date() functions match up. What matters is the timezone your MySQL engine is in as this is where you are doing the conversion.

I would calculate the exact timestamp from the correct datetime in your application (e.g 25th at 00:00:00) and pass it in to the query.

The conversion itself:

 where date_format(from_unixtime(b.timestamp), '%M %e %Y') = date_format(from_unixtime(:timestamp), '%M %e %Y')

invalidates any index on the timestamp, so may lead to slow performance.

It would be better to write this as:

 WHERE b.timestamp >= :timestamp
   AND b.timestamp <  :timestamp + INTERVAL 1 DAY

Your other options is to change the timezone of mysql.

Community
  • 1
  • 1
Arth
  • 12,789
  • 5
  • 37
  • 69