Timezone.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Stdlib\DateTime;
  7. use Magento\Framework\App\Config\ScopeConfigInterface;
  8. use Magento\Framework\App\ScopeInterface;
  9. use Magento\Framework\App\ScopeResolverInterface;
  10. use Magento\Framework\Exception\LocalizedException;
  11. use Magento\Framework\Locale\ResolverInterface;
  12. use Magento\Framework\Phrase;
  13. /**
  14. * Timezone library
  15. *
  16. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  17. */
  18. class Timezone implements TimezoneInterface
  19. {
  20. /**
  21. * @var array
  22. */
  23. protected $_allowedFormats = [
  24. \IntlDateFormatter::FULL,
  25. \IntlDateFormatter::LONG,
  26. \IntlDateFormatter::MEDIUM,
  27. \IntlDateFormatter::SHORT,
  28. ];
  29. /**
  30. * @var string
  31. */
  32. protected $_scopeType;
  33. /**
  34. * @var ScopeResolverInterface
  35. */
  36. protected $_scopeResolver;
  37. /**
  38. * @var \Magento\Framework\Stdlib\DateTime
  39. */
  40. protected $_dateTime;
  41. /**
  42. * @var string
  43. */
  44. protected $_defaultTimezonePath;
  45. /**
  46. * @var ScopeConfigInterface
  47. */
  48. protected $_scopeConfig;
  49. /**
  50. * @var ResolverInterface
  51. */
  52. protected $_localeResolver;
  53. /**
  54. * @param ScopeResolverInterface $scopeResolver
  55. * @param ResolverInterface $localeResolver
  56. * @param \Magento\Framework\Stdlib\DateTime $dateTime
  57. * @param ScopeConfigInterface $scopeConfig
  58. * @param string $scopeType
  59. * @param string $defaultTimezonePath
  60. */
  61. public function __construct(
  62. ScopeResolverInterface $scopeResolver,
  63. ResolverInterface $localeResolver,
  64. \Magento\Framework\Stdlib\DateTime $dateTime,
  65. ScopeConfigInterface $scopeConfig,
  66. $scopeType,
  67. $defaultTimezonePath
  68. ) {
  69. $this->_scopeResolver = $scopeResolver;
  70. $this->_localeResolver = $localeResolver;
  71. $this->_dateTime = $dateTime;
  72. $this->_defaultTimezonePath = $defaultTimezonePath;
  73. $this->_scopeConfig = $scopeConfig;
  74. $this->_scopeType = $scopeType;
  75. }
  76. /**
  77. * @inheritdoc
  78. */
  79. public function getDefaultTimezonePath()
  80. {
  81. return $this->_defaultTimezonePath;
  82. }
  83. /**
  84. * @inheritdoc
  85. */
  86. public function getDefaultTimezone()
  87. {
  88. return 'UTC';
  89. }
  90. /**
  91. * @inheritdoc
  92. */
  93. public function getConfigTimezone($scopeType = null, $scopeCode = null)
  94. {
  95. return $this->_scopeConfig->getValue(
  96. $this->getDefaultTimezonePath(),
  97. $scopeType ?: $this->_scopeType,
  98. $scopeCode
  99. );
  100. }
  101. /**
  102. * @inheritdoc
  103. */
  104. public function getDateFormat($type = \IntlDateFormatter::SHORT)
  105. {
  106. return (new \IntlDateFormatter(
  107. $this->_localeResolver->getLocale(),
  108. $type,
  109. \IntlDateFormatter::NONE
  110. ))->getPattern();
  111. }
  112. /**
  113. * @inheritdoc
  114. */
  115. public function getDateFormatWithLongYear()
  116. {
  117. return preg_replace(
  118. '/(?<!y)yy(?!y)/',
  119. 'Y',
  120. $this->getDateFormat()
  121. );
  122. }
  123. /**
  124. * @inheritdoc
  125. */
  126. public function getTimeFormat($type = \IntlDateFormatter::SHORT)
  127. {
  128. return (new \IntlDateFormatter(
  129. $this->_localeResolver->getLocale(),
  130. \IntlDateFormatter::NONE,
  131. $type
  132. ))->getPattern();
  133. }
  134. /**
  135. * @inheritdoc
  136. */
  137. public function getDateTimeFormat($type)
  138. {
  139. return $this->getDateFormat($type) . ' ' . $this->getTimeFormat($type);
  140. }
  141. /**
  142. * @inheritdoc
  143. */
  144. public function date($date = null, $locale = null, $useTimezone = true, $includeTime = true)
  145. {
  146. $locale = $locale ?: $this->_localeResolver->getLocale();
  147. $timezone = $useTimezone
  148. ? $this->getConfigTimezone()
  149. : date_default_timezone_get();
  150. switch (true) {
  151. case (empty($date)):
  152. return new \DateTime('now', new \DateTimeZone($timezone));
  153. case ($date instanceof \DateTime):
  154. return $date->setTimezone(new \DateTimeZone($timezone));
  155. case ($date instanceof \DateTimeImmutable):
  156. return new \DateTime($date->format('Y-m-d H:i:s'), $date->getTimezone());
  157. case (!is_numeric($date)):
  158. $timeType = $includeTime ? \IntlDateFormatter::SHORT : \IntlDateFormatter::NONE;
  159. $formatter = new \IntlDateFormatter(
  160. $locale,
  161. \IntlDateFormatter::SHORT,
  162. $timeType,
  163. new \DateTimeZone($timezone)
  164. );
  165. $date = $this->appendTimeIfNeeded($date, $includeTime);
  166. $date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp();
  167. break;
  168. }
  169. return (new \DateTime(null, new \DateTimeZone($timezone)))->setTimestamp($date);
  170. }
  171. /**
  172. * @inheritdoc
  173. */
  174. public function scopeDate($scope = null, $date = null, $includeTime = false)
  175. {
  176. $timezone = $this->_scopeConfig->getValue($this->getDefaultTimezonePath(), $this->_scopeType, $scope);
  177. $date = new \DateTime(is_numeric($date) ? '@' . $date : $date, new \DateTimeZone($timezone));
  178. if (!$includeTime) {
  179. $date->setTime(0, 0, 0);
  180. }
  181. return $date;
  182. }
  183. /**
  184. * @inheritdoc
  185. */
  186. public function formatDate($date = null, $format = \IntlDateFormatter::SHORT, $showTime = false)
  187. {
  188. $formatTime = $showTime ? $format : \IntlDateFormatter::NONE;
  189. if (!($date instanceof \DateTimeInterface)) {
  190. $date = new \DateTime($date);
  191. }
  192. return $this->formatDateTime($date, $format, $formatTime);
  193. }
  194. /**
  195. * @inheritdoc
  196. */
  197. public function scopeTimeStamp($scope = null)
  198. {
  199. $timezone = $this->_scopeConfig->getValue($this->getDefaultTimezonePath(), $this->_scopeType, $scope);
  200. $currentTimezone = @date_default_timezone_get();
  201. @date_default_timezone_set($timezone);
  202. $date = date('Y-m-d H:i:s');
  203. @date_default_timezone_set($currentTimezone);
  204. return strtotime($date);
  205. }
  206. /**
  207. * @inheritdoc
  208. */
  209. public function isScopeDateInInterval($scope, $dateFrom = null, $dateTo = null)
  210. {
  211. if (!$scope instanceof ScopeInterface) {
  212. $scope = $this->_scopeResolver->getScope($scope);
  213. }
  214. $scopeTimeStamp = $this->scopeTimeStamp($scope);
  215. $fromTimeStamp = strtotime($dateFrom);
  216. $toTimeStamp = strtotime($dateTo);
  217. if ($dateTo) {
  218. // fix date YYYY-MM-DD 00:00:00 to YYYY-MM-DD 23:59:59
  219. $toTimeStamp += 86400;
  220. }
  221. $result = false;
  222. if (!$this->_dateTime->isEmptyDate($dateFrom) && $scopeTimeStamp < $fromTimeStamp) {
  223. } elseif (!$this->_dateTime->isEmptyDate($dateTo) && $scopeTimeStamp > $toTimeStamp) {
  224. } else {
  225. $result = true;
  226. }
  227. return $result;
  228. }
  229. /**
  230. * @inheritdoc
  231. */
  232. public function formatDateTime(
  233. $date,
  234. $dateType = \IntlDateFormatter::SHORT,
  235. $timeType = \IntlDateFormatter::SHORT,
  236. $locale = null,
  237. $timezone = null,
  238. $pattern = null
  239. ) {
  240. if (!($date instanceof \DateTimeInterface)) {
  241. $date = new \DateTime($date);
  242. }
  243. if ($timezone === null) {
  244. if ($date->getTimezone() == null || $date->getTimezone()->getName() == 'UTC'
  245. || $date->getTimezone()->getName() == '+00:00'
  246. ) {
  247. $timezone = $this->getConfigTimezone();
  248. } else {
  249. $timezone = $date->getTimezone();
  250. }
  251. }
  252. $formatter = new \IntlDateFormatter(
  253. $locale ?: $this->_localeResolver->getLocale(),
  254. $dateType,
  255. $timeType,
  256. $timezone,
  257. null,
  258. $pattern
  259. );
  260. return $formatter->format($date);
  261. }
  262. /**
  263. * @inheritdoc
  264. */
  265. public function convertConfigTimeToUtc($date, $format = 'Y-m-d H:i:s')
  266. {
  267. if (!($date instanceof \DateTimeInterface)) {
  268. if ($date instanceof \DateTimeImmutable) {
  269. $date = new \DateTime($date->format('Y-m-d H:i:s'), new \DateTimeZone($this->getConfigTimezone()));
  270. } else {
  271. $date = new \DateTime($date, new \DateTimeZone($this->getConfigTimezone()));
  272. }
  273. } else {
  274. if ($date->getTimezone()->getName() !== $this->getConfigTimezone()) {
  275. throw new LocalizedException(
  276. new Phrase(
  277. 'The DateTime object timezone needs to be the same as the "%1" timezone in config.',
  278. $this->getConfigTimezone()
  279. )
  280. );
  281. }
  282. }
  283. $date->setTimezone(new \DateTimeZone('UTC'));
  284. return $date->format($format);
  285. }
  286. /**
  287. * Retrieve date with time
  288. *
  289. * @param string $date
  290. * @param bool $includeTime
  291. * @return string
  292. */
  293. private function appendTimeIfNeeded($date, $includeTime)
  294. {
  295. if ($includeTime && !preg_match('/\d{1}:\d{2}/', $date)) {
  296. $date .= " 0:00am";
  297. }
  298. return $date;
  299. }
  300. }