/
DBDatetime.php
272 lines (245 loc) · 7.79 KB
/
DBDatetime.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
<?php
namespace SilverStripe\ORM\FieldType;
use Exception;
use IntlDateFormatter;
use InvalidArgumentException;
use SilverStripe\Forms\DatetimeField;
use SilverStripe\ORM\DB;
use SilverStripe\Security\Member;
use SilverStripe\Security\Security;
use SilverStripe\View\TemplateGlobalProvider;
/**
* Represents a date-time field.
* The field currently supports New Zealand date format (DD/MM/YYYY),
* or an ISO 8601 formatted date and time (Y-m-d H:i:s).
* Alternatively you can set a timestamp that is evaluated through
* PHP's built-in date() and strtotime() function according to your system locale.
*
* For all computations involving the current date and time,
* please use {@link DBDatetime::now()} instead of PHP's built-in date() and time()
* methods. This ensures that all time-based computations are testable with mock dates
* through {@link DBDatetime::set_mock_now()}.
*
* Example definition via {@link DataObject::$db}:
* <code>
* static $db = array(
* "Expires" => "DBDatetime",
* );
* </code>
*
* @todo Add localization support, see http://open.silverstripe.com/ticket/2931
* @skipUpgrade
*/
class DBDatetime extends DBDate implements TemplateGlobalProvider
{
/**
* Standard ISO format string for date and time in CLDR standard format,
* with a whitespace separating date and time (common database representation, e.g. in MySQL).
*/
const ISO_DATETIME = 'y-MM-dd HH:mm:ss';
/**
* Standard ISO format string for date and time in CLDR standard format,
* with a "T" separator between date and time (W3C standard, e.g. for HTML5 datetime-local fields).
*/
const ISO_DATETIME_NORMALISED = 'y-MM-dd\'T\'HH:mm:ss';
/**
* Returns the standard localised date
*
* @return string Formatted date.
*/
public function Date()
{
$formatter = $this->getFormatter(IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE);
return $formatter->format($this->getTimestamp());
}
/**
* Returns the standard localised time
*
* @return string Formatted time.
*/
public function Time()
{
$formatter = $this->getFormatter(IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM);
return $formatter->format($this->getTimestamp());
}
/**
* Returns the time in 12-hour format using the format string 'h:mm a' e.g. '1:32 pm'.
*
* @return string Formatted time.
*/
public function Time12()
{
return $this->Format('h:mm a');
}
/**
* Returns the time in 24-hour format using the format string 'H:mm' e.g. '13:32'.
*
* @return string Formatted time.
*/
public function Time24()
{
return $this->Format('H:mm');
}
/**
* Return a date and time formatted as per a CMS user's settings.
*
* @param Member $member
* @return boolean | string A time and date pair formatted as per user-defined settings.
*/
public function FormatFromSettings($member = null)
{
if (!$member) {
$member = Security::getCurrentUser();
}
// Fall back to nice
if (!$member) {
return $this->Nice();
}
$dateFormat = $member->getDateFormat();
$timeFormat = $member->getTimeFormat();
// Get user format
return $this->Format($dateFormat . ' ' . $timeFormat, $member->getLocale());
}
public function requireField()
{
$parts = [
'datatype' => 'datetime',
'arrayValue' => $this->arrayValue
];
$values = [
'type' => 'datetime',
'parts' => $parts
];
DB::require_field($this->tableName, $this->name, $values);
}
/**
* Returns the url encoded date and time in ISO 6801 format using format
* string 'y-MM-dd%20HH:mm:ss' e.g. '2014-02-28%2013:32:22'.
*
* @return string Formatted date and time.
*/
public function URLDatetime()
{
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, $locale);
$field
->setDescription(_t(
'SilverStripe\\Forms\\FormField.EXAMPLE',
'e.g. {format}',
'Example format',
[ 'format' => $date ]
))
->setAttribute('placeholder', $dateTimeFormat);
return $field;
}
/**
*
*/
protected static $mock_now = null;
/**
* Returns either the current system date as determined
* by date(), or a mocked date through {@link set_mock_now()}.
*
* @return static
*/
public static function now()
{
/** @var DBDatetime $now */
$now = null;
if (self::$mock_now) {
$now = self::$mock_now;
} else {
$now = DBField::create_field('Datetime', time());
}
return $now;
}
/**
* Mock the system date temporarily, which is useful for time-based unit testing.
* Use {@link clear_mock_now()} to revert to the current system date.
* Caution: This sets a fixed date that doesn't increment with time.
*
* @param DBDatetime|string $datetime Either in object format, or as a DBDatetime compatible string.
* @throws Exception
*/
public static function set_mock_now($datetime)
{
if (!$datetime instanceof DBDatetime) {
$value = $datetime;
$datetime = DBField::create_field('Datetime', $datetime);
if ($datetime === false) {
throw new InvalidArgumentException('DBDatetime::set_mock_now(): Wrong format: ' . $value);
}
}
self::$mock_now = $datetime;
}
/**
* Clear any mocked date, which causes
* {@link Now()} to return the current system date.
*/
public static function clear_mock_now()
{
self::$mock_now = null;
}
public static function get_template_global_variables()
{
return array(
'Now' => array('method' => 'now', 'casting' => 'Datetime'),
);
}
/**
* Get date / time formatter for the current locale
*
* @param int $dateLength
* @param int $timeLength
* @return IntlDateFormatter
*/
public function getFormatter($dateLength = IntlDateFormatter::MEDIUM, $timeLength = IntlDateFormatter::MEDIUM)
{
return parent::getFormatter($dateLength, $timeLength);
}
/**
* Return formatter in a given locale. Useful if localising in a format other than the current locale.
*
* @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;
}
/**
* Get standard ISO date format string
*
* @return string
*/
public function getISOFormat()
{
return self::ISO_DATETIME;
}
}