This year, I'm working with/mentoring a paid intern on a device monitoring project for a portion of our fleet. These sort of projects are always fun and meaningful in that we identify a problem or opportunity to improve, and then solve said problem in a way we've not done before. It works out well for everyone involved because we get an improved process or "thing," the intern gains some practical experience and skills (often with stuff they've never encountered), and the intern gets paid to boot.
This fall's project boils down to a client/server check-in system, with appropriate "proactive" notification when things start to look out of place. And so far the progress is going as planned.
During this week's check-in, an oddity was identified with regard to the date math (timestamp differences), and it was time to dig in to figure out what was happening. Before I had a chance to jump over to the codebase, the intern identified the discrepancy:
For some reason the time being returned (by the clients) is five hours ago?
That statement immediately told me the underlying issue: timezone discrepancies in the date math.
We're just about done with daylight saving time, and this led into a good conversation about how today (at the time of the conversation) the offset was five hours, but come next week it'll be six hours...and any potential straight math solution would need maintenance. So, what to do?
Find the Time Zone Discrepancy
One of these things is not like the other: so which one is "broken?" Turns out, neither are really "wrong" but they're not in sync. This could be fixed on either side by forcing UTC on the clients checking in...or fixed by adjusting the server side to the local timezone. Slightly complicating the implementation is that clients are running Windows/Powershell, and the server side is Linux/PHP.
Implement the Fix
Fortunately, both Powershell and PHP provide options and built-in functions to work with this. Initially we made the server side change to ensure the rest of the system would behave. It was relatively simple (thanks to some Google inquiries). However, the longer-term solution is to standardize this on the clients (output as UTC), which we can do with a simpler call in Powershell, as illustrated below.
PHP, Server Side (convert to localized timezone)
Before:
$localTime = time();
After (adds timezone_offset_get
and timezone_open
functions):
$localTime = time() + timezone_offset_get(timezone_open('America/Chicago'), new DateTime());
Powershell, Client Side (convert to UTC)
Before:
$timeStamp = [math]::Truncate((New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds)
After (adds ToUniversalTime()
call:
$timeStamp = [math]::Truncate((New-TimeSpan -Start (Get-Date "01/01/1970") -End ((Get-Date).ToUniversalTime())).TotalSeconds)
Test and Move On
Making both of the changes above would not solve the problem, only switch the "failure" point. In the end, using a conversion on the server side is acceptable (and would be the preference if the disparate clients were already fully deployed). Since we haven't rolled out the client bit other than on a small number of test machines, the better long-term fix for us was to implement the client side change to force UTC timestamps.
We're not really doing much with date math in the aforementioned, but making sure the timestamps are common on both sides is critical to ensure the next steps behave as planned. And speaking from other random projects and side/playground projects I've fiddled with (such as my Holiday Progress Twitter Bot), the most gross (or egregious) bits always comes down to the upfront handling of timezones and their appropriate conversions. The rest is simple.