001    package railo.commons.date;
002    
003    import java.util.Locale;
004    import java.util.TimeZone;
005    
006    import railo.commons.lang.SystemOut;
007    import railo.runtime.engine.ThreadLocalPageContext;
008    import railo.runtime.exp.ExpressionException;
009    import railo.runtime.type.dt.DateTime;
010    import railo.runtime.type.dt.DateTimeImpl;
011    
012    public abstract class DateTimeUtil {
013            
014        private static final double DAY_MILLIS = 86400000D;
015            private static final long CF_UNIX_OFFSET = 2209161600000L;
016    
017            public static final int SECOND = 0;
018            public static final int MINUTE = 1;
019            public static final int HOUR = 2;
020            public static final int DAY = 3;
021            public static final int YEAR = 10;
022            public static final int MONTH = 11;
023            public static final int WEEK = 12;
024            public static final int QUARTER = 20;
025            public static final int MILLISECOND =30;
026            
027            
028            
029            private static DateTimeUtil instance;
030    
031            public static DateTimeUtil getInstance(){
032                    if(instance==null)      {
033                            // try to load Joda Date TimeUtil
034                            try{
035                                    instance=new JREDateTimeUtil();
036                                    SystemOut.printDate("using JRE Date Library");
037                            }
038                            // when not available (jar) load Impl that is based on the JRE
039                            catch(Throwable t){
040                                    instance=new JREDateTimeUtil();
041                                    SystemOut.printDate("using JRE Date Library");
042                            }
043                    }
044                    return instance;
045            }
046    
047            public DateTime toDateTime(TimeZone tz,int year, int month, int day, int hour, int minute, int second, int milliSecond) throws DateTimeException {
048                    return new DateTimeImpl(toTime(tz,year, month, day, hour, minute, second,milliSecond),false);
049            }
050            
051            public DateTime toDateTime(TimeZone tz,int year, int month, int day, int hour, int minute, int second, int milliSecond, DateTime defaultValue) {
052                    long time = toTime(tz,year, month, day, hour, minute, second,milliSecond,Long.MIN_VALUE);
053                    if(time==Long.MIN_VALUE) return defaultValue;
054                    return new DateTimeImpl(time,false);
055            }       
056            
057            /**
058         * returns a date time instance by a number, the conversion from the double to 
059         * date is o the base of the CFML rules.
060         * @param days double value to convert to a number
061         * @return DateTime Instance
062         */
063        public DateTime toDateTime(double days) {
064            long utc=Math.round(days*DAY_MILLIS);
065            utc-=CF_UNIX_OFFSET;
066            utc-=getLocalTimeZoneOffset(utc);
067            return new DateTimeImpl(utc,false);
068        }
069            
070            
071            public long toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond,long defaultValue){
072                    tz=ThreadLocalPageContext.getTimeZone(tz);
073                    year=toYear(year);
074            
075            if(month<1)          return defaultValue;
076            if(month>12) return defaultValue;
077            if(day<1)            return defaultValue;
078            if(hour<0)           return defaultValue;
079            if(minute<0)         return defaultValue;
080            if(second<0)         return defaultValue;
081            if(milliSecond<0)    return defaultValue;
082            if(hour>24)  return defaultValue;
083            if(minute>59)        return defaultValue;
084            if(second>59)        return defaultValue;
085            
086            if(daysInMonth(year, month)<day) return defaultValue;
087            
088            return _toTime(tz, year, month, day, hour, minute, second, milliSecond);
089            }
090    
091            public long toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond) throws DateTimeException{
092                    tz=ThreadLocalPageContext.getTimeZone(tz);
093                    year=toYear(year);
094            
095            if(month<1)          throw new DateTimeException("month number ["+month+"] must be at least 1");
096            if(month>12) throw new DateTimeException("month number ["+month+"] can not be greater than 12");
097            if(day<1)            throw new DateTimeException("day number ["+day+"] must be at least 1");
098            if(hour<0)           throw new DateTimeException("hour number ["+hour+"] must be at least 0");
099            if(minute<0)         throw new DateTimeException("minute number ["+minute+"] must be at least 0");
100            if(second<0)         throw new DateTimeException("second number ["+second+"] must be at least 0");
101            if(milliSecond<0)throw new DateTimeException("milli second number ["+milliSecond+"] must be at least 0");
102            
103            if(hour>24)  throw new DateTimeException("hour number ["+hour+"] can not be greater than 24");
104            if(minute>59)        throw new DateTimeException("minute number ["+minute+"] can not be greater than 59");
105            if(second>59)        throw new DateTimeException("second number ["+second+"] can not be greater than 59");
106            
107            if(daysInMonth(year, month)<day) 
108                    throw new DateTimeException("day number ["+day+"] can not be greater than "+daysInMonth(year, month)+" when month is "+month+" and year "+year);
109            
110            return _toTime(tz, year, month, day, hour, minute, second, milliSecond);
111            }
112            
113            /**
114             * return how much days given month in given year has
115             * @param year
116             * @param month
117             * @return
118             */
119            public int daysInMonth(int year,int month){
120                    switch(month) {
121                    case 1:
122                    case 3:
123                    case 5:
124                    case 7:
125                    case 8:
126                    case 10:
127                    case 12:
128                            return 31;
129                    case 4:
130                    case 6:
131                    case 9:
132                        case 11:
133                            return 30;
134                    case 2:
135                            return isLeapYear(year)?29:28;
136            }
137                    return -1;
138            }
139            
140            /**
141             * translate 2 digit numbers to a year; for example 10 to 2010 or 50 to 1950
142             * @param year
143             * @return year matching number
144             */
145            public int toYear(int year) {
146                    if(year<100) {
147                if(year<30)year=year+=2000;
148                else year=year+=1900;
149            }
150                    return year;
151            }
152            
153            /**
154             * return if given is is a leap year or not
155             * @param year
156             * @return is leap year
157             */
158            public boolean isLeapYear(int year) {
159                    return ((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
160        }
161            
162            /**
163         * cast boolean value
164         * @param dateTime 
165         * @return boolean value
166         * @throws ExpressionException
167         */
168        public boolean toBooleanValue(DateTime dateTime) throws DateTimeException {
169            throw new DateTimeException("can't cast Date ["+dateTime.toGMTString()+"] to boolean value");
170        }
171        
172        public double toDoubleValue(DateTime dateTime) {
173            long utc = dateTime.getTime();
174            utc+=getLocalTimeZoneOffset     (utc);
175            utc+=CF_UNIX_OFFSET;
176            return utc/DAY_MILLIS;
177        }
178        
179        private static long getLocalTimeZoneOffset(long utc){
180            return ThreadLocalPageContext.getTimeZone().getOffset(utc);
181        }
182        
183    
184            public long getMilliSecondsAdMidnight(TimeZone timeZone, long time) {
185                    return time-getMilliSecondsInDay(timeZone, time);
186            }
187        
188        abstract long _toTime(TimeZone tz,int year,int month,int day,int hour,int minute,int second,int milliSecond);
189            
190            public abstract int getYear(TimeZone tz,railo.runtime.type.dt.DateTime dt);
191            
192            public abstract int getMonth(TimeZone tz,DateTime dt);
193            
194            public abstract int getDay(TimeZone tz,DateTime dt);
195    
196            public abstract int getHour(TimeZone tz,DateTime dt);
197            
198            public abstract int getMinute(TimeZone tz,DateTime dt);
199            
200            public abstract int getSecond(TimeZone tz,DateTime dt);
201            
202            public abstract int getMilliSecond(TimeZone tz,DateTime dt);
203    
204            public abstract long getMilliSecondsInDay(TimeZone tz, long time);
205            
206            public abstract int getDaysInMonth(TimeZone tz,DateTime dt);
207    
208            public abstract int getDayOfYear(Locale locale,TimeZone tz, DateTime dt);
209    
210            public abstract int getDayOfWeek(Locale locale,TimeZone tz, DateTime dt);
211    
212            public abstract int getWeekOfYear(Locale locale,TimeZone tz,DateTime dt);
213    
214            public abstract long getDiff(TimeZone tz, int datePart,DateTime left,DateTime right);
215    
216            public abstract String toString(DateTime dt, TimeZone tz);
217    
218    
219    }