TimeSpan fixes.

This commit is contained in:
flash 2020-12-28 18:32:43 +00:00
parent b1a6a4d047
commit 0fa0ac0d1b

View file

@ -23,7 +23,7 @@ class FWIF {
public const TYPE_ARRAY = 0x05; // List of values, terminated with TRAILER public const TYPE_ARRAY = 0x05; // List of values, terminated with TRAILER
public const TYPE_OBJECT = 0x06; // List of values with ASCII names, terminated with TRAILER public const TYPE_OBJECT = 0x06; // List of values with ASCII names, terminated with TRAILER
public const TYPE_DATETIME = 0x07; // A gregorian year, month and day as well as an hour, minute, seconds and millisecond component, variable ranging from 4 to 7 bytes public const TYPE_DATETIME = 0x07; // A gregorian year, month and day as well as an hour, minute, seconds and millisecond component, variable ranging from 4 to 7 bytes
public const TYPE_TIMESPAN = 0x08; // A period of time, follows the same format DATETIME but uses an additional flag to indicate negative periods public const TYPE_TIMESPAN = 0x08; // A period of time, containing days, hours, minutes, seconds and milliseconds, variable ranging from 4 to 6 bytes
public const TRAILER = 0xFF; // Termination byte public const TRAILER = 0xFF; // Termination byte
@ -409,8 +409,7 @@ class FWIF {
return new DateTimeImmutable($dt . 'UTC'); return new DateTimeImmutable($dt . 'UTC');
} }
private const TIMESPAN_FLAG_YEAR = 0x10000000; private const TIMESPAN_FLAG_DAYS = 0x20000000;
private const TIMESPAN_FLAG_DMY = 0x20000000;
private const TIMESPAN_FLAG_NEGA = 0x40000000; private const TIMESPAN_FLAG_NEGA = 0x40000000;
private const TIMESPAN_MILLI_SHIFT = 16; // << private const TIMESPAN_MILLI_SHIFT = 16; // <<
@ -419,19 +418,16 @@ class FWIF {
private const TIMESPAN_SECS_SHIFT = 11; // << private const TIMESPAN_SECS_SHIFT = 11; // <<
private const TIMESPAN_MINS_SHIFT = 5; // << private const TIMESPAN_MINS_SHIFT = 5; // <<
private const TIMESPAN_DAYS_SHIFT = 10; // << private const TIMESPAN_DAYS_MASK = 0x7FFF;
private const TIMESPAN_MONTH_SHIFT = 6; // <<
private const TIMESPAN_YEAR_HI_MASK = 0x3F00; private const TIMESPAN_YEAR_DAYS = 365.0;
private const TIMESPAN_YEAR_HI_SHIFT = 8; // >> private const TIMESPAN_MONTH_DAYS = 31.0;
private const TIMESPAN_YEAR_LO_MASK = 0x00FF;
/* +--------+--------+ w - unsigned 10-bit millisecs y - Y enable flag /* +--------+--------+ w - unsigned 10-bit millisecs n - Negative flag
* |.ndy.www|wwwwwwwS| S - unsigned 6-bit seconds D - unsigned 5-bit day * |.nd..www|wwwwwwwS| S - unsigned 6-bit seconds d - DMY enable flag
* |SSSSSmmm|mmmHHHHH| m - unsigned 6-bit minutes M - unsigned 4-bit month * |SSSSSmmm|mmmHHHHH| m - unsigned 6-bit minutes D - unsigned 15-bit day
* |.DDDDDMM|MMYYYYYY| H - unsigned 5-bit hours Y - unsigned 14-bit year * |.DDDDDDD|DDDDDDDD| H - unsigned 5-bit hours
* |YYYYYYYY| | n - Negative flag * +--------+--------+
* +--------+--------+ d - DMY enable flag
*/ */
private static function encodeTimeSpan(DateInterval $di, int $flags): string { private static function encodeTimeSpan(DateInterval $di, int $flags): string {
@ -441,24 +437,18 @@ class FWIF {
$wsmh |= ( $di->i & self::DATETIME_MINS_MASK) << self::TIMESPAN_MINS_SHIFT; $wsmh |= ( $di->i & self::DATETIME_MINS_MASK) << self::TIMESPAN_MINS_SHIFT;
$wsmh |= ( $di->h & self::DATETIME_HOUR_MASK); $wsmh |= ( $di->h & self::DATETIME_HOUR_MASK);
if($di->d > 0 || $di->m > 0 || $di->y > 0) { $days = $di->days;
$wsmh |= self::TIMESPAN_FLAG_DMY; if($days === false) // Best I can come up with on short notice, fuck it
$dmy = ($di->d & self::DATETIME_DAY_MASK) << self::TIMESPAN_DAYS_SHIFT; $days = (int)($di->d + ($di->m * self::TIMESPAN_YEAR_DAYS) + ($di->y * self::TIMESPAN_MONTH_DAYS));
$dmy |= ($di->m & self::DATETIME_MONTH_MASK) << self::TIMESPAN_MONTH_SHIFT;
if($di->y > 0) { if($days > 0) {
$wsmh |= self::TIMESPAN_FLAG_YEAR; $wsmh |= self::TIMESPAN_FLAG_DAYS;
$dmy |= ($di->y & self::TIMESPAN_YEAR_HI_MASK) >> self::TIMESPAN_YEAR_HI_SHIFT; $days &= self::TIMESPAN_DAYS_MASK;
$y = ($di->y & self::TIMESPAN_YEAR_LO_MASK);
}
} }
$packed = pack('N', $wsmh); $packed = pack('N', $wsmh);
if($wsmh & self::TIMESPAN_FLAG_DMY) { if($wsmh & self::TIMESPAN_FLAG_DAYS)
$packed .= pack('n', $dmy); $packed .= pack('n', $days);
if($wsmh & self::TIMESPAN_FLAG_YEAR)
$packed .= chr($y);
}
return $packed; return $packed;
} }
@ -472,16 +462,13 @@ class FWIF {
$di->i = ($wsmh >> self::TIMESPAN_MINS_SHIFT) & self::DATETIME_MINS_MASK; $di->i = ($wsmh >> self::TIMESPAN_MINS_SHIFT) & self::DATETIME_MINS_MASK;
$di->h = $wsmh & self::DATETIME_HOUR_MASK; $di->h = $wsmh & self::DATETIME_HOUR_MASK;
if($wsmh & self::TIMESPAN_FLAG_DMY) { if($wsmh & self::TIMESPAN_FLAG_DAYS) {
$dmy = unpack('n', fread($data, 2))[1]; $days = unpack('n', fread($data, 2))[1] & self::TIMESPAN_DAYS_MASK;
$di->d = ($dmy >> self::TIMESPAN_DAYS_SHIFT) & self::DATETIME_DAY_MASK; $di->days = $days;
$di->y = (int)floor($days / self::TIMESPAN_YEAR_DAYS);
// OOPS! THESE WILL BE HORRIBLY INACCURATE! $days -= $di->y * self::TIMESPAN_YEAR_DAYS;
// Perhaps go back to the drawing board and tack months and years onto days? $di->m = (int)ceil($days / self::TIMESPAN_MONTH_DAYS);
$di->m = ($dmy >> self::TIMESPAN_MONTH_SHIFT) & self::DATETIME_MONTH_MASK; $di->d = max(0, $days - ($di->m * self::TIMESPAN_MONTH_DAYS));
if($wsmh & self::TIMESPAN_FLAG_YEAR)
$di->y = ord(fgetc($data))
| (($dmy << self::TIMESPAN_YEAR_HI_SHIFT) & self::TIMESPAN_YEAR_HI_MASK);
} }
return $di; return $di;