Code Coverage  | 
     ||||||||||
Classes and Traits  | 
      Functions and Methods  | 
      Lines  | 
     ||||||||
| Total |         | 
      0.00%  | 
      0 / 1  | 
              | 
      60.00%  | 
      3 / 5  | 
      CRAP |         | 
      85.71%  | 
      66 / 77  | 
     
| TimeOffset |         | 
      0.00%  | 
      0 / 1  | 
              | 
      60.00%  | 
      3 / 5  | 
      22.29 |         | 
      85.71%  | 
      66 / 77  | 
     
| fromUnixTime |         | 
      100.00%  | 
      1 / 1  | 
      2 |         | 
      100.00%  | 
      10 / 10  | 
     |||
| toUnixTime |         | 
      100.00%  | 
      1 / 1  | 
      2 |         | 
      100.00%  | 
      6 / 6  | 
     |||
| getOffsetFor |         | 
      0.00%  | 
      0 / 1  | 
      9.95 |         | 
      68.75%  | 
      22 / 32  | 
     |||
| extractAbbreviation |         | 
      0.00%  | 
      0 / 1  | 
      8.02 |         | 
      93.75%  | 
      15 / 16  | 
     |||
| anonymous function |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      2 / 2  | 
     |||
| <?php | |
| namespace Popy\Calendar\Converter\UnixTimeConverter; | |
| use DateTimeZone; | |
| use DateTimeImmutable; | |
| use Popy\Calendar\Converter\Conversion; | |
| use Popy\Calendar\ValueObject\TimeOffset as TimeOffsetValue; | |
| use Popy\Calendar\Converter\UnixTimeConverterInterface; | |
| use Popy\Calendar\ValueObject\DateRepresentationInterface; | |
| /** | |
| * Determines dates offset and applies it to unixTime. | |
| */ | |
| class TimeOffset implements UnixTimeConverterInterface | |
| { | |
| /** | |
| * Day length in seconds. | |
| * | |
| * @var integer | |
| */ | |
| protected $dayLengthInSeconds = 24 * 3600; | |
| /** | |
| * @inheritDoc | |
| */ | |
| public function fromUnixTime(Conversion $conversion) | |
| { | |
| $offset = $conversion->getFrom()->getOffset(); | |
| $conversion->setUnixTime( | |
| $conversion->getUnixTime() + $offset->getValue() | |
| ); | |
| if (null !== $conversion->getTo()) { | |
| $conversion->setTo( | |
| $conversion->getTo()->withOffset($offset) | |
| ); | |
| } | |
| } | |
| /** | |
| * @inheritDoc | |
| */ | |
| public function toUnixTime(Conversion $conversion) | |
| { | |
| $input = $conversion->getTo() ?: $conversion->getFrom(); | |
| $unixTime = $conversion->getUnixTime(); | |
| $input = $this->getOffsetFor($input, $unixTime); | |
| $conversion | |
| ->setUnixTime($unixTime - $input->getOffset()->getValue()) | |
| ->setTo($input) | |
| ; | |
| } | |
| /** | |
| * Search for the offset that have (or might) have been used for the input | |
| * date representation, and updates input date. | |
| * | |
| * @param DateRepresentationInterface $input | |
| * @param integer $timestamp Calculated offsetted timestamp | |
| * | |
| * @return DateRepresentationInterface | |
| */ | |
| protected function getOffsetFor(DateRepresentationInterface $input, $timestamp) | |
| { | |
| $input = $this->extractAbbreviation($input); | |
| $offset = $input->getOffset(); | |
| if (null !== $offset->getValue()) { | |
| return $input; | |
| } | |
| // Looking for timezone offset matching the incomplete timestamp. | |
| // The LMT transition is skipped to mirror the behaviour of | |
| // DateTimeZone->getOffset() | |
| $previous = null; | |
| $offsets = $input->getTimezone()->getTransitions( | |
| $timestamp - $this->dayLengthInSeconds, | |
| // Usually, $timestamp + $this->dayLengthInSeconds should be enougth, | |
| // but for dates before 1900-01-01 timezones fallback to LMT that | |
| // we are trying to skip. | |
| max(0, $timestamp + $this->dayLengthInSeconds) | |
| ); | |
| // DateTimeZone can return a false $offsets value for unsupported ranges. | |
| if (false === $offsets) { | |
| return $input->withOffset( | |
| $offset | |
| ->withValue( | |
| $input->getTimezone()->getOffset( | |
| new DateTimeImmutable() | |
| ) | |
| ) | |
| ) | |
| ; | |
| } | |
| foreach ($offsets as $info) { | |
| if ( | |
| (!$previous || $previous['abbr'] !== 'LMT') | |
| && $timestamp - $info['offset'] < $info['ts'] | |
| ) { | |
| break; | |
| } | |
| $previous = $info; | |
| } | |
| if ($previous === null) { | |
| return $input; | |
| } | |
| return $input->withOffset(new TimeOffsetValue( | |
| $previous['offset'], | |
| $previous['isdst'], | |
| $previous['abbr'] | |
| )); | |
| } | |
| /** | |
| * Extract informations from timezone abbreviation. | |
| * | |
| * @param DateRepresentationInterface $input | |
| * | |
| * @return DateRepresentationInterface | |
| */ | |
| protected function extractAbbreviation(DateRepresentationInterface $input) | |
| { | |
| $offset = $input->getOffset(); | |
| if (null === $abbr = $offset->getAbbreviation()) { | |
| return $input; | |
| } | |
| $abbr = strtolower($abbr); | |
| $list = DateTimeZone::listAbbreviations(); | |
| if (!isset($list[$abbr]) || empty($list[$abbr])) { | |
| return $input; | |
| } | |
| $list = $list[$abbr]; | |
| $criterias = [ | |
| 'offset' => $offset->getValue(), | |
| 'timezone_id' => $input->getTimezone()->getName(), | |
| 'dst' => $offset->isDst(), | |
| ]; | |
| foreach ($criterias as $key => $value) { | |
| if (null === $value) { | |
| continue; | |
| } | |
| $previous = $list; | |
| $list = array_filter($list, function ($infos) use ($key, $value) { | |
| return $value === $infos[$key]; | |
| }); | |
| if (empty($list)) { | |
| $list = $previous; | |
| } | |
| } | |
| $infos = reset($list); | |
| if (null === $offset->getValue()) { | |
| $offset = $offset->withValue($infos['offset']); | |
| } | |
| return $input | |
| ->withOffset($offset->withDst($infos['dst'])) | |
| ->withTimezone(new DateTimeZone($infos['timezone_id'])) | |
| ; | |
| } | |
| } |