Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TSimpleDateFormatter class file
4
 *
5
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TSimpleDateFormatter.php 2488 2008-08-06 01:34:06Z knut $
10
 * @package System.Util
11
 */
12
 
13
/**
14
 * TSimpleDateFormatter class.
15
 *
16
 * Formats and parses dates using the SimpleDateFormat pattern.
17
 * This pattern is compatible with the I18N and java's SimpleDateFormatter.
18
 * <code>
19
 * Pattern |      Description
20
 * ----------------------------------------------------
21
 * d       | Day of month 1 to 31, no padding
22
 * dd      | Day of monath 01 to 31, zero leading
23
 * M       | Month digit 1 to 12, no padding
24
 * MM      | Month digit 01 to 12, zero leading
25
 * yy      | 2 year digit, e.g., 96, 05
26
 * yyyy    | 4 year digit, e.g., 2005
27
 * ----------------------------------------------------
28
 * </code>
29
 *
30
 * Usage example, to format a date
31
 * <code>
32
 * $formatter = new TSimpleDateFormatter("dd/MM/yyy");
33
 * echo $formatter->format(time());
34
 * </code>
35
 *
36
 * To parse the date string into a date timestamp.
37
 * <code>
38
 * $formatter = new TSimpleDateFormatter("d-M-yyy");
39
 * echo $formatter->parse("24-6-2005");
40
 * </code>
41
 *
42
 * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
43
 * @version $Id: TSimpleDateFormatter.php 2488 2008-08-06 01:34:06Z knut $
44
 * @package System.Util
45
 * @since 3.0
46
 */
47
class TSimpleDateFormatter
48
{
49
	/**
50
	 * Formatting pattern.
51
	 * @var string
52
	 */
53
	private $pattern;
54
 
55
	/**
56
	 * Charset, default is 'UTF-8'
57
	 * @var string
58
	 */
59
	private $charset = 'UTF-8';
60
 
61
	/**
62
	 * Constructor, create a new date time formatter.
63
	 * @param string formatting pattern.
64
	 * @param string pattern and value charset
65
	 */
66
	public function __construct($pattern, $charset='UTF-8')
67
	{
68
		$this->setPattern($pattern);
69
		$this->setCharset($charset);
70
	}
71
 
72
	/**
73
	 * @return string formatting pattern.
74
	 */
75
	public function getPattern()
76
	{
77
		return $this->pattern;
78
	}
79
 
80
	/**
81
	 * @param string formatting pattern.
82
	 */
83
	public function setPattern($pattern)
84
	{
85
		$this->pattern = $pattern;
86
	}
87
 
88
	/**
89
	 * @return string formatting charset.
90
	 */
91
	public function getCharset()
92
	{
93
		return $this->charset;
94
	}
95
 
96
	/**
97
	 * @param string formatting charset.
98
	 */
99
	public function setCharset($charset)
100
	{
101
		$this->charset = $charset;
102
	}
103
 
104
	/**
105
	 * Format the date according to the pattern.
106
	 * @param string|int the date to format, either integer or a string readable by strtotime.
107
	 * @return string formatted date.
108
	 */
109
	public function format($value)
110
	{
111
		$date = $this->getDate($value);
112
		$bits['yyyy'] = $date['year'];
113
		$bits['yy'] = substr("{$date['year']}", -2);
114
 
115
		$bits['MM'] = str_pad("{$date['mon']}", 2, '0', STR_PAD_LEFT);
116
		$bits['M'] = $date['mon'];
117
 
118
		$bits['dd'] = str_pad("{$date['mday']}", 2, '0', STR_PAD_LEFT);
119
		$bits['d'] = $date['mday'];
120
 
121
		$pattern = preg_replace('/M{3,4}/', 'MM', $this->pattern);
122
		return str_replace(array_keys($bits), $bits, $pattern);
123
	}
124
 
125
	public function getMonthPattern()
126
	{
127
		if(is_int(strpos($this->pattern, 'MMMM')))
128
			return 'MMMM';
129
		if(is_int(strpos($this->pattern, 'MMM')))
130
			return 'MMM';
131
		if(is_int(strpos($this->pattern, 'MM')))
132
			return 'MM';
133
		if(is_int(strpos($this->pattern, 'M')))
134
			return 'M';
135
		return false;
136
	}
137
 
138
	public function getDayPattern()
139
	{
140
		if(is_int(strpos($this->pattern, 'dd')))
141
			return 'dd';
142
		if(is_int(strpos($this->pattern, 'd')))
143
			return 'd';
144
		return false;
145
	}
146
 
147
	public function getYearPattern()
148
	{
149
		if(is_int(strpos($this->pattern, 'yyyy')))
150
			return 'yyyy';
151
		if(is_int(strpos($this->pattern, 'yy')))
152
			return 'yy';
153
		return false;
154
	}
155
 
156
	public function getDayMonthYearOrdering()
157
	{
158
		$ordering = array();
159
		if(is_int($day= strpos($this->pattern, 'd')))
160
			$ordering['day'] = $day;
161
		if(is_int($month= strpos($this->pattern, 'M')))
162
			$ordering['month'] = $month;
163
		if(is_int($year= strpos($this->pattern, 'yy')))
164
			$ordering['year'] = $year;
165
		asort($ordering);
166
		return array_keys($ordering);
167
	}
168
 
169
	/**
170
	 * Gets the time stamp from string or integer.
171
	 * @param string|int date to parse
172
	 * @return array date info array
173
	 */
174
	private function getDate($value)
175
	{
176
		if(!is_string($value))
177
		{
178
			$s = Prado::createComponent('System.Util.TDateTimeStamp');
179
			return $s->getDate($value);
180
		}
181
		$date = @strtotime($value);
182
		if($date < 0)
183
			throw new TInvalidDataValueException('invalid_date', $value);
184
		return @getdate($date);
185
	}
186
 
187
	/**
188
	 * @return boolean true if the given value matches with the date pattern.
189
	 */
190
	public function isValidDate($value)
191
	{
192
		if($value === null) {
193
			return false;
194
		} else {
195
			return $this->parse($value, false) !== null;
196
		}
197
	}
198
 
199
	/**
200
	 * Parse the string according to the pattern.
201
	 * @param string|int date string or integer to parse
202
	 * @return int date time stamp
203
	 * @throws TInvalidDataValueException if date string is malformed.
204
	 */
205
	public function parse($value,$defaultToCurrentTime=true)
206
	{
207
		if(is_int($value) || is_float($value))
208
			return $value;
209
		else if(!is_string($value))
210
			throw new TInvalidDataValueException('date_to_parse_must_be_string', $value);
211
 
212
		if(empty($this->pattern)) return time();
213
 
214
		$date = time();
215
 
216
		if($this->length(trim($value)) < 1)
217
			return $defaultToCurrentTime ? $date : null;
218
 
219
		$pattern = $this->pattern;
220
 
221
		$i_val = 0;
222
		$i_format = 0;
223
		$pattern_length = $this->length($pattern);
224
		$c = '';
225
		$token='';
226
		$x=null; $y=null;
227
 
228
 
229
		if($defaultToCurrentTime)
230
		{
231
			$year = "{$date['year']}";
232
			$month = $date['mon'];
233
			$day = $date['mday'];
234
		}
235
		else
236
		{
237
			$year = null;
238
			$month = null;
239
			$day = null;
240
		}
241
 
242
		while ($i_format < $pattern_length)
243
		{
244
			$c = $this->charAt($pattern,$i_format);
245
			$token='';
246
			while ($this->charEqual($pattern, $i_format, $c)
247
						&& ($i_format < $pattern_length))
248
			{
249
				$token .= $this->charAt($pattern, $i_format++);
250
			}
251
 
252
			if ($token=='yyyy' || $token=='yy' || $token=='y')
253
			{
254
				if ($token=='yyyy') { $x=4;$y=4; }
255
				if ($token=='yy')   { $x=2;$y=2; }
256
				if ($token=='y')    { $x=2;$y=4; }
257
				$year = $this->getInteger($value,$i_val,$x,$y);
258
				if($year === null)
259
					return null;
260
					//throw new TInvalidDataValueException('Invalid year', $value);
261
				$i_val += strlen($year);
262
				if(strlen($year) == 2)
263
				{
264
					$iYear = (int)$year;
265
					if($iYear > 70)
266
						$year = $iYear + 1900;
267
					else
268
						$year = $iYear + 2000;
269
				}
270
				$year = (int)$year;
271
			}
272
			elseif($token=='MM' || $token=='M')
273
			{
274
				$month=$this->getInteger($value,$i_val,
275
									$this->length($token),2);
276
				$iMonth = (int)$month;
277
				if($month === null || $iMonth < 1 || $iMonth > 12 )
278
					return null;
279
					//throw new TInvalidDataValueException('Invalid month', $value);
280
				$i_val += strlen($month);
281
				$month = $iMonth;
282
			}
283
			elseif ($token=='dd' || $token=='d')
284
			{
285
				$day = $this->getInteger($value,$i_val,
286
									$this->length($token), 2);
287
				$iDay = (int)$day;
288
				if($day === null || $iDay < 1 || $iDay >31)
289
					return null;
290
					//throw new TInvalidDataValueException('Invalid day', $value);
291
				$i_val += strlen($day);
292
				$day = $iDay;
293
			}
294
			else
295
			{
296
				if($this->substring($value, $i_val, $this->length($token)) != $token)
297
					return null;
298
					//throw new TInvalidDataValueException("Subpattern '{$this->pattern}' mismatch", $value);
299
				else
300
					$i_val += $this->length($token);
301
			}
302
		}
303
		if ($i_val != $this->length($value))
304
			throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
305
		if(!$defaultToCurrentTime && ($month === null || $day === null || $year === null))
306
			return null;
307
		else
308
		{
309
			if(empty($year)) {
310
				$year = date('Y');
311
			}
312
			$day = (int)$day <= 0 ? 1 : (int)$day;
313
			$month = (int)$month <= 0 ? 1 : (int)$month;
314
			$s = Prado::createComponent('System.Util.TDateTimeStamp');
315
			return $s->getTimeStamp(0, 0, 0, $month, $day, $year);
316
		}
317
	}
318
 
319
	/**
320
	 * Calculate the length of a string, may be consider iconv_strlen?
321
	 */
322
	private function length($string)
323
	{
324
		//use iconv_strlen or just strlen?
325
		return strlen($string);
326
	}
327
 
328
	/**
329
	 * Get the char at a position.
330
	 */
331
	private function charAt($string, $pos)
332
	{
333
		return $this->substring($string, $pos, 1);
334
	}
335
 
336
	/**
337
	 * Gets a portion of a string, uses iconv_substr.
338
	 */
339
	private function substring($string, $start, $length)
340
	{
341
		return iconv_substr($string, $start, $length);
342
	}
343
 
344
	/**
345
	 * Returns true if char at position equals a particular char.
346
	 */
347
	private function charEqual($string, $pos, $char)
348
	{
349
		return $this->charAt($string, $pos) == $char;
350
	}
351
 
352
	/**
353
	 * Gets integer from part of a string, allows integers of any length.
354
	 * @param string string to retrieve the integer from.
355
	 * @param int starting position
356
	 * @param int minimum integer length
357
	 * @param int maximum integer length
358
	 * @return string integer portion of the string, null otherwise
359
	 */
360
	private function getInteger($str,$i,$minlength,$maxlength)
361
	{
362
		//match for digits backwards
363
		for ($x = $maxlength; $x >= $minlength; $x--)
364
		{
365
			$token= $this->substring($str, $i,$x);
366
			if ($this->length($token) < $minlength)
367
				return null;
368
			if (preg_match('/^\d+$/', $token))
369
				return $token;
370
		}
371
		return null;
372
	}
373
}
374
 
375
?>