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_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_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
@ -409,8 +409,7 @@ class FWIF {
return new DateTimeImmutable($dt . 'UTC');
}
private const TIMESPAN_FLAG_YEAR = 0x10000000;
private const TIMESPAN_FLAG_DMY = 0x20000000;
private const TIMESPAN_FLAG_DAYS = 0x20000000;
private const TIMESPAN_FLAG_NEGA = 0x40000000;
private const TIMESPAN_MILLI_SHIFT = 16; // <<
@ -419,19 +418,16 @@ class FWIF {
private const TIMESPAN_SECS_SHIFT = 11; // <<
private const TIMESPAN_MINS_SHIFT = 5; // <<
private const TIMESPAN_DAYS_SHIFT = 10; // <<
private const TIMESPAN_MONTH_SHIFT = 6; // <<
private const TIMESPAN_DAYS_MASK = 0x7FFF;
private const TIMESPAN_YEAR_HI_MASK = 0x3F00;
private const TIMESPAN_YEAR_HI_SHIFT = 8; // >>
private const TIMESPAN_YEAR_LO_MASK = 0x00FF;
private const TIMESPAN_YEAR_DAYS = 365.0;
private const TIMESPAN_MONTH_DAYS = 31.0;
/* +--------+--------+ w - unsigned 10-bit millisecs y - Y enable flag
* |.ndy.www|wwwwwwwS| S - unsigned 6-bit seconds D - unsigned 5-bit day
* |SSSSSmmm|mmmHHHHH| m - unsigned 6-bit minutes M - unsigned 4-bit month
* |.DDDDDMM|MMYYYYYY| H - unsigned 5-bit hours Y - unsigned 14-bit year
* |YYYYYYYY| | n - Negative flag
* +--------+--------+ d - DMY enable flag
/* +--------+--------+ w - unsigned 10-bit millisecs n - Negative flag
* |.nd..www|wwwwwwwS| S - unsigned 6-bit seconds d - DMY enable flag
* |SSSSSmmm|mmmHHHHH| m - unsigned 6-bit minutes D - unsigned 15-bit day
* |.DDDDDDD|DDDDDDDD| H - unsigned 5-bit hours
* +--------+--------+
*/
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->h & self::DATETIME_HOUR_MASK);
if($di->d > 0 || $di->m > 0 || $di->y > 0) {
$wsmh |= self::TIMESPAN_FLAG_DMY;
$dmy = ($di->d & self::DATETIME_DAY_MASK) << self::TIMESPAN_DAYS_SHIFT;
$dmy |= ($di->m & self::DATETIME_MONTH_MASK) << self::TIMESPAN_MONTH_SHIFT;
$days = $di->days;
if($days === false) // Best I can come up with on short notice, fuck it
$days = (int)($di->d + ($di->m * self::TIMESPAN_YEAR_DAYS) + ($di->y * self::TIMESPAN_MONTH_DAYS));
if($di->y > 0) {
$wsmh |= self::TIMESPAN_FLAG_YEAR;
$dmy |= ($di->y & self::TIMESPAN_YEAR_HI_MASK) >> self::TIMESPAN_YEAR_HI_SHIFT;
$y = ($di->y & self::TIMESPAN_YEAR_LO_MASK);
}
if($days > 0) {
$wsmh |= self::TIMESPAN_FLAG_DAYS;
$days &= self::TIMESPAN_DAYS_MASK;
}
$packed = pack('N', $wsmh);
if($wsmh & self::TIMESPAN_FLAG_DMY) {
$packed .= pack('n', $dmy);
if($wsmh & self::TIMESPAN_FLAG_YEAR)
$packed .= chr($y);
}
if($wsmh & self::TIMESPAN_FLAG_DAYS)
$packed .= pack('n', $days);
return $packed;
}
@ -472,16 +462,13 @@ class FWIF {
$di->i = ($wsmh >> self::TIMESPAN_MINS_SHIFT) & self::DATETIME_MINS_MASK;
$di->h = $wsmh & self::DATETIME_HOUR_MASK;
if($wsmh & self::TIMESPAN_FLAG_DMY) {
$dmy = unpack('n', fread($data, 2))[1];
$di->d = ($dmy >> self::TIMESPAN_DAYS_SHIFT) & self::DATETIME_DAY_MASK;
// OOPS! THESE WILL BE HORRIBLY INACCURATE!
// Perhaps go back to the drawing board and tack months and years onto days?
$di->m = ($dmy >> self::TIMESPAN_MONTH_SHIFT) & self::DATETIME_MONTH_MASK;
if($wsmh & self::TIMESPAN_FLAG_YEAR)
$di->y = ord(fgetc($data))
| (($dmy << self::TIMESPAN_YEAR_HI_SHIFT) & self::TIMESPAN_YEAR_HI_MASK);
if($wsmh & self::TIMESPAN_FLAG_DAYS) {
$days = unpack('n', fread($data, 2))[1] & self::TIMESPAN_DAYS_MASK;
$di->days = $days;
$di->y = (int)floor($days / self::TIMESPAN_YEAR_DAYS);
$days -= $di->y * self::TIMESPAN_YEAR_DAYS;
$di->m = (int)ceil($days / self::TIMESPAN_MONTH_DAYS);
$di->d = max(0, $days - ($di->m * self::TIMESPAN_MONTH_DAYS));
}
return $di;