mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '4.1' into 4
# Conflicts: # src/Forms/DateField.php
This commit is contained in:
commit
5fa5abf295
@ -173,9 +173,9 @@ class DateField extends TextField
|
||||
*/
|
||||
public function getDateFormat()
|
||||
{
|
||||
// Browsers expect ISO 8601 dates, localisation is handled on the client
|
||||
if ($this->getHTML5()) {
|
||||
// Browsers expect ISO 8601 dates, localisation is handled on the client
|
||||
$this->setDateFormat(DBDate::ISO_DATE);
|
||||
return DBDate::ISO_DATE;
|
||||
}
|
||||
|
||||
if ($this->dateFormat) {
|
||||
@ -220,7 +220,7 @@ class DateField extends TextField
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->getHTML5() && $this->locale) {
|
||||
if ($this->getHTML5() && $this->locale && $this->locale !== DBDate::ISO_LOCALE) {
|
||||
throw new \LogicException(
|
||||
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setLocale()'
|
||||
);
|
||||
@ -252,9 +252,8 @@ class DateField extends TextField
|
||||
*/
|
||||
protected function getInternalFormatter()
|
||||
{
|
||||
$locale = i18n::config()->uninherited('default_locale');
|
||||
$formatter = IntlDateFormatter::create(
|
||||
i18n::config()->uninherited('default_locale'),
|
||||
DBDate::ISO_LOCALE,
|
||||
IntlDateFormatter::MEDIUM,
|
||||
IntlDateFormatter::NONE
|
||||
);
|
||||
@ -446,6 +445,10 @@ class DateField extends TextField
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
// Use iso locale for html5
|
||||
if ($this->getHTML5()) {
|
||||
return DBDate::ISO_LOCALE;
|
||||
}
|
||||
return $this->locale ?: i18n::get_locale();
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Forms;
|
||||
use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\FieldType\DBDate;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\ValidationResult;
|
||||
|
||||
@ -297,7 +298,7 @@ class DatetimeField extends TextField
|
||||
}
|
||||
|
||||
$formatter = IntlDateFormatter::create(
|
||||
i18n::config()->uninherited('default_locale'),
|
||||
DBDate::ISO_LOCALE,
|
||||
IntlDateFormatter::MEDIUM,
|
||||
IntlDateFormatter::MEDIUM,
|
||||
$timezone
|
||||
@ -337,10 +338,10 @@ class DatetimeField extends TextField
|
||||
$internalFormatter = $this->getInternalFormatter();
|
||||
$timestamp = $internalFormatter->parse($value);
|
||||
|
||||
// Retry without "T" separator
|
||||
// Retry with "T" separator
|
||||
if (!$timestamp) {
|
||||
$fallbackFormatter = $this->getInternalFormatter();
|
||||
$fallbackFormatter->setPattern(DBDatetime::ISO_DATETIME);
|
||||
$fallbackFormatter->setPattern(DBDatetime::ISO_DATETIME_NORMALISED);
|
||||
$timestamp = $fallbackFormatter->parse($value);
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,14 @@ class DBDate extends DBField
|
||||
*/
|
||||
const ISO_DATE = 'y-MM-dd';
|
||||
|
||||
/**
|
||||
* Fixed locale to use for ISO date formatting. This is necessary to prevent
|
||||
* locale-specific numeric localisation breaking internal date strings.
|
||||
*
|
||||
* @internal (remove internal in 4.2)
|
||||
*/
|
||||
const ISO_LOCALE = 'en_US';
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
{
|
||||
$value = $this->parseDate($value);
|
||||
@ -77,8 +85,7 @@ class DBDate extends DBField
|
||||
}
|
||||
|
||||
// Format as iso8601
|
||||
$formatter = $this->getFormatter();
|
||||
$formatter->setPattern($this->getISOFormat());
|
||||
$formatter = $this->getInternalFormatter();
|
||||
return $formatter->format($source);
|
||||
}
|
||||
|
||||
@ -203,7 +210,45 @@ class DBDate extends DBField
|
||||
*/
|
||||
public function getFormatter($dateLength = IntlDateFormatter::MEDIUM, $timeLength = IntlDateFormatter::NONE)
|
||||
{
|
||||
return new IntlDateFormatter(i18n::get_locale(), $dateLength, $timeLength);
|
||||
return $this->getCustomFormatter(null, null, $dateLength, $timeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return formatter in a given locale. Useful if localising in a format other than the current locale.
|
||||
*
|
||||
* @internal (Remove internal in 4.2)
|
||||
*
|
||||
* @param string|null $locale The current locale, or null to use default
|
||||
* @param string|null $pattern Custom pattern to use for this, if required
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getCustomFormatter(
|
||||
$locale = null,
|
||||
$pattern = null,
|
||||
$dateLength = IntlDateFormatter::MEDIUM,
|
||||
$timeLength = IntlDateFormatter::NONE
|
||||
) {
|
||||
$locale = $locale ?: i18n::get_locale();
|
||||
$formatter = IntlDateFormatter::create($locale, $dateLength, $timeLength);
|
||||
if ($pattern) {
|
||||
$formatter->setPattern($pattern);
|
||||
}
|
||||
return $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatter used internally
|
||||
*
|
||||
* @internal
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
protected function getInternalFormatter()
|
||||
{
|
||||
$formatter = $this->getCustomFormatter(DBDate::ISO_LOCALE, DBDate::ISO_DATE);
|
||||
$formatter->setLenient(false);
|
||||
return $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,10 +266,14 @@ class DBDate extends DBField
|
||||
* for the day of the month ("1st", "2nd", "3rd" etc)
|
||||
*
|
||||
* @param string $format Format code string. See http://userguide.icu-project.org/formatparse/datetime
|
||||
* @param string $locale Custom locale to use (add to signature in 5.0)
|
||||
* @return string The date in the requested format
|
||||
*/
|
||||
public function Format($format)
|
||||
{
|
||||
// Note: soft-arg uses func_get_args() to respect semver. Add to signature in 5.0
|
||||
$locale = func_num_args() > 1 ? func_get_arg(1) : null;
|
||||
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
}
|
||||
@ -234,9 +283,8 @@ class DBDate extends DBField
|
||||
$format = str_replace('{o}', "'{$this->DayOfMonth(true)}'", $format);
|
||||
}
|
||||
|
||||
$formatter = $this->getFormatter();
|
||||
$formatter->setPattern($format);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
$formatter = $this->getCustomFormatter($locale, $format);
|
||||
return $formatter->Format($this->getTimestamp());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,8 +318,7 @@ class DBDate extends DBField
|
||||
}
|
||||
|
||||
// Get user format
|
||||
$format = $member->getDateFormat();
|
||||
return $this->Format($format);
|
||||
return $this->Format($member->getDateFormat(), $member->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,7 +366,9 @@ class DBDate extends DBField
|
||||
*/
|
||||
public function Rfc2822()
|
||||
{
|
||||
return $this->Format('y-MM-dd HH:mm:ss');
|
||||
$formatter = $this->getInternalFormatter();
|
||||
$formatter->setPattern('y-MM-dd HH:mm:ss');
|
||||
return $formatter->format($this->getTimestamp());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +469,7 @@ class DBDate extends DBField
|
||||
);
|
||||
|
||||
case "minutes":
|
||||
$span = round($ago/60);
|
||||
$span = round($ago / 60);
|
||||
return _t(
|
||||
__CLASS__ . '.MINUTES_SHORT_PLURALS',
|
||||
'{count} min|{count} mins',
|
||||
@ -428,7 +477,7 @@ class DBDate extends DBField
|
||||
);
|
||||
|
||||
case "hours":
|
||||
$span = round($ago/3600);
|
||||
$span = round($ago / 3600);
|
||||
return _t(
|
||||
__CLASS__ . '.HOURS_SHORT_PLURALS',
|
||||
'{count} hour|{count} hours',
|
||||
@ -436,7 +485,7 @@ class DBDate extends DBField
|
||||
);
|
||||
|
||||
case "days":
|
||||
$span = round($ago/86400);
|
||||
$span = round($ago / 86400);
|
||||
return _t(
|
||||
__CLASS__ . '.DAYS_SHORT_PLURALS',
|
||||
'{count} day|{count} days',
|
||||
@ -444,7 +493,7 @@ class DBDate extends DBField
|
||||
);
|
||||
|
||||
case "months":
|
||||
$span = round($ago/86400/30);
|
||||
$span = round($ago / 86400 / 30);
|
||||
return _t(
|
||||
__CLASS__ . '.MONTHS_SHORT_PLURALS',
|
||||
'{count} month|{count} months',
|
||||
@ -452,7 +501,7 @@ class DBDate extends DBField
|
||||
);
|
||||
|
||||
case "years":
|
||||
$span = round($ago/86400/365);
|
||||
$span = round($ago / 86400 / 365);
|
||||
return _t(
|
||||
__CLASS__ . '.YEARS_SHORT_PLURALS',
|
||||
'{count} year|{count} years',
|
||||
@ -466,8 +515,8 @@ class DBDate extends DBField
|
||||
|
||||
public function requireField()
|
||||
{
|
||||
$parts=array('datatype'=>'date', 'arrayValue'=>$this->arrayValue);
|
||||
$values=array('type'=>'date', 'parts'=>$parts);
|
||||
$parts = array('datatype' => 'date', 'arrayValue' => $this->arrayValue);
|
||||
$values = array('type' => 'date', 'parts' => $parts);
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
@ -505,7 +554,7 @@ class DBDate extends DBField
|
||||
*/
|
||||
public function URLDate()
|
||||
{
|
||||
return rawurlencode($this->Format(self::ISO_DATE));
|
||||
return rawurlencode($this->Format(self::ISO_DATE, self::ISO_LOCALE));
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
|
@ -2,15 +2,14 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use Exception;
|
||||
use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Forms\DatetimeField;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\TemplateGlobalProvider;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Represents a date-time field.
|
||||
@ -111,7 +110,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
$timeFormat = $member->getTimeFormat();
|
||||
|
||||
// Get user format
|
||||
return $this->Format($dateFormat . ' ' . $timeFormat);
|
||||
return $this->Format($dateFormat . ' ' . $timeFormat, $member->getLocale());
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
@ -135,16 +134,17 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
*/
|
||||
public function URLDatetime()
|
||||
{
|
||||
return rawurlencode($this->Format(self::ISO_DATETIME));
|
||||
return rawurlencode($this->Format(self::ISO_DATETIME, self::ISO_LOCALE));
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
{
|
||||
$field = DatetimeField::create($this->name, $title);
|
||||
$dateTimeFormat = $field->getDatetimeFormat();
|
||||
$locale = $field->getLocale();
|
||||
|
||||
// Set date formatting hints and example
|
||||
$date = static::now()->Format($dateTimeFormat);
|
||||
$date = static::now()->Format($dateTimeFormat, $locale);
|
||||
$field
|
||||
->setDescription(_t(
|
||||
'SilverStripe\\Forms\\FormField.EXAMPLE',
|
||||
@ -225,7 +225,41 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
*/
|
||||
public function getFormatter($dateLength = IntlDateFormatter::MEDIUM, $timeLength = IntlDateFormatter::MEDIUM)
|
||||
{
|
||||
return new IntlDateFormatter(i18n::get_locale(), $dateLength, $timeLength);
|
||||
return parent::getFormatter($dateLength, $timeLength);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return formatter in a given locale. Useful if localising in a format other than the current locale.
|
||||
*
|
||||
* @internal (Remove internal in 4.2)
|
||||
*
|
||||
* @param string|null $locale The current locale, or null to use default
|
||||
* @param string|null $pattern Custom pattern to use for this, if required
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getCustomFormatter(
|
||||
$locale = null,
|
||||
$pattern = null,
|
||||
$dateLength = IntlDateFormatter::MEDIUM,
|
||||
$timeLength = IntlDateFormatter::MEDIUM
|
||||
) {
|
||||
return parent::getCustomFormatter($locale, $pattern, $dateLength, $timeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatter used internally
|
||||
*
|
||||
* @internal
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
protected function getInternalFormatter()
|
||||
{
|
||||
$formatter = $this->getCustomFormatter(DBDate::ISO_LOCALE, DBDatetime::ISO_DATETIME);
|
||||
$formatter->setLenient(false);
|
||||
return $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,11 +109,11 @@ class DatetimeFieldTest extends SapphireTest
|
||||
{
|
||||
$f = new DatetimeField('Datetime', 'Datetime');
|
||||
$f->setValue('2003-03-29 23:59:38');
|
||||
$this->assertEquals($f->dataValue(), '2003-03-29 23:59:38', 'Accepts ISO');
|
||||
$this->assertEquals('2003-03-29 23:59:38', $f->dataValue(), 'Accepts ISO');
|
||||
|
||||
$f = new DatetimeField('Datetime', 'Datetime');
|
||||
$f->setValue('2003-03-29T23:59:38');
|
||||
$this->assertNull($f->dataValue(), 'Rejects normalised ISO');
|
||||
$this->assertEquals('2003-03-29 23:59:38', $f->dataValue(), 'Accepts normalised ISO');
|
||||
}
|
||||
|
||||
public function testSubmittedValue()
|
||||
@ -152,7 +152,7 @@ class DatetimeFieldTest extends SapphireTest
|
||||
$this->assertTrue($f->validate(new RequiredFields()));
|
||||
|
||||
$f = new DatetimeField('Datetime', 'Datetime', '2003-03-29T23:59:38');
|
||||
$this->assertFalse($f->validate(new RequiredFields()), 'Normalised ISO');
|
||||
$this->assertTrue($f->validate(new RequiredFields()), 'Normalised ISO');
|
||||
|
||||
$f = new DatetimeField('Datetime', 'Datetime', '2003-03-29');
|
||||
$this->assertFalse($f->validate(new RequiredFields()), 'Leaving out time');
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
namespace SilverStripe\ORM\Tests;
|
||||
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Security\Member;
|
||||
|
||||
/**
|
||||
* Tests for {@link Datetime} class.
|
||||
@ -70,6 +69,23 @@ class DBDatetimeTest extends SapphireTest
|
||||
$this->assertEquals('10 Oct 3000 15 32 24', $date->Format('d MMM y H m s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Coverage for dates using hindi-numerals
|
||||
*/
|
||||
public function testHindiNumerals()
|
||||
{
|
||||
// Parent locale is english; Can be localised to arabic
|
||||
$date = DBDatetime::create_field('Datetime', '1600-10-10 15:32:24');
|
||||
$this->assertEquals('10 Oct 1600 15 32 24', $date->Format('d MMM y H m s'));
|
||||
$this->assertEquals('١٠ أكتوبر ١٦٠٠ ١٥ ٣٢ ٢٤', $date->Format('d MMM y H m s', 'ar'));
|
||||
|
||||
// Parent locale is arabic; Datavalue uses ISO date
|
||||
i18n::set_locale('ar');
|
||||
$date = DBDatetime::create_field('Datetime', '1600-10-10 15:32:24');
|
||||
$this->assertEquals('١٠ أكتوبر ١٦٠٠ ١٥ ٣٢ ٢٤', $date->Format('d MMM y H m s'));
|
||||
$this->assertEquals('1600-10-10 15:32:24', $date->getValue());
|
||||
}
|
||||
|
||||
public function testNice()
|
||||
{
|
||||
$date = DBDatetime::create_field('Datetime', '2001-12-31 22:10:59');
|
||||
|
Loading…
Reference in New Issue
Block a user