Skip to content

Commit f7083b2

Browse files
authored
Merge pull request #3052 from magento-thunder/MAGETWO-94196
Fixed issues: - MAGETWO-94196: [2.1] The fix of incorrect date format was lost since 2.1.13
2 parents ecc1eec + ec99a86 commit f7083b2

File tree

4 files changed

+320
-43
lines changed

4 files changed

+320
-43
lines changed

app/code/Magento/Catalog/Model/Product/Option/Type/Date.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public function prepareForCart()
142142

143143
if ($this->_dateExists()) {
144144
if ($this->useCalendar()) {
145-
$timestamp += $this->_localeDate->date($value['date'], null, true)->getTimestamp();
145+
$timestamp += $this->_localeDate->date($value['date'], null, true, false)->getTimestamp();
146146
} else {
147147
$timestamp += mktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
148148
}

lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
/**
1212
* Timezone library
13+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1314
*/
1415
class Timezone implements TimezoneInterface
1516
{
@@ -110,11 +111,21 @@ public function getConfigTimezone($scopeType = null, $scopeCode = null)
110111
*/
111112
public function getDateFormat($type = \IntlDateFormatter::SHORT)
112113
{
113-
return (new \IntlDateFormatter(
114+
$pattern = (new \IntlDateFormatter(
114115
$this->_localeResolver->getLocale(),
115116
$type,
116117
\IntlDateFormatter::NONE
117118
))->getPattern();
119+
120+
/**
121+
* This replacement is a workaround to prevent bugs in some third party libraries,
122+
* that works incorrectly with 'yyyy' value.
123+
* According to official doc of the ICU library
124+
* internally used in \Intl, 'yyyy' and 'y' formats are the same
125+
* @see http://userguide.icu-project.org/formatparse/datetime
126+
*/
127+
$pattern = str_replace('yyyy', 'y', $pattern);
128+
return $pattern;
118129
}
119130

120131
/**
@@ -151,9 +162,8 @@ public function getDateTimeFormat($type)
151162

152163
/**
153164
* {@inheritdoc}
154-
* @SuppressWarnings(PHPMD.NPathComplexity)
155165
*/
156-
public function date($date = null, $locale = null, $useTimezone = true)
166+
public function date($date = null, $locale = null, $useTimezone = true, $includeTime = true)
157167
{
158168
$locale = $locale ?: $this->_localeResolver->getLocale();
159169
$timezone = $useTimezone
@@ -164,17 +174,52 @@ public function date($date = null, $locale = null, $useTimezone = true)
164174
return new \DateTime('now', new \DateTimeZone($timezone));
165175
} elseif ($date instanceof \DateTime) {
166176
return $date->setTimezone(new \DateTimeZone($timezone));
177+
} elseif ($date instanceof \DateTimeImmutable) {
178+
return new \DateTime($date->format('Y-m-d H:i:s'), $date->getTimezone());
167179
} elseif (!is_numeric($date)) {
168-
$formatter = new \IntlDateFormatter(
169-
$locale,
170-
\IntlDateFormatter::SHORT,
171-
\IntlDateFormatter::NONE
172-
);
173-
$date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp();
180+
$date = $this->prepareDate($date, $locale, $timezone, $includeTime);
174181
}
182+
175183
return (new \DateTime(null, new \DateTimeZone($timezone)))->setTimestamp($date);
176184
}
177185

186+
/**
187+
* Convert string date according to locale format
188+
*
189+
* @param string $date
190+
* @param string $locale
191+
* @param string $timezone
192+
* @param bool $includeTime
193+
* @return string
194+
*/
195+
private function prepareDate($date, $locale, $timezone, $includeTime)
196+
{
197+
$timeType = $includeTime ? \IntlDateFormatter::SHORT : \IntlDateFormatter::NONE;
198+
$formatter = new \IntlDateFormatter(
199+
$locale,
200+
\IntlDateFormatter::SHORT,
201+
$timeType,
202+
new \DateTimeZone($timezone)
203+
);
204+
205+
/**
206+
* IntlDateFormatter does not parse correctly date formats per some locales
207+
* It depends on ICU lib version used by intl extension
208+
* For locales like fr_FR, ar_KW parse date with hyphen as separator
209+
*/
210+
if ($includeTime) {
211+
$date = $this->appendTimeIfNeeded($date);
212+
}
213+
try {
214+
$date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp();
215+
} catch (\Exception $e) {
216+
$date = str_replace('/', '-', $date);
217+
$date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp();
218+
}
219+
220+
return $date;
221+
}
222+
178223
/**
179224
* {@inheritdoc}
180225
*/
@@ -195,7 +240,7 @@ public function formatDate($date = null, $format = \IntlDateFormatter::SHORT, $s
195240
{
196241
$formatTime = $showTime ? $format : \IntlDateFormatter::NONE;
197242

198-
if (!($date instanceof \DateTime)) {
243+
if (!($date instanceof \DateTimeInterface)) {
199244
$date = new \DateTime($date);
200245
}
201246

@@ -232,12 +277,8 @@ public function isScopeDateInInterval($scope, $dateFrom = null, $dateTo = null)
232277
$toTimeStamp += 86400;
233278
}
234279

235-
$result = false;
236-
if (!$this->_dateTime->isEmptyDate($dateFrom) && $scopeTimeStamp < $fromTimeStamp) {
237-
} elseif (!$this->_dateTime->isEmptyDate($dateTo) && $scopeTimeStamp > $toTimeStamp) {
238-
} else {
239-
$result = true;
240-
}
280+
$result = !(!$this->_dateTime->isEmptyDate($dateFrom) && $scopeTimeStamp < $fromTimeStamp)
281+
&& !(!$this->_dateTime->isEmptyDate($dateTo) && $scopeTimeStamp > $toTimeStamp);
241282
return $result;
242283
}
243284

@@ -258,7 +299,7 @@ public function formatDateTime(
258299
$timezone = null,
259300
$pattern = null
260301
) {
261-
if (!($date instanceof \DateTime)) {
302+
if (!($date instanceof \DateTimeInterface)) {
262303
$date = new \DateTime($date);
263304
}
264305

@@ -294,8 +335,12 @@ public function formatDateTime(
294335
*/
295336
public function convertConfigTimeToUtc($date, $format = 'Y-m-d H:i:s')
296337
{
297-
if (!($date instanceof \DateTime)) {
298-
$date = new \DateTime($date, new \DateTimeZone($this->getConfigTimezone()));
338+
if (!($date instanceof \DateTimeInterface)) {
339+
if ($date instanceof \DateTimeImmutable) {
340+
$date = new \DateTime($date->format('Y-m-d H:i:s'), new \DateTimeZone($this->getConfigTimezone()));
341+
} else {
342+
$date = new \DateTime($date, new \DateTimeZone($this->getConfigTimezone()));
343+
}
299344
} else {
300345
if ($date->getTimezone()->getName() !== $this->getConfigTimezone()) {
301346
throw new LocalizedException(
@@ -308,4 +353,18 @@ public function convertConfigTimeToUtc($date, $format = 'Y-m-d H:i:s')
308353

309354
return $date->format($format);
310355
}
356+
357+
/**
358+
* Add time in case if no time provided but required
359+
*
360+
* @param string $date
361+
* @return string
362+
*/
363+
private function appendTimeIfNeeded($date)
364+
{
365+
if (!preg_match('/\d{1,2}:\d{2}/', $date)) {
366+
$date .= " 00:00";
367+
}
368+
return $date;
369+
}
311370
}

lib/internal/Magento/Framework/Stdlib/DateTime/TimezoneInterface.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,10 @@ public function getDateTimeFormat($type);
6565
* @param mixed $date
6666
* @param string $locale
6767
* @param bool $useTimezone
68+
* @param bool $includeTime
6869
* @return \DateTime
6970
*/
70-
public function date($date = null, $locale = null, $useTimezone = true);
71+
public function date($date = null, $locale = null, $useTimezone = true, $includeTime = true);
7172

7273
/**
7374
* Create \DateTime object with date converted to scope timezone and scope Locale
@@ -125,8 +126,8 @@ public function isScopeDateInInterval($scope, $dateFrom = null, $dateTo = null);
125126
* @param string|\DateTimeInterface $date
126127
* @param int $dateType
127128
* @param int $timeType
128-
* @param string|null $locale
129-
* @param string|null $timezone
129+
* @param null $locale
130+
* @param null $timezone
130131
* @param string|null $pattern
131132
* @return string
132133
*/

0 commit comments

Comments
 (0)