001    // TODO Time constructor muss auch noch entfernt werden und durch DateUtil methode ersetzen
002    package railo.runtime.op.date;
003    
004    import java.text.DateFormat;
005    import java.text.ParsePosition;
006    import java.util.Calendar;
007    import java.util.Date;
008    import java.util.Locale;
009    import java.util.TimeZone;
010    
011    import railo.commons.date.DateTimeUtil;
012    import railo.commons.date.TimeZoneConstants;
013    import railo.commons.i18n.FormatUtil;
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.Component;
016    import railo.runtime.engine.ThreadLocalPageContext;
017    import railo.runtime.exp.ExpressionException;
018    import railo.runtime.exp.PageException;
019    import railo.runtime.op.Castable;
020    import railo.runtime.op.Caster;
021    import railo.runtime.op.Decision;
022    import railo.runtime.type.ObjectWrap;
023    import railo.runtime.type.dt.DateTime;
024    import railo.runtime.type.dt.DateTimeImpl;
025    import railo.runtime.type.dt.Time;
026    import railo.runtime.type.dt.TimeImpl;
027    
028    /**
029     * Class to cast Strings to Date Objects
030     */
031    public final class DateCaster {
032    
033            //private static short MODE_DAY_STR=1;
034            //private static short MODE_MONTH_STR=2;
035            //private static short MODE_NONE=4;
036            private static long DEFAULT_VALUE=Long.MIN_VALUE;
037            
038            private static DateTimeUtil util=DateTimeUtil.getInstance();
039            public static boolean classicStyle=false;
040            
041            /**     
042             * converts a Object to a DateTime Object (Advanced but slower)
043             * @param o Object to Convert
044             * @param timezone
045             * @return Date Time Object
046             * @throws PageException
047             */
048            public static DateTime toDateAdvanced(Object o,TimeZone timezone) throws PageException {
049                    if(o instanceof Date)           {
050                            if(o instanceof DateTime) return (DateTime)o;
051                            return new DateTimeImpl((Date)o);
052                    }
053                    else if(o instanceof Castable)  return ((Castable)o).castToDateTime();
054                    else if(o instanceof String)    {
055                        DateTime dt=toDateAdvanced((String)o,timezone,null);
056                        if(dt==null)
057                                    throw new ExpressionException("can't cast ["+o+"] to date value");
058                        return dt;
059                    }
060                    else if(o instanceof Number)            return util.toDateTime(((Number)o).doubleValue());
061                    else if(o instanceof ObjectWrap) return toDateAdvanced(((ObjectWrap)o).getEmbededObject(),timezone);
062                    else if(o instanceof Calendar){
063                            
064                            return new DateTimeImpl((Calendar)o);
065                    }
066                    throw new ExpressionException("can't cast ["+Caster.toClassName(o)+"] to date value");
067            }
068            
069            /**
070             * converts a Object to a DateTime Object (Advanced but slower)
071             * @param str String to Convert
072             * @param timezone
073             * @return Date Time Object
074             * @throws PageException
075             */
076            public static DateTime toDateAdvanced(String str,TimeZone timezone) throws PageException {
077                    DateTime dt=toDateAdvanced(str,timezone,null);
078                if(dt==null)
079                            throw new ExpressionException("can't cast ["+str+"] to date value");
080                return dt;
081            }
082    
083            /**
084             * converts a Object to a DateTime Object (Advanced but slower), returns null if invalid string
085             * @param o Object to Convert
086             * @param timeZone
087             * @param defaultValue 
088             * @return Date Time Object
089             */
090            public static DateTime toDateAdvanced(Object o,TimeZone timeZone, DateTime defaultValue) {
091                    if(o instanceof DateTime)               return (DateTime)o;
092                    else if(o instanceof Date)              return new DateTimeImpl((Date)o);
093                    else if(o instanceof Castable)  {
094                        return ((Castable)o).castToDateTime(defaultValue);
095                    }
096                    else if(o instanceof String)    return toDateAdvanced(o.toString(),timeZone,defaultValue);
097                    else if(o instanceof Number)    return util.toDateTime(((Number)o).doubleValue());
098                    else if(o instanceof Calendar){
099                            return new DateTimeImpl((Calendar)o);
100                    }
101                    else if(o instanceof ObjectWrap) return toDateAdvanced(((ObjectWrap)o).getEmbededObject(defaultValue),timeZone,defaultValue);
102                    return defaultValue;
103            }
104    
105            /**
106             * converts a String to a DateTime Object (Advanced but slower), returns null if invalid string
107             * @param str String to convert
108             * @param timeZone
109             * @param defaultValue 
110             * @return Date Time Object
111             */
112            public static DateTime toDateAdvanced(String str,boolean alsoNumbers,TimeZone timeZone, DateTime defaultValue) {
113                    str=str.trim();
114                    timeZone=ThreadLocalPageContext.getTimeZone(timeZone);
115                    DateTime dt=toDateSimple(str,alsoNumbers,timeZone,defaultValue);
116                    if(dt==null) {  
117                    DateFormat[] formats = FormatUtil.getCFMLFormats(timeZone, true);
118                        synchronized(formats){
119                            Date d;
120                            ParsePosition pp=new ParsePosition(0);
121                            for(int i=0;i<formats.length;i++) {
122                                            //try {
123                                                    pp.setErrorIndex(-1);
124                                                    pp.setIndex(0);
125                                                    d = formats[i].parse(str,pp);
126                                                    if (pp.getIndex() == 0 || d==null || pp.getIndex()<str.length()) continue;                                           
127                                                    dt= new DateTimeImpl(d.getTime(),false);
128                                                    return dt;
129                                            //}catch (ParseException e) {}
130                                    }
131                    }
132                        dt=Caster.toDateTime(Locale.US, str, timeZone,defaultValue, false);
133                }
134                return dt;
135            }
136            
137            public static DateTime toDateAdvanced(String str, TimeZone timeZone, DateTime defaultValue) {
138                return toDateAdvanced(str, true, timeZone,defaultValue);
139            }
140            
141            /**
142             * converts a boolean to a DateTime Object
143             * @param b boolean to Convert
144             * @param timeZone 
145             * @return coverted Date Time Object
146             */
147            public static DateTime toDateSimple(boolean b, TimeZone timeZone) {
148                    return toDateSimple(b?1L:0L, timeZone);
149            }
150    
151            /**
152             * converts a char to a DateTime Object
153             * @param c char to Convert
154             * @param timeZone
155             * @return coverted Date Time Object
156             */
157            public static DateTime toDateSimple(char c, TimeZone timeZone) {
158                    return toDateSimple((long)c, timeZone);
159            }
160    
161            /**
162             * converts a double to a DateTime Object
163             * @param d double to Convert
164             * @param timeZone
165             * @return coverted Date Time Object
166             */
167            public static DateTime toDateSimple(double d, TimeZone timeZone) {
168                    return toDateSimple((long)d, timeZone);
169            }
170            
171            /* *
172             * converts a double to a DateTime Object
173             * @param d double to Convert
174             * @param timeZone
175             * @return coverted Date Time Object
176             * /
177            public static DateTime toDateSimple(long l, TimeZone timezone) {
178                    return new DateTimeImpl(l,false);
179            }*/
180    
181            /**
182             * converts a Object to a DateTime Object, returns null if invalid string
183             * @param o Object to Convert
184             * @param timeZone
185             * @return coverted Date Time Object
186             * @throws PageException
187             */
188            public static DateTime toDateSimple(Object o, TimeZone timeZone) throws PageException {
189                    if(o instanceof DateTime)               return (DateTime)o;
190                    else if(o instanceof Date)              return new DateTimeImpl((Date)o);
191                    else if(o instanceof Castable)  return ((Castable)o).castToDateTime();
192                    else if(o instanceof String)    return toDateSimple(o.toString(),true, timeZone);
193                    else if(o instanceof Number)            return util.toDateTime(((Number)o).doubleValue());
194                    else if(o instanceof Calendar)          return new DateTimeImpl((Calendar)o);
195                    else if(o instanceof ObjectWrap) return toDateSimple(((ObjectWrap)o).getEmbededObject(),timeZone);
196                    else if(o instanceof Calendar){
197                            return new DateTimeImpl((Calendar)o);
198                    }
199                    
200                    if(o instanceof Component)
201                            throw new ExpressionException("can't cast component ["+((Component)o).getAbsName()+"] to date value");
202                    
203                    throw new ExpressionException("can't cast ["+Caster.toTypeName(o)+"] to date value");
204            }
205            
206            /**
207             * converts a Object to a DateTime Object, returns null if invalid string
208             * @param str String to Convert
209             * @param timeZone
210             * @return coverted Date Time Object
211             * @throws PageException
212             */
213            public static DateTime toDateSimple(String str, TimeZone timeZone) throws PageException {
214                     DateTime dt=toDateSimple(str,true, timeZone,null);
215                     if(dt==null)
216                             throw new ExpressionException("can't cast ["+str+"] to date value");
217                     return dt;
218            }
219    
220            /**
221             * converts a Object to a Time Object, returns null if invalid string
222             * @param o Object to Convert
223             * @return coverted Date Time Object
224             * @throws PageException
225             */
226            public static Time toTime(TimeZone timeZone,Object o) throws PageException {
227                if(o instanceof Time)               return (Time)o;
228                else if(o instanceof Date)          return new TimeImpl((Date)o);
229                    else if(o instanceof Castable)  return new TimeImpl(((Castable)o).castToDateTime());
230                    else if(o instanceof String)    {
231                        Time dt=toTime(timeZone,o.toString(),null);
232                        if(dt==null)
233                                    throw new ExpressionException("can't cast ["+o+"] to time value");
234                        return dt;
235                    }
236                    else if(o instanceof ObjectWrap) return toTime(timeZone,((ObjectWrap)o).getEmbededObject());
237                    else if(o instanceof Calendar){
238                            // TODO check timezone offset
239                            return new TimeImpl(((Calendar)o).getTimeInMillis(),false);
240                    }
241                    throw new ExpressionException("can't cast ["+Caster.toClassName(o)+"] to time value");
242            }
243    
244        /**
245         * converts a Object to a DateTime Object, returns null if invalid string
246         * @param o Object to Convert
247         * @param alsoNumbers
248         * @param timeZone
249         * @param defaultValue 
250         * @return coverted Date Time Object
251         */
252             public static DateTime toDateSimple(Object o,boolean alsoNumbers, TimeZone timeZone, DateTime defaultValue) {
253                     return _toDateAdvanced(o, alsoNumbers, timeZone, defaultValue, false);
254             }
255             
256             public static DateTime toDateAdvanced(Object o,boolean alsoNumbers, TimeZone timeZone, DateTime defaultValue) {
257            return _toDateAdvanced(o, alsoNumbers, timeZone, defaultValue, true);
258             }
259             
260             private static DateTime _toDateAdvanced(Object o,boolean alsoNumbers, TimeZone timeZone, DateTime defaultValue, boolean advanced) {
261            if(o instanceof DateTime)       return (DateTime)o;
262            else if(o instanceof Date)      return new DateTimeImpl((Date)o);
263            else if(o instanceof Castable)  {
264                return ((Castable)o).castToDateTime(defaultValue);
265            }
266            else if(o instanceof String)    {
267                    if(advanced)return toDateAdvanced(o.toString(),alsoNumbers, timeZone,defaultValue);
268                    return toDateSimple(o.toString(),alsoNumbers, timeZone,defaultValue);
269            }
270            else if(alsoNumbers && o instanceof Number)     return util.toDateTime(((Number)o).doubleValue());
271            else if(o instanceof ObjectWrap) {
272                    return _toDateAdvanced(((ObjectWrap)o).getEmbededObject(defaultValue),alsoNumbers,timeZone,defaultValue,advanced);
273            }
274            else if(o instanceof Calendar){
275                            return new DateTimeImpl((Calendar)o);
276                    }
277                    return defaultValue;
278        }
279                
280        
281    
282        /**
283         * converts a Object to a DateTime Object, returns null if invalid string
284         * @param o Object to Convert
285         * @param alsoNumbers
286         * @param timeZone
287         * @return coverted Date Time Object
288         * @throws PageException  
289         */
290        public static DateTime toDateSimple(Object o,boolean alsoNumbers, TimeZone timeZone) throws PageException {
291            DateTime dt = toDateSimple(o,alsoNumbers,timeZone,null);
292            if(dt==null) throw new ExpressionException("can't cast value to a Date Object");
293            return dt;
294        }
295        
296        public static DateTime toDateAdvanced(Object o,boolean alsoNumbers, TimeZone timeZone) throws PageException {
297            DateTime dt = toDateAdvanced(o,alsoNumbers,timeZone,null);
298            if(dt==null) throw new ExpressionException("can't cast value to a Date Object");
299            return dt;
300        }
301        
302        
303            
304            /**
305             * converts a String to a Time Object, returns null if invalid string
306             * @param str String to convert
307             * @param defaultValue 
308             * @return Time Object
309             * @throws  
310             */
311            public static Time toTime(TimeZone timeZone,String str, Time defaultValue)  {
312                    
313                    if(str==null || str.length()<3) {
314                        return defaultValue;
315                    }
316                    DateString ds=new DateString(str);
317            // Timestamp
318                    if(ds.isCurrent('{') && ds.isLast('}')) {
319                        
320                            // Time
321                            // "^\\{t '([0-9]{1,2}):([0-9]{1,2}):([0-9]{2})'\\}$"
322                            if(ds.fwIfNext('t')) {
323                                        
324                                        // Time
325                                                    if(!(ds.fwIfNext(' ') && ds.fwIfNext('\'')))return defaultValue;
326                                                    ds.next();
327                                            // hour
328                                                    int hour=ds.readDigits();
329                                                    if(hour==-1) return defaultValue;
330                                                    
331                                                    if(!ds.fwIfCurrent(':'))return defaultValue;
332                                            
333                                            // minute
334                                                    int minute=ds.readDigits();
335                                                    if(minute==-1) return defaultValue;
336                                                    
337                                                    if(!ds.fwIfCurrent(':'))return defaultValue;
338                                            
339                                            // second
340                                                    int second=ds.readDigits();
341                                                    if(second==-1) return defaultValue;
342                                                    
343                                                    if(!(ds.fwIfCurrent('\'') && ds.fwIfCurrent('}')))return defaultValue;
344                                                    
345                                                    if(ds.isAfterLast()){
346                                                            long time=util.toTime(timeZone,1899,12,30,hour,minute,second,0,DEFAULT_VALUE);
347                                                            if(time==DEFAULT_VALUE)return defaultValue;
348                                                            return new TimeImpl(time,false);
349                                                    }
350                                                    return defaultValue;
351                                    
352                                                    
353                            }
354                            return defaultValue;
355                    }
356            // Time start with int
357                    /*else if(ds.isDigit()) {
358                        char sec=ds.charAt(1);
359                        char third=ds.charAt(2);
360                        // 16.10.2004 (02:15)?
361                            if(sec==':' || third==':') {
362                                    // hour
363                                    int hour=ds.readDigits();
364                                    if(hour==-1) return defaultValue;
365                                    
366                                    if(!ds.fwIfCurrent(':'))return defaultValue;
367                                    
368                                    // minutes
369                                    int minutes=ds.readDigits();
370                                    if(minutes==-1) return defaultValue;
371                                    
372                                    if(ds.isAfterLast()) {
373                                            long time=util.toTime(timeZone,1899,12,30,hour,minutes,0,0,DEFAULT_VALUE);
374                                            if(time==DEFAULT_VALUE) return defaultValue;
375                                            
376                                            return new TimeImpl(time,false);
377                                    }
378                                    //else if(!ds.fwIfCurrent(':'))return null;
379                                    else if(!ds.fwIfCurrent(':')) {
380                                        if(!ds.fwIfCurrent(' '))return defaultValue;
381                                        
382                                        if(ds.fwIfCurrent('a') || ds.fwIfCurrent('A'))      {
383                                            if(ds.fwIfCurrent('m') || ds.fwIfCurrent('M')) {
384                                                if(ds.isAfterLast()) {
385                                                    long time=util.toTime(timeZone,1899,12,30,hour,minutes,0,0,DEFAULT_VALUE);
386                                                                    if(time==DEFAULT_VALUE) return defaultValue;
387                                                    return new TimeImpl(time,false);
388                                                }
389                                            }
390                                            return defaultValue;
391                                        }
392                                        else if(ds.fwIfCurrent('p') || ds.fwIfCurrent('P')) {
393                                            if(ds.fwIfCurrent('m') || ds.fwIfCurrent('M')) {
394                                                if(ds.isAfterLast()) {
395                                                    long time=util.toTime(timeZone,1899,12,30,hour<13?hour+12:hour,minutes,0,0,DEFAULT_VALUE);
396                                                                    if(time==DEFAULT_VALUE) return defaultValue;
397                                                                    return new TimeImpl(time,false);
398                                                }
399                                            }
400                                            return defaultValue;
401                                        }
402                                        return defaultValue;
403                                    }
404                                    
405                                    
406                                    // seconds
407                                    int seconds=ds.readDigits();
408                                    if(seconds==-1) return defaultValue;
409                                    
410                                    if(ds.isAfterLast()) {
411                                            long time=util.toTime(timeZone,1899,12,30,hour,minutes,seconds,0,DEFAULT_VALUE);
412                                            if(time==DEFAULT_VALUE) return defaultValue;
413                                            return new TimeImpl(time,false);
414                                    }
415                                                                    
416                        }
417                    }*/
418                    
419                    // TODO bessere impl
420                    ds.reset();
421                    DateTime rtn = parseTime(timeZone, new int[]{1899,12,30}, ds, defaultValue,-1);
422                    if(rtn==defaultValue) return defaultValue;
423                    return new TimeImpl(rtn);
424                    
425                    
426                    
427                    //return defaultValue;
428            }
429    
430            
431            
432            /**
433             * converts a String to a DateTime Object, returns null if invalid string
434             * @param str String to convert
435             * @param alsoNumbers
436             * @param timeZone
437             * @param defaultValue 
438             * @return Date Time Object
439             */     
440            private static DateTime parseDateTime(String str,DateString ds,boolean alsoNumbers,TimeZone timeZone, DateTime defaultValue) {
441                    int month=0;
442                    int first=ds.readDigits();
443                    // first
444                    if(first==-1) {
445                            first=ds.readMonthString();
446                            if(first==-1)return defaultValue;
447                            month=1;
448                    }
449                    
450                    if(ds.isAfterLast()) return month==1?defaultValue:toNumberDate(str,alsoNumbers,defaultValue);
451                    
452                    char del=ds.current();
453                    if(del!='.' && del!='/' && del!='-' && del!=' ' && del!='\t') {
454                            if(ds.fwIfCurrent(':')){
455                                    return parseTime(timeZone, new int[]{1899,12,30}, ds, defaultValue,first);
456                            }
457                            return defaultValue;
458                    }
459                    ds.next();
460                    ds.removeWhitespace();
461                    
462                    // second
463                    int second=ds.readDigits();
464                    if(second==-1){
465                            second=ds.readMonthString();
466                            if(second==-1)return defaultValue;
467                            month=2;
468                    }
469                    
470                    if(ds.isAfterLast()) {
471                            return toDate(month,timeZone,first,second,defaultValue);
472                    }
473                    
474                    char del2=ds.current();
475                    if(del!=del2) {
476                            ds.fwIfCurrent(' ');
477                            ds.fwIfCurrent('T');
478                            ds.fwIfCurrent(' ');
479                            return parseTime(timeZone,_toDate(timeZone,month, first, second),ds,defaultValue,-1);
480                    }
481                    ds.next();
482                    ds.removeWhitespace();
483                    
484                    
485                    
486                    int third=ds.readDigits();
487                    if(third==-1){
488                            return defaultValue;
489                    }
490                    
491                    if(ds.isAfterLast()) {
492                            if(classicStyle() && del=='.')return toDate(month,timeZone,second,first,third,defaultValue);
493                            return toDate(month,timeZone,first,second,third,defaultValue);
494                    }
495                    ds.fwIfCurrent(' ');
496                    ds.fwIfCurrent('T');
497                    ds.fwIfCurrent(' ');
498                    if(classicStyle() && del=='.')return parseTime(timeZone,_toDate(month, second,first,third),ds,defaultValue,-1);
499                    return parseTime(timeZone,_toDate(month, first, second,third),ds,defaultValue,-1);
500                    
501                    
502            }
503            
504            private static boolean classicStyle() {
505                    return classicStyle;
506            }
507    
508            private static DateTime parseTime(TimeZone timeZone,int[] date, DateString ds,DateTime defaultValue, int hours) {
509                    if(date==null)return defaultValue;
510                    
511    
512                    ds.removeWhitespace();
513                    
514                    // hour
515                    boolean next=false;
516                    if(hours==-1){
517                            ds.removeWhitespace();
518                            hours=ds.readDigits();
519                            ds.removeWhitespace();
520                            if(hours==-1) {
521                                    return parseOffset(ds,timeZone,date,0,0,0,0,defaultValue);
522                            }
523                    }
524                    else next=true;
525                    
526                    int minutes=0;
527                    if(next || ds.fwIfCurrent(':')){
528                            ds.removeWhitespace();
529                            minutes=ds.readDigits();
530                            ds.removeWhitespace();
531                            if(minutes==-1) return defaultValue;
532                    }
533                    
534    
535                    int seconds=0;
536                    if(ds.fwIfCurrent(':')){
537                            ds.removeWhitespace();
538                            seconds=ds.readDigits();
539                            ds.removeWhitespace();
540                            if(seconds==-1) return defaultValue;
541                    }
542                    
543                    int msSeconds=0;
544                    if(ds.fwIfCurrent('.')){
545                            ds.removeWhitespace();
546                            msSeconds=ds.readDigits();
547                            ds.removeWhitespace();
548                            if(msSeconds==-1) return defaultValue;
549                    }
550                    
551                    if(ds.isAfterLast()){
552                            return DateTimeUtil.getInstance().toDateTime(timeZone, date[0], date[1], date[2], hours, minutes, seconds, msSeconds, defaultValue);
553                    }
554                    ds.fwIfCurrent(' ');
555                    
556                    if(ds.fwIfCurrent('a') || ds.fwIfCurrent('A'))  {
557                            if(!ds.fwIfCurrent('m'))ds.fwIfCurrent('M');
558                    if(ds.isAfterLast()) 
559                        return DateTimeUtil.getInstance().toDateTime(timeZone, date[0], date[1], date[2], 
560                                    hours<12?hours:hours-12, minutes, seconds, msSeconds, defaultValue);
561                    return defaultValue;
562                }
563                else if(ds.fwIfCurrent('p') || ds.fwIfCurrent('P')) {
564                    if(!ds.fwIfCurrent('m'))ds.fwIfCurrent('M');
565                    if(hours>24) return defaultValue;
566                    if(ds.isAfterLast()) 
567                            return DateTimeUtil.getInstance().toDateTime(timeZone, date[0], date[1], date[2], 
568                                            hours<12?hours+12:hours, minutes, seconds, msSeconds,defaultValue);
569                    return defaultValue;
570                }
571                    
572                    ds.fwIfCurrent(' ');
573                    return parseOffset(ds,timeZone,date,hours,minutes,seconds,msSeconds,defaultValue);
574                
575            }
576    
577            private static DateTime parseOffset(DateString ds, TimeZone timeZone, int[] date,int hours, int minutes, int seconds, int msSeconds,DateTime defaultValue) {
578                    if(ds.isLast() && (ds.fwIfCurrent('Z') ||  ds.fwIfCurrent('z'))) {
579                            return util.toDateTime(TimeZoneConstants.UTC, date[0], date[1], date[2], hours, minutes, seconds, msSeconds,defaultValue);
580                    }
581                    else if(ds.fwIfCurrent('+')){
582                    DateTime rtn = util.toDateTime(timeZone, date[0], date[1], date[2], hours, minutes, seconds, msSeconds,defaultValue);
583                    if(rtn==defaultValue) return rtn;
584                    return readOffset(true,timeZone,rtn,date[0], date[1], date[2], hours, minutes, seconds, msSeconds,ds,defaultValue);
585                }
586                else if(ds.fwIfCurrent('-')){
587                    DateTime rtn = util.toDateTime(timeZone, date[0], date[1], date[2], hours, minutes, seconds, msSeconds, defaultValue);
588                    if(rtn==defaultValue) return rtn;
589                    return readOffset(false,timeZone,rtn,date[0], date[1], date[2], hours, minutes, seconds, msSeconds,ds,defaultValue);
590                }
591                    return defaultValue;
592            }
593    
594            private static DateTime toDate(int month, TimeZone timeZone,int first, int second, DateTime defaultValue) {
595                    int[] d = _toDate(timeZone,month, first, second);
596                    if(d==null)return defaultValue;
597                    return util.toDateTime(timeZone, d[0], d[1], d[2],0,0,0,0,defaultValue);
598            }
599            
600            private static int[] _toDate(TimeZone tz,int month, int first, int second) {
601                    int YEAR=year(tz);
602                    if(first<=12 && month<2){
603                            if(util.daysInMonth(YEAR, first)>=second)
604                                    return new int[]{YEAR, first, second};
605                            return new int[]{util.toYear(second), first, 1};
606                    }
607                    // first>12
608                    if(second<=12){
609                            if(util.daysInMonth(YEAR, second)>=first)
610                                    return new int[]{YEAR, second, first};
611                            return new int[]{util.toYear(first), second, 1};
612                    }
613                    return null;
614            }
615            private static int year(TimeZone tz) {
616                    return util.getYear(ThreadLocalPageContext.getTimeZone(tz),new DateTimeImpl());
617            }
618    
619            private static DateTime toDate(int month, TimeZone timeZone,int first, int second, int third, DateTime defaultValue) {
620                    int[] d = _toDate(month, first, second, third);
621                    if(d==null) return defaultValue;
622                    return util.toDateTime(timeZone, d[0], d[1], d[2], 0, 0, 0,0,defaultValue);
623            }
624                    
625            private static int[] _toDate(int month, int first, int second, int third) {
626                    if(first<=12){
627                            if(month==2)
628                                    return new int[]{util.toYear(third), second, first};
629                            if(util.daysInMonth(util.toYear(third), first)>=second)
630                                    return new int[]{util.toYear(third), first, second};
631                            return null;
632                    }
633                    if(second>12)return null;
634                    if(month==2){
635                            int tmp=first;
636                            first=third;
637                            third=tmp;
638                    }
639                    if(util.daysInMonth(util.toYear(first), second)<third) {
640                            if(util.daysInMonth(util.toYear(third), second)>=first)
641                                    return new int[]{util.toYear(third), second, first};
642                            return null;
643                    }
644                    return new int[]{util.toYear(first), second, third};
645            }
646            
647            
648            public static DateTime toDateSimple(String str,boolean alsoNumbers, TimeZone timeZone, DateTime defaultValue) {
649                    str=StringUtil.trim(str,"");
650                    
651                    
652                    DateString ds=new DateString(str);
653                    
654            // Timestamp
655                    if(ds.isCurrent('{') && ds.isLast('}')) {
656                            return _toDateSimpleTS(ds,timeZone,defaultValue);
657                    }
658                    DateTime res = parseDateTime(str,ds,alsoNumbers,timeZone,defaultValue);
659                    if(alsoNumbers && res==defaultValue && Decision.isNumeric(str)) {
660                    double dbl = Caster.toDoubleValue(str,Double.NaN);
661                    if(Decision.isValid(dbl))return util.toDateTime(dbl);
662                }
663                    return res;
664            }
665    
666            private static DateTime _toDateSimpleTS(DateString ds, TimeZone timeZone, DateTime defaultValue) {
667                    // Date
668                    // "^\\{d '([0-9]{2,4})-([0-9]{1,2})-([0-9]{1,2})'\\}$"
669                    if(ds.fwIfNext('d')) {
670                            if(!(ds.fwIfNext(' ') && ds.fwIfNext('\'')))return defaultValue;
671                            ds.next();
672                    // year
673                            int year=ds.readDigits();
674                            if(year==-1) return defaultValue;
675                            
676                            if(!ds.fwIfCurrent('-'))return defaultValue;
677                    
678                    // month
679                            int month=ds.readDigits();
680                            if(month==-1) return defaultValue;
681                            
682                            if(!ds.fwIfCurrent('-'))return defaultValue;
683                    
684                    // day
685                            int day=ds.readDigits();
686                            if(day==-1) return defaultValue;
687                            
688                            if(!(ds.fwIfCurrent('\'') && ds.fwIfCurrent('}')))return defaultValue;
689                            
690                            if(ds.isAfterLast()) return util.toDateTime(timeZone,year, month, day, 0, 0, 0, 0, defaultValue);//new DateTimeImpl(year,month,day);
691                            
692                            return defaultValue;
693                            
694                    }
695                    
696                    // DateTime
697                    // "^\\{ts '([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{2}):([0-9]{1,2}):([0-9]{2})'\\}$"
698                    else if(ds.fwIfNext('t')) {
699                            if(!(ds.fwIfNext('s') && ds.fwIfNext(' ') && ds.fwIfNext('\''))) {
700                                    
701                                // Time
702                                            if(!(ds.fwIfNext(' ') && ds.fwIfNext('\'')))return defaultValue;
703                                            ds.next();
704                                    // hour
705                                            int hour=ds.readDigits();
706                                            if(hour==-1) return defaultValue;
707                                            
708                                            if(!ds.fwIfCurrent(':'))return defaultValue;
709                                    
710                                    // minute
711                                            int minute=ds.readDigits();
712                                            if(minute==-1) return defaultValue;
713                                            
714                                            if(!ds.fwIfCurrent(':'))return defaultValue;
715                                    
716                                    // second
717                                            int second=ds.readDigits();
718                                            if(second==-1) return defaultValue;
719                                    
720    
721                       // Milli Second
722                            int millis=0;
723                            
724                            if(ds.fwIfCurrent('.')){
725                                millis=ds.readDigits();
726                            }
727                                            
728                                            
729                                            if(!(ds.fwIfCurrent('\'') && ds.fwIfCurrent('}')))return defaultValue;
730                                            
731                                            
732                                            
733                                            if(ds.isAfterLast()){
734                                                    long time=util.toTime(timeZone,1899,12,30,hour,minute,second,millis,DEFAULT_VALUE);
735                                                    if(time==DEFAULT_VALUE)return defaultValue;
736                                                    return new TimeImpl(time,false);
737                                            }
738                                            return defaultValue;
739                            }
740                            ds.next();
741                    // year
742                            int year=ds.readDigits();
743                            if(year==-1) return defaultValue;
744                            
745                            if(!ds.fwIfCurrent('-'))return defaultValue;
746                    
747                    // month
748                            int month=ds.readDigits();
749                            if(month==-1) return defaultValue;
750                            
751                            if(!ds.fwIfCurrent('-'))return defaultValue;
752                    
753                    // day
754                            int day=ds.readDigits();
755                            if(day==-1) return defaultValue;
756                            
757                            if(!ds.fwIfCurrent(' '))return defaultValue;
758                    
759                    // hour
760                            int hour=ds.readDigits();
761                            if(hour==-1) return defaultValue;
762                            
763                            if(!ds.fwIfCurrent(':'))return defaultValue;
764                    
765                    // minute
766                            int minute=ds.readDigits();
767                            if(minute==-1) return defaultValue;
768                            
769                            if(!ds.fwIfCurrent(':'))return defaultValue;
770                    
771                    // second
772                            int second=ds.readDigits();
773                            if(second==-1) return defaultValue;
774                            
775    
776    
777           // Milli Second
778                int millis=0;
779                
780                if(ds.fwIfCurrent('.')){
781                    millis=ds.readDigits();
782                }
783                
784                if(!(ds.fwIfCurrent('\'') && ds.fwIfCurrent('}')))return defaultValue;
785                if(ds.isAfterLast())return util.toDateTime(timeZone,year, month, day,hour,minute,second,millis,defaultValue);//new DateTimeImpl(year,month,day,hour,minute,second);
786                            return defaultValue;
787                            
788                    }
789                    else return defaultValue;
790            }
791    
792            private static DateTime toNumberDate(String str,boolean alsoNumbers, DateTime defaultValue) {
793                if(!alsoNumbers) return defaultValue;
794                    double dbl = Caster.toDoubleValue(str,Double.NaN);
795                    if(Decision.isValid(dbl))return util.toDateTime(dbl);
796                return defaultValue;
797            }
798    
799        /**
800             * reads a offset definition at the end of a date string
801         * @param timeZone
802             * @param dt previous parsed date Object
803             * @param ds DateString to parse
804         * @param defaultValue 
805             * @return date Object with offset
806         */
807        private static DateTime readOffset(boolean isPlus,TimeZone timeZone,DateTime dt,int years, int months, int days, int hours, int minutes, int seconds, int milliSeconds, DateString ds,DateTime defaultValue) {
808        //timeZone=ThreadLocalPageContext.getTimeZone(timeZone);
809        if(timeZone==null) return defaultValue;
810            // HOUR
811            int hourLength=ds.getPos();
812            int hour=ds.readDigits();
813            hourLength=ds.getPos()-hourLength;
814            if(hour==-1) return defaultValue;
815            
816            // MINUTE
817            int minute=0;
818            if(!ds.isAfterLast()) {
819                    if(!ds.fwIfCurrent(':'))return defaultValue;            
820                    minute=ds.readDigits();
821                    if(minute==-1) return defaultValue;
822                    
823            }
824            else if(hourLength>2){
825                    int h=hour/100;
826                    minute=hour-(h*100);
827                    hour=h;
828            }
829    
830            if(hour>12) return defaultValue;
831            if(minute>59) return defaultValue;
832            if(hour==12 && minute>0) return defaultValue;
833            
834            long offset = hour*60L*60L*1000L;
835            offset+=minute*60*1000;
836            
837            if(ds.isAfterLast()) {
838                    long time= util.toTime(TimeZoneConstants.UTC, years, months, days, hours, minutes, seconds, milliSeconds, 0);
839            
840                    if(isPlus)time-=offset;
841                    else time+=offset;
842                    return new DateTimeImpl(time,false);
843            }
844            return defaultValue;
845        }
846        
847        public static String toUSDate(Object o, TimeZone timeZone) throws PageException {
848            if(Decision.isUSDate(o)) return Caster.toString(o);
849            DateTime date = DateCaster.toDateAdvanced(o, timeZone);
850            return new railo.runtime.format.DateFormat(Locale.US).format(date,"mm/dd/yyyy");
851        }
852        
853        public static String toEuroDate(Object o, TimeZone timeZone) throws PageException {
854            if(Decision.isEuroDate(o)) return Caster.toString(o);
855            DateTime date = DateCaster.toDateAdvanced(o, timeZone);
856            return new railo.runtime.format.DateFormat(Locale.US).format(date,"dd.mm.yyyy");
857        }
858        
859        
860    }