Completed
Push — new-committers ( 29cb6f...bcba16 )
by Sam
12:18 queued 33s
created

Date::Full()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
/**
3
 * Represents a date field.
4
 * The field currently supports New Zealand date format (DD/MM/YYYY),
5
 * or an ISO 8601 formatted date (YYYY-MM-DD).
6
 * Alternatively you can set a timestamp that is evaluated through
7
 * PHP's built-in date() function according to your system locale.
8
 *
9
 * Example definition via {@link DataObject::$db}:
10
 * <code>
11
 * static $db = array(
12
 * 	"Expires" => "Date",
13
 * );
14
 * </code>
15
 *
16
 * @todo Add localization support, see http://open.silverstripe.com/ticket/2931
17
 *
18
 * @package framework
19
 * @subpackage model
20
 */
21
class Date extends DBField {
22
23
	public function setValue($value, $record = null) {
24 View Code Duplication
		if($value === false || $value === null || (is_string($value) && !strlen($value))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
25
			// don't try to evaluate empty values with strtotime() below, as it returns "1970-01-01" when it should be
26
			// saved as NULL in database
27
			$this->value = null;
28
			return;
29
		}
30
31
		// @todo This needs tidy up (what if you only specify a month and a year, for example?)
32
		if(is_array($value)) {
33
			if(!empty($value['Day']) && !empty($value['Month']) && !empty($value['Year'])) {
34
				$this->value = $value['Year'] . '-' . $value['Month'] . '-' . $value['Day'];
35
				return;
36
			} else {
37
				// return nothing (so checks below don't fail on an empty array)
38
				return null;
39
			}
40
		}
41
42
		// Default to NZ date format - strtotime expects a US date
43 View Code Duplication
		if(preg_match('#^([0-9]+)/([0-9]+)/([0-9]+)$#', $value, $parts)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
44
			$value = "$parts[2]/$parts[1]/$parts[3]";
45
		}
46
47
		if(is_numeric($value)) {
48
			$this->value = date('Y-m-d', $value);
49 View Code Duplication
		} elseif(is_string($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
			try{
51
				$date = new DateTime($value);
52
				$this->value = $date->Format('Y-m-d');
53
				return;
54
			}catch(Exception $e){
55
				$this->value = null;
56
				return;
57
			}
58
		}
59
	}
60
61
	/**
62
	 * Returns the date in the format dd/mm/yy
63
	 */
64
	public function Nice() {
65
		if($this->value) return $this->Format('d/m/Y');
66
	}
67
68
	/**
69
	 * Returns the date in US format: “01/18/2006”
70
	 */
71
	public function NiceUS() {
72
		if($this->value) return $this->Format('m/d/Y');
73
	}
74
75
	/**
76
	 * Returns the year from the given date
77
	 */
78
	public function Year() {
79
		if($this->value) return $this->Format('Y');
80
	}
81
82
	/**
83
	 * Returns the Full day, of the given date.
84
	 */
85
	public function Day(){
86
		if($this->value) return $this->Format('l');
87
	}
88
89
	/**
90
	 * Returns a full textual representation of a month, such as January.
91
	 */
92
	public function Month() {
93
		if($this->value) return $this->Format('F');
94
	}
95
96
	/**
97
	 * Returns the short version of the month such as Jan
98
	 */
99
	public function ShortMonth() {
100
		if($this->value) return $this->Format('M');
101
	}
102
103
	/**
104
	 * Returns the day of the month.
105
	 * @param boolean $includeOrdinals Include ordinal suffix to day, e.g. "th" or "rd"
0 ignored issues
show
Documentation introduced by
There is no parameter named $includeOrdinals. Did you maybe mean $includeOrdinal?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
106
	 * @return string
107
	 */
108
	public function DayOfMonth($includeOrdinal = false) {
109
		if($this->value) {
110
			$format = 'j';
111
			if ($includeOrdinal) $format .= 'S';
112
			return $this->Format($format);
113
		}
114
	}
115
116
	/**
117
	 * Returns the date in the format 24 December 2006
118
	 */
119
	public function Long() {
120
		if($this->value) return $this->Format('j F Y');
121
	}
122
123
	/**
124
	 * Returns the date in the format 24 Dec 2006
125
	 */
126
	public function Full() {
127
		if($this->value) return $this->Format('j M Y');
128
	}
129
130
	/**
131
	 * Return the date using a particular formatting string.
132
	 *
133
	 * @param string $format Format code string. e.g. "d M Y" (see http://php.net/date)
134
	 * @return string The date in the requested format
135
	 */
136
	public function Format($format) {
137
		if($this->value){
138
			$date = new DateTime($this->value);
139
			return $date->Format($format);
140
		}
141
	}
142
143
	/**
144
	 * Return the date formatted using the given strftime formatting string.
145
	 *
146
	 * strftime obeys the current LC_TIME/LC_ALL when printing lexical values
147
	 * like day- and month-names
148
	 */
149
	public function FormatI18N($formattingString) {
150
		if($this->value) {
151
			return strftime($formattingString, strtotime($this->value));
152
		}
153
	}
154
155
	/**
156
	 * Return a date formatted as per a CMS user's settings.
157
	 *
158
	 * @param Member $member
159
	 * @return boolean | string A date formatted as per user-defined settings.
160
	 */
161
	public function FormatFromSettings($member = null) {
162
		require_once 'Zend/Date.php';
163
164
		if(!$member) {
165
			if(!Member::currentUserID()) {
166
				return false;
167
			}
168
			$member = Member::currentUser();
169
		}
170
171
		$formatD = $member->getDateFormat();
172
		$zendDate = new Zend_Date($this->getValue(), 'y-MM-dd');
173
174
		return $zendDate->toString($formatD);
175
	}
176
177
	/*
178
	 * Return a string in the form "12 - 16 Sept" or "12 Aug - 16 Sept"
179
	 * @param Date $otherDateObj Another date object specifying the end of the range
180
	 * @param boolean $includeOrdinals Include ordinal suffix to day, e.g. "th" or "rd"
181
	 * @return string
182
	 */
183
	public function RangeString($otherDateObj, $includeOrdinals = false) {
184
		$d1 = $this->DayOfMonth($includeOrdinals);
185
		$d2 = $otherDateObj->DayOfMonth($includeOrdinals);
186
		$m1 = $this->ShortMonth();
187
		$m2 = $otherDateObj->ShortMonth();
188
		$y1 = $this->Year();
189
		$y2 = $otherDateObj->Year();
190
191
		if($y1 != $y2) return "$d1 $m1 $y1 - $d2 $m2 $y2";
192
		else if($m1 != $m2) return "$d1 $m1 - $d2 $m2 $y1";
193
		else return "$d1 - $d2 $m1 $y1";
194
	}
195
196
	public function Rfc822() {
197
		if($this->value) return date('r', strtotime($this->value));
198
	}
199
200
	public function Rfc2822() {
201
		if($this->value) return date('Y-m-d H:i:s', strtotime($this->value));
202
	}
203
204
	public function Rfc3339() {
205
		$timestamp = ($this->value) ? strtotime($this->value) : false;
206
		if(!$timestamp) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $timestamp of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
207
208
		$date = date('Y-m-d\TH:i:s', $timestamp);
209
210
		$matches = array();
211
		if(preg_match('/^([\-+])(\d{2})(\d{2})$/', date('O', $timestamp), $matches)) {
212
			$date .= $matches[1].$matches[2].':'.$matches[3];
213
		} else {
214
			$date .= 'Z';
215
		}
216
217
		return $date;
218
	}
219
220
	/**
221
	 * Returns the number of seconds/minutes/hours/days or months since the timestamp.
222
	 *
223
	 * @param boolean $includeSeconds Show seconds, or just round to "less than a minute".
224
	 * @param int $significance Minimum significant value of X for "X units ago" to display
225
	 * @return  String
226
	 */
227
	public function Ago($includeSeconds = true, $significance = 2) {
228
		if($this->value) {
229
			$time = SS_Datetime::now()->Format('U');
230
			if(strtotime($this->value) == $time || $time > strtotime($this->value)) {
231
				return _t(
232
					'Date.TIMEDIFFAGO',
233
					"{difference} ago",
234
					'Natural language time difference, e.g. 2 hours ago',
235
					array('difference' => $this->TimeDiff($includeSeconds, $significance))
0 ignored issues
show
Documentation introduced by
array('difference' => $t...econds, $significance)) is of type array<string,false|strin...":"false|string|null"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
236
				);
237
			} else {
238
				return _t(
239
					'Date.TIMEDIFFIN',
240
					"in {difference}",
241
					'Natural language time difference, e.g. in 2 hours',
242
					array('difference' => $this->TimeDiff($includeSeconds, $significance))
0 ignored issues
show
Documentation introduced by
array('difference' => $t...econds, $significance)) is of type array<string,false|strin...":"false|string|null"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
243
				);
244
			}
245
		}
246
	}
247
248
	/**
249
	 * @param boolean $includeSeconds Show seconds, or just round to "less than a minute".
250
	 * @param int $significance Minimum significant value of X for "X units ago" to display
251
	 * @return string
252
	 */
253
	public function TimeDiff($includeSeconds = true, $significance = 2) {
254
		if(!$this->value) return false;
255
256
		$time = SS_Datetime::now()->Format('U');
257
		$ago = abs($time - strtotime($this->value));
258
		if($ago < 60 && !$includeSeconds) {
259
			return _t('Date.LessThanMinuteAgo', 'less than a minute');
260
		} elseif($ago < $significance * 60 && $includeSeconds) {
261
			return $this->TimeDiffIn('seconds');
262
		} elseif($ago < $significance * 3600) {
263
			return $this->TimeDiffIn('minutes');
264
		} elseif($ago < $significance * 86400) {
265
			return $this->TimeDiffIn('hours');
266
		} elseif($ago < $significance * 86400 * 30) {
267
			return $this->TimeDiffIn('days');
268
		} elseif($ago < $significance * 86400 * 365) {
269
			return $this->TimeDiffIn('months');
270
		} else {
271
			return $this->TimeDiffIn('years');
272
		}
273
	}
274
275
	/**
276
	 * Gets the time difference, but always returns it in a certain format
277
	 *
278
	 * @param string $format The format, could be one of these:
279
	 * 'seconds', 'minutes', 'hours', 'days', 'months', 'years'.
280
	 * @return string The resulting formatted period
281
	 */
282
	public function TimeDiffIn($format) {
283
		if(!$this->value) return false;
284
285
		$time = SS_Datetime::now()->Format('U');
286
		$ago = abs($time - strtotime($this->value));
287
288
		switch($format) {
289
			case "seconds":
290
				$span = $ago;
291
				return ($span != 1) ? "{$span} "._t("Date.SECS", "secs") : "{$span} "._t("Date.SEC", "sec");
292
293
			case "minutes":
294
				$span = round($ago/60);
295
				return ($span != 1) ? "{$span} "._t("Date.MINS", "mins") : "{$span} "._t("Date.MIN", "min");
296
297
			case "hours":
298
				$span = round($ago/3600);
299
				return ($span != 1) ? "{$span} "._t("Date.HOURS", "hours") : "{$span} "._t("Date.HOUR", "hour");
300
301
			case "days":
302
				$span = round($ago/86400);
303
				return ($span != 1) ? "{$span} "._t("Date.DAYS", "days") : "{$span} "._t("Date.DAY", "day");
304
305
			case "months":
306
				$span = round($ago/86400/30);
307
				return ($span != 1) ? "{$span} "._t("Date.MONTHS", "months") : "{$span} "._t("Date.MONTH", "month");
308
309
			case "years":
310
				$span = round($ago/86400/365);
311
				return ($span != 1) ? "{$span} "._t("Date.YEARS", "years") : "{$span} "._t("Date.YEAR", "year");
312
		}
313
	}
314
315
	public function requireField() {
316
		$parts=Array('datatype'=>'date', 'arrayValue'=>$this->arrayValue);
317
		$values=Array('type'=>'date', 'parts'=>$parts);
318
		DB::require_field($this->tableName, $this->name, $values);
0 ignored issues
show
Documentation introduced by
$values is of type array<string,string|arra...arrayValue\":\"?\"}>"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
319
	}
320
321
	/**
322
	 * Returns true if date is in the past.
323
	 * @return boolean
324
	 */
325
	public function InPast() {
326
		return strtotime($this->value) < SS_Datetime::now()->Format('U');
327
	}
328
329
	/**
330
	 * Returns true if date is in the future.
331
	 * @return boolean
332
	 */
333
	public function InFuture() {
334
		return strtotime($this->value) > SS_Datetime::now()->Format('U');
335
	}
336
337
	/**
338
	 * Returns true if date is today.
339
	 * @return boolean
340
	 */
341
	public function IsToday() {
342
		return (date('Y-m-d', strtotime($this->value)) == SS_Datetime::now()->Format('Y-m-d'));
343
	}
344
345
	/**
346
	 * Returns a date suitable for insertion into a URL and use by the system.
347
	 */
348
	public function URLDate() {
349
		return date('Y-m-d', strtotime($this->value));
350
	}
351
352
353
	public function days_between($fyear, $fmonth, $fday, $tyear, $tmonth, $tday){
354
		return abs((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, $tmonth, $tday, $tyear))/(60*60*24));
355
	}
356
357
	public function day_before($fyear, $fmonth, $fday){
358
		return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-1,$fyear));
359
	}
360
361
	public function next_day($fyear, $fmonth, $fday){
362
		return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday+1,$fyear));
363
	}
364
365
	public function weekday($fyear, $fmonth, $fday){ // 0 is a Monday
366
		return (((mktime ( 0, 0, 0, $fmonth, $fday, $fyear) - mktime ( 0, 0, 0, 7, 17, 2006))/(60*60*24))+700000) % 7;
367
	}
368
369
	public function prior_monday($fyear, $fmonth, $fday){
370
		return date ("Y-m-d", mktime (0,0,0,$fmonth,$fday-$this->weekday($fyear, $fmonth, $fday),$fyear));
371
	}
372
373
	/**
374
	 * Return the nearest date in the past, based on day and month.
375
	 * Automatically attaches the correct year.
376
	 *
377
	 * This is useful for determining a financial year start or end date.
378
	 *
379
	 * @param $fmonth int The number of the month (e.g. 3 is March, 4 is April)
380
	 * @param $fday int The day of the month
381
	 * @param $fyear int Determine historical value
382
	 * @return string Date in YYYY-MM-DD format
383
	 */
384
	public static function past_date($fmonth, $fday = 1, $fyear = null) {
385
		if(!$fyear) $fyear = date('Y');
386
		$fday = (int) $fday;
387
		$fmonth = (int) $fmonth;
388
		$fyear = (int) $fyear;
389
390
		$pastDate = mktime(0, 0, 0, $fmonth, $fday, $fyear);
391
		$curDate = mktime(0, 0, 0, date('m'), date('d'), $fyear);
392
393
		if($pastDate < $curDate) {
394
			return date('Y-m-d', mktime(0, 0, 0, $fmonth, $fday, $fyear));
395
		} else {
396
			return date('Y-m-d', mktime(0, 0, 0, $fmonth, $fday, $fyear - 1));
397
		}
398
	}
399
400 View Code Duplication
	public function scaffoldFormField($title = null, $params = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
401
		$field = DateField::create($this->name, $title);
402
403
		// Show formatting hints for better usability
404
		$field->setDescription(sprintf(
405
			_t('FormField.Example', 'e.g. %s', 'Example format'),
406
			Convert::raw2xml(Zend_Date::now()->toString($field->getConfig('dateformat')))
407
		));
408
		$field->setAttribute('placeholder', $field->getConfig('dateformat'));
409
410
		return $field;
411
	}
412
}
413