Comparing dates with timezone getting wrong evaluation - php

I have a service where users can create events and participate in said events. On event creation, users can assign the start, end dates and times and then fill in the timezone that the event is going to take place in. Upon completion they can invite other users to participate in the event.
When members visit the event page a piece of backend logic checks current time against the event's start time. If the current time (of the user/user's timezone) is within the start and end time of the event, the user will then be able to attend the event (giving them access to a hallway page where they can video conference).
My issue is with the comparison of dates with different timezones. I'm saving all the dates with the default UTC timezone. Example of a start date being
date: 2019-07-27 11:00:00.0 UTC (+00:00)
And then comparing $now with it. $now being the below for example
date: 2019-07-27 18:11:18.747797 Asia/Beirut (+03:00)
$now is being assigned as such
$now = Carbon::now()->tz($userProfile->timezone->key);
But when I do a comparison such as
$now->lte($event->ends_at)
I'm getting a wrong evaluation where even if $now is later than $event->ends_at it is still evaluating as true. Is it a matter of evaluating dates with different timezones?

lte()rely on<=` PHP operator as PHP do it for DateTime objects and it compares naively only numbers. So you should compare only dates in the same timezone (ideally on UTC dates).
$now->copy()->tz('UTC')->lte($event->ends_at->copy()->tz('UTC'))
The ->copy() calls are not needed if you're working with CarbonImmutable (recommended).

Related

compare date and time with users timezone php

I'm creating an auction site where time and date is inserted in following format:
Auction Date : 08/20/2015 # 05:30 PM IST
I want to match this time with my user's time and dont want to show auctions which have passed the start date as per users time zone. Assume users may come from different timezones.
Can someone please guide me on this.
You would have to storage your user's timezone somewhere for comparisson purposes. This means your user's model (user's specific info in your system) must know about their timezone.
Then in PHP you have the DateTime and DateTimeZone classes to play with it.
To give you an example, and this is in the docs you can instantiate DateTime like this:
$dt = new DateTime("your date string", new DateTimeZone("[timezone_location_string]"));
You can compare DateTime objects with the PHP comparisson operators (<,>,>=,<=,==) which is pretty nice.
And here you have a list of timezones used in PHP for instantiating objects like DateTimeZone():
http://php.net/manual/en/timezones.php

How can I handle both all-day and timed events while dealing with timezones?

I'm creating a calendar that should supoprt both all-day events, and start/end times. The website also has to deal with the user's timezone.
My questions is:
- Events with a start/end time should be localized to the user's timezone, the day of the event may change, and that's the expected functionality.
- All day events should ALWAYS be the same date for all users.
I'm storing the dates in the database as UNIX timestamps, and I'm having trouble with dealing with both of these requirements gracefully.
Thanks!
You can store a single UTC datetime value and adjust it according to (1) user's timezone (See CONVERT_TZ) and (2) an indicator on the event indicating if it is all-day or not. If not all-day, convert the datetime to a date (without timezone conversion), otherwise apply the timezone conversion mentioned above. If you want to save on database fields, use a second datetime for the end, leaving it null for all-day events.

PHP time calculation with different days and timezones

I'm working on a PHP solution for a radio station at the moment that requires me to determine whether the current time ("H:I" format) is between a set time frame.
The schedule comprises of intervals of 2 hours (starting at either 12midnight or 1am). This schedule is changeable dependent on a user selected timezone (or default setting).
The issue I'm having is determining whether the current time is between any of these times. For example, whether 2am is between 00:00 and 02:00, 04:00 etc.
Ultimately, I want to highlight the timeframe in which the current time falls.
I apologise if I'm being unclear in anything I've put, and I can explain further if necessary.
Use DateTime and DateInterval classes: http://hu1.php.net/datetime . I don't think different day and timezone is an issue in them...

How to deal with timezones between server and client?

I'm developing a website where I have to deal with different possible timezones from the users. This becomes a great problem since the website hosts time-delicate events like auctions.
All dates/times on the server are in UTC. Database stores everything in UTC timestamps. PHP default timezone is set to UTC too (date_default_timezone_set('UTC');).
Now, my problem is how I should interact with the users, whether I'm only showing a date or, more important, I'm reading a date/time from user input.
A concrete example:
An auction has a deadline, which I store in database as UTC.
When I view the auction on the website, a javascript timer uses a Date object to calculate the remaining time. It automatically converts the timezone to GMT+0100 (my local timezone). So if the deadline is '2013-08-08 10:46:08' (UTC), the javascript date object will return Aug 08 2013 11:26:15 GMT+0100 (GMT Standard Time).
If the current time is greater than 11:46:08 then the timer says that the remaining time is 00:00 (which is correct).
But if I try to insert a bid, the server accepts since the condition on the MySQL INSERT evaluates to true:
INSERT INTO Bids ... WHERE ... AND auction_deadline > NOW() ...
( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')
All this mumbo jumbo of timezone melts my brains. What am I missing here? I'm almost certain that storing all dates/times in UTC inside the database is the best. I just can't think crystal clear how do deal with it between the user and the database.
Your problem doesn't involve timezones at all, just the fact that clients can turn their clocks or have their clock skewed considerably. For that the fix is to poll the server every once in a while for an offset fix to use in calculations.
In fact, you don't even need date objects. There is a certain universal instant in time when the auction ends. Let's say it is 1375960662823. Right now, the universal instant in time is 1375960669199, so from that we see that the auction ends in 6 seconds (1375960662823 - 1375960669199 ~ 6000 ). It will end in 6 seconds regardless if I am in Morocco or Japan. Do you understand it yet?
To generate these numbers, on the client side you can call var now = Date.now() + skewFix where skewFix is the correction that needs to applied in case client has time skew or manually set their computer to wrong time.
In PHP, you can generate it with $now = time() * 1000;
This is rather a typical subject yet very complex for most to understand. First thing, you never mention the DAYLIGHT SAVING. yeah I am increasing your tension :).
Now let us see how we can do this. You did a good job by saving the Time in UTC. Now, I hope you have registered members and that each member has ability to set their preferred timezone, otherwise you will show Server' timezone based time to them.
When you through "start time" to user you must send them after converting UTC time to their time, similarly when you accept TIME from browser be it user action or javascript you need to convert that time to UTC considering the fact that user is that time zone that he select for his profile.
Hope that clear the idea on where you are going wrong? Please read through day light saving as that will play an important role too when you move ahead with other logic on same.
EDIT:
You can use javascript's Timezone offset, for auto submission and user input based on his settings.
Date in JavaScript uses local timezone. You should get UTC time for the user and send it to the server
new Date
Thu Aug 08 2013 17:00:14 GMT+0530 (India Standard Time)
(new Date("Thu Aug 08 2013 17:00:14")).toUTCString();
"Thu, 08 Aug 2013 11:30:14 GMT"
This will resolve the timezone issue between the server and client.
You said
( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')
In MySQL - NOW returns the current time in the server's local time zone (docs).
You probably want something like UTC_TIMESTAMP which returns the current time in UTC (docs).
Also - you probably shouldn't accept any input time from the client JavaScript at all. Only trust your own clock. When a bid is placed, use the time on your server in MySQL or in PHP. Don't accept it as input.
You can do the following
once page is loaded, send an ajax request to server with timezone offset of user. You can get timezone offset using the following code.
var curdate = new Date()
var offset = curdate.getTimezoneOffset()
offset is timezone offset in minute.
I think it will help.
everytime when you get the date from the clientside, you can use the getUTC to convert to UTC date ie:
var todayDate = new Date();
var todayDateInUTC = new Date(todayDate.getUTCFullYear(), todayDate.getUTCMonth(), todayDate.getUTCDate(), todayDate.getUTCHours(), todayDate.getUTCMinutes(), todayDate.getUTCSeconds());
so right before you insert the bid date to database, use the getUTC functions to convert it into UTC format.

Timezone and Daylight Savings Issues

I've looked through the other solutions on SO and none of them seem to address the timezone/dst issue in the following regard.
I am making calls to NOAA Tide Prediction API and NOAA National Weather Service API which require a time range to be passed for retrieving data. For each location in my database, I have the timezone as a UTC offset and whether daylight savings time is observed (either 1 or 0). I'm trying to format some dates (todays and tomorrow) to be what the LST (Local Standard Time) would be in it's own timezone so I can pass to these API's.
I'm having trouble figuring out how to know if a date, such as todays, is within the daylight savings time range or not.
Here is what I have so far:
// Get name of timezone for tide station
// NOTE: $locationdata->timezone is something like "-5"
$tz_name = timezone_name_from_abbr("", $locationdata->timezone * 3600, false);
$dtz = new DateTimeZone($tz_name);
// Create time range
$start_time = new DateTime('', $dtz);
$end_time = new DateTime('', $dtz);
$end_time = $end_time->modify('+1 day');
// Modify time to match local timezone
$start_time->setTimezone($dtz);
$end_time->setTimezone($dtz);
// Adjust for daylight savings time
if( $locationdata->dst == '1' )
{
// DST is observed in this area.
// ** HOW DO I KNOW IF TODAY IS CURRENTLY DST OR NOT? **
}
// Make call to API using modified time range
...
How can I go about doing this? Thanks.
You can use PHP's time and date functions:
$tzObj = timezone_open($tz_name);
$dateObj = date_create("07.03.2012 10:10:10", $tzObj);
$dst_active = date_format($dateObj, "I");
If DST is active on the given date, $dst_active is 1, else 0.
Instead of specifying a time in the call to date_create you can also pass "now" to receive the value for the current date and time.
However, like Jon mentioned, different countries within the same timezone offset may observe DST while others may not.
For each location in my database, I have the timezone as a UTC offset and whether daylight savings time is observed (either 1 or 0).
That's not enough information. There can be multiple time zones which all have the same standard offset, all observe DST, but perform DST transitions at different times. (Indeed, historically they may also start and stop observing daylight saving time for several years.)
Basically, your database should contain a time zone ID, not the offset/DST-true-or-false. (Assuming PHP uses the zoneinfo time zone database, a time zone ID is something like "Europe/London".)
EDIT: To find the offset of a given DateTime, you can call getOffset, which you can then compare with the standard time offset. But unless you have the definitive time zone ID, you will be risking getting the wrong zone.
Cillosis,
I hope you are not working with Java! I am and fought with time all the time. I also work with weather data. Most of the data I use is in local standard time (ignoring daylight saving time). I also need to use times from other time zones and found that Java kept reading my computer's time zone. I also kept running into deprecated classes. I came up with a solution that works. It is a bit of a kluge, so I have it heavily documented and it only exists in one function. My solution is relative time. I have set the local time to UTC. I am subtracting the GMT offset instead of adding it. I don’t really care about the actual times, all I care about is the difference between two times. It is working very well.
Good luck

Categories