Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
20.00% covered (danger)
20.00%
1 / 5
CRAP
90.62% covered (success)
90.62%
58 / 64
Time
0.00% covered (danger)
0.00%
0 / 1
20.00% covered (danger)
20.00%
1 / 5
17.24
90.62% covered (success)
90.62%
58 / 64
 __construct
0.00% covered (danger)
0.00%
0 / 1
3.14
75.00% covered (warning)
75.00%
6 / 8
 fromUnixTime
0.00% covered (danger)
0.00%
0 / 1
2.00
94.12% covered (success)
94.12%
16 / 17
 toUnixTime
0.00% covered (danger)
0.00%
0 / 1
2.01
88.89% covered (warning)
88.89%
8 / 9
 convertMicrosecondsToTime
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
14 / 14
 convertTimeToMicroseconds
0.00% covered (danger)
0.00%
0 / 1
7.10
87.50% covered (warning)
87.50%
14 / 16
<?php
namespace Popy\Calendar\Converter\UnixTimeConverter;
use Popy\Calendar\ValueObject\Time as TimeObject;
use Popy\Calendar\Converter\Conversion;
use Popy\Calendar\Converter\UnixTimeConverterInterface;
use Popy\Calendar\ValueObject\DateTimeRepresentationInterface;
/**
 * Time of the day representation.
 *
 * Fragment units are, usually, named as, and used as :
 * 0 => hours (format symbols ghGH)
 * 1 => minutes (format symbol i)
 * 2 => seconds (format symbol s)
 * 3 => milliseconds (format symbol v)
 * 4 => microseconds (format symbol ยต)
 *
 * Transversal units are, usually, named as and used as :
 * 0 => Internet swatch time (format symbol B).
 */
class Time implements UnixTimeConverterInterface
{
    /**
     * Day length in seconds.
     *
     * @var integer
     */
    protected $dayLengthInSeconds = 24 * 3600;
    /**
     * Time format ranges.
     *
     * @var array<int>
     */
    protected $ranges = [24, 60, 60, 1000, 1000];
    /**
     * Day length in microseconds.
     *
     * @var integer
     */
    protected $dayLengthInMicroSeconds;
    /**
     * Class constructor.
     *
     * @param array|null   $ranges             Time segments ranges/sizes.
     * @param integer|null $dayLengthInSeconds Day length.
     */
    public function __construct(array $ranges = null, $dayLengthInSeconds = null)
    {
        if (null !== $ranges) {
            $this->ranges = $ranges;
        }
        if (null !== $dayLengthInSeconds) {
            $this->dayLengthInSeconds = $dayLengthInSeconds;
        }
        $this->dayLengthInMicroSeconds = $this->dayLengthInSeconds * 1000000;
    }
    /**
     * @inheritDoc
     */
    public function fromUnixTime(Conversion $conversion)
    {
        $input = $conversion->getTo();
        if (!$input instanceof DateTimeRepresentationInterface) {
            return;
        }
        $unixTime = $conversion->getUnixTime();
        $microSec = $conversion->getUnixMicroTime()
            + ($unixTime % $this->dayLengthInSeconds) * 1000000
        ;
        $time = $this->convertMicrosecondsToTime($microSec);
        // Swatch time calculation. It's a fixed earth-day ratio, starting at a
        // fixed +01:00 time offset.
        $time = $time->withTransversal(
            0,
            intval(1000 * ($input->getUnixTime() + 3600) / 86400) % 1000
        );
        // Removing the consumed seconds
        $unixTime -= $unixTime % $this->dayLengthInSeconds;
        $conversion
            ->setUnixTime($unixTime)
            ->setUnixMicroTime(0)
            ->setTo($input->withTime($time))
        ;
    }
    /**
     * @inheritDoc
     */
    public function toUnixTime(Conversion $conversion)
    {
        $input = $conversion->getTo();
        if (!$input instanceof DateTimeRepresentationInterface) {
            return;
        }
        $time = $input->getTime()->withSizes($this->ranges);
        $microsec = $this->convertTimeToMicroseconds($time);
        $conversion
            ->setTo($input->withTime($time))
            ->setUnixTime($conversion->getUnixTime() + intval($microsec / 1000000))
            // Swatch time can return negative time. Shield against that.
            ->setUnixMicroTime(max(0, $microsec % 1000000))
        ;
    }
    /**
     * Convert a time expressed in microseconds, into a Time object.
     *
     * @param integer $time
     *
     * @return TimeObject
     */
    public function convertMicrosecondsToTime($time)
    {
        // Calculating day-ratio;
        // Dividing microseconds per seconds results in the intended value
        $ratio = intval($time / $this->dayLengthInSeconds);
        // If using a different time format, apply ratio
        $timeScale = array_product($this->ranges);
        if ($this->dayLengthInMicroSeconds !== $timeScale) {
            $time = intval(
                ($time * $timeScale) / $this->dayLengthInMicroSeconds
            );
        }
        $len = count($this->ranges);
        $res = array_fill(0, $len, 0);
        for ($i=$len - 1; $i > -1; $i--) {
            $res[$i] = $time % $this->ranges[$i];
            $time = intval($time / $this->ranges[$i]);
        }
        return new TimeObject($res, $this->ranges, $ratio);
    }
    /**
     * Converts a "Time" into its value in its lower unit.
     *
     * @param TimeObject $time
     *
     * @return integer
     */
    public function convertTimeToMicroseconds(TimeObject $time)
    {
        $meaningfull = $time->countMeaningfull() > 0;
        // IF time had no meaningfull informations, fallback to a day ratio.
        if (!$meaningfull && null !== $ratio = $time->getRatio()) {
            return $ratio * $this->dayLengthInSeconds;
        }
        // IF time had no meaningfull informations, use internel swatch time.
        // May not work properly on non-earth systems. Whatever, who uses this
        // anyway ? ANd who will use this on other planets ?
        if (!$meaningfull && null !== $swatch = $time->getTransversal(0)) {
            return $swatch * 1000 * 86400
                - 3600 * 1000000 // minus fixed time offset
            ;
        }
        $len = count($this->ranges);
        $res = 0;
   
        for ($i=0; $i < $len; $i++) {
            $res = $res * $this->ranges[$i] + (int)$time->get($i);
        }
        // If using a different time format, apply ratio
        $timeScale = array_product($this->ranges);
        if ($this->dayLengthInMicroSeconds !== $timeScale) {
            return intval(($res * $this->dayLengthInMicroSeconds) / $timeScale);
        }
        return $res;
    }
}