PHP - determining midday using UTC time with timezone offset

Viewed 31

Given a time in UTC and the timezone offset, I want to establish a four hour window centred on Midday localtime.

This function has been in active use in a radio database and I now learn has been giving inconsistent results for over 15 years without anyone realizing it until now.

The problem is that it doesn't register the full four hour window when the timezone offset is between -10 and -12, or +10 and +12.

Here's my simplified PHP test code which produces the results described above:

<?php
function convertHtoHH($value) {
    // Takes hour as an integer and formats it as hh
    return
        ($value < 0 ? '-' : '')
        . substr('00', 0, 2 - strlen(abs($value)))
        . abs($value);
}

function isDaytime($hhmm, $timezone) {
    // Supposed to return 'true' if time is within two hours of noon local time
    return ($hhmm + 24 >= ($timezone * -1) + 34)
        && ($hhmm + 24 <  ($timezone * -1) + 38);
}
?>
<html>
<head>
    <title>Daytime Tester</title>
</head>
<body>
<h1>Daytime Tester</h1>
<table border='1' cellpadding='1' cellspacing='0'>
    <thead>
        <tr>
            <th rowspan='2'>&nbsp;<br>Local</th>
            <th colspan='24' style='text-align: center'>UTC</th>
        </tr>
        <tr>
<?php for ($u = 0; $u < 24; $u++): ?>
    <th><?php echo convertHtoHH($u); ?></th>
<?php endfor; ?>
        </tr>
    </thead>
    <tbody>
<?php for ($l = -12; $l <= 12; $l++): ?>
    <?php $local = convertHtoHH($l); ?>
        <tr>
            <th><?php echo $local; ?></th>
    <?php for ($u=0; $u<24; $u++): ?>
        <?php $UTC = convertHtoHH($u); ?>
        <?php $DT = isDaytime($UTC, $l); ?>
            <td><?php echo ($DT ? 'Y' : ''); ?></td>
    <?php endfor; ?>
        </tr>
<?php endfor; ?>
        </tbody>
    </table>
</body>
</html>

When executed, the above code generates this test result set: Output, with missing values shown in red

Clearly the following function provides an incomplete result:

function isDaytime($hhmm, $timezone) {
    return ($hhmm + 24 >= ($timezone * -1) + 34)
        && ($hhmm + 24 <  ($timezone * -1) + 38);
}

Can anyone help me solve this conundrum?

1 Answers

You can simplify isDaytime by using a modulus operator. By adding 24 and taking the modulus 24, we can guarantee that the range of $timeModulo is 0 - 24 and not negative or otherwise weird.

function isDaytime($hhmm, $timezone) {
    $timeModulo = ($hhmm + $timezone + 24) % 24;
    return $timeModulo >= 10 && $timeModulo < 14;
}
Related