]> git.sur5r.net Git - bacula/bacula/blob - gui/baculum/framework/Util/TSimpleDateFormatter.php
Add Baculum
[bacula/bacula] / gui / baculum / framework / Util / TSimpleDateFormatter.php
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-2013 PradoSoft
8  * @license http://www.pradosoft.com/license/
9  * @version $Id: TSimpleDateFormatter.php 3245 2013-01-07 20:23:32Z ctrlaltca $
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 3245 2013-01-07 20:23:32Z ctrlaltca $
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                 $s = Prado::createComponent('System.Util.TDateTimeStamp');
177                 if(is_numeric($value))
178                         return $s->getDate($value);
179                 else
180                         return $s->parseDate($value);           
181         }
182
183         /**
184          * @return boolean true if the given value matches with the date pattern.
185          */
186         public function isValidDate($value)
187         {
188                 if($value === null) {
189                         return false;
190                 } else {
191                         return $this->parse($value, false) !== null;
192                 }
193         }
194
195         /**
196          * Parse the string according to the pattern.
197          * @param string|int date string or integer to parse
198          * @return int date time stamp
199          * @throws TInvalidDataValueException if date string is malformed.
200          */
201         public function parse($value,$defaultToCurrentTime=true)
202         {
203                 if(is_int($value) || is_float($value))
204                         return $value;
205                 else if(!is_string($value))
206                         throw new TInvalidDataValueException('date_to_parse_must_be_string', $value);
207
208                 if(empty($this->pattern)) return time();
209
210                 $date = time();
211
212                 if($this->length(trim($value)) < 1)
213                         return $defaultToCurrentTime ? $date : null;
214
215                 $pattern = $this->pattern;
216
217                 $i_val = 0;
218                 $i_format = 0;
219                 $pattern_length = $this->length($pattern);
220                 $c = '';
221                 $token='';
222                 $x=null; $y=null;
223
224
225                 if($defaultToCurrentTime)
226                 {
227                         $year = "{$date['year']}";
228                         $month = $date['mon'];
229                         $day = $date['mday'];
230                 }
231                 else
232                 {
233                         $year = null;
234                         $month = null;
235                         $day = null;
236                 }
237
238                 while ($i_format < $pattern_length)
239                 {
240                         $c = $this->charAt($pattern,$i_format);
241                         $token='';
242                         while ($this->charEqual($pattern, $i_format, $c)
243                                                 && ($i_format < $pattern_length))
244                         {
245                                 $token .= $this->charAt($pattern, $i_format++);
246                         }
247
248                         if ($token=='yyyy' || $token=='yy' || $token=='y')
249                         {
250                                 if ($token=='yyyy') { $x=4;$y=4; }
251                                 if ($token=='yy')   { $x=2;$y=2; }
252                                 if ($token=='y')    { $x=2;$y=4; }
253                                 $year = $this->getInteger($value,$i_val,$x,$y);
254                                 if($year === null)
255                                         return null;
256                                         //throw new TInvalidDataValueException('Invalid year', $value);
257                                 $i_val += strlen($year);
258                                 if(strlen($year) == 2)
259                                 {
260                                         $iYear = (int)$year;
261                                         if($iYear > 70)
262                                                 $year = $iYear + 1900;
263                                         else
264                                                 $year = $iYear + 2000;
265                                 }
266                                 $year = (int)$year;
267                         }
268                         elseif($token=='MM' || $token=='M')
269                         {
270                                 $month=$this->getInteger($value,$i_val,
271                                                                         $this->length($token),2);
272                                 $iMonth = (int)$month;
273                                 if($month === null || $iMonth < 1 || $iMonth > 12 )
274                                         return null;
275                                         //throw new TInvalidDataValueException('Invalid month', $value);
276                                 $i_val += strlen($month);
277                                 $month = $iMonth;
278                         }
279                         elseif ($token=='dd' || $token=='d')
280                         {
281                                 $day = $this->getInteger($value,$i_val,
282                                                                         $this->length($token), 2);
283                                 $iDay = (int)$day;
284                                 if($day === null || $iDay < 1 || $iDay >31)
285                                         return null;
286                                         //throw new TInvalidDataValueException('Invalid day', $value);
287                                 $i_val += strlen($day);
288                                 $day = $iDay;
289                         }
290                         else
291                         {
292                                 if($this->substring($value, $i_val, $this->length($token)) != $token)
293                                         return null;
294                                         //throw new TInvalidDataValueException("Subpattern '{$this->pattern}' mismatch", $value);
295                                 else
296                                         $i_val += $this->length($token);
297                         }
298                 }
299                 if ($i_val != $this->length($value))
300                         return null;
301                         //throw new TInvalidDataValueException("Pattern '{$this->pattern}' mismatch", $value);
302                 if(!$defaultToCurrentTime && ($month === null || $day === null || $year === null))
303                         return null;
304                 else
305                 {               
306                         if(empty($year)) {
307                                 $year = date('Y');
308                         }
309                         $day = (int)$day <= 0 ? 1 : (int)$day;
310                         $month = (int)$month <= 0 ? 1 : (int)$month;
311                         $s = Prado::createComponent('System.Util.TDateTimeStamp');
312                         return $s->getTimeStamp(0, 0, 0, $month, $day, $year);
313                 }
314         }
315
316         /**
317          * Calculate the length of a string, may be consider iconv_strlen?
318          */
319         private function length($string)
320         {
321                 //use iconv_strlen or just strlen?
322                 return strlen($string);
323         }
324
325         /**
326          * Get the char at a position.
327          */
328         private function charAt($string, $pos)
329         {
330                 return $this->substring($string, $pos, 1);
331         }
332
333         /**
334          * Gets a portion of a string, uses iconv_substr.
335          */
336         private function substring($string, $start, $length)
337         {
338                 return iconv_substr($string, $start, $length);
339         }
340
341         /**
342          * Returns true if char at position equals a particular char.
343          */
344         private function charEqual($string, $pos, $char)
345         {
346                 return $this->charAt($string, $pos) == $char;
347         }
348
349         /**
350          * Gets integer from part of a string, allows integers of any length.
351          * @param string string to retrieve the integer from.
352          * @param int starting position
353          * @param int minimum integer length
354          * @param int maximum integer length
355          * @return string integer portion of the string, null otherwise
356          */
357         private function getInteger($str,$i,$minlength,$maxlength)
358         {
359                 //match for digits backwards
360                 for ($x = $maxlength; $x >= $minlength; $x--)
361                 {
362                         $token= $this->substring($str, $i,$x);
363                         if ($this->length($token) < $minlength)
364                                 return null;
365                         if (preg_match('/^\d+$/', $token))
366                                 return $token;
367                 }
368                 return null;
369         }
370 }
371