001    /**
002     * Implements the CFML Function datediff
003     */
004    package railo.runtime.functions.dateTime;
005    
006    import java.util.Calendar;
007    import java.util.TimeZone;
008    
009    import railo.commons.date.JREDateTimeUtil;
010    import railo.runtime.PageContext;
011    import railo.runtime.exp.ExpressionException;
012    import railo.runtime.exp.FunctionException;
013    import railo.runtime.ext.function.Function;
014    import railo.runtime.op.Decision;
015    import railo.runtime.type.dt.DateTime;
016    
017    /**
018     * 
019     */
020    public final class DateDiff implements Function {
021    
022            //private static final int DATEPART_S = 0;
023            //private static final int DATEPART_N = 1;
024            //private static final int DATEPART_H = 2;
025            private static final int DATEPART_D = 3;
026            private static final int DATEPART_Y = DATEPART_D;
027            private static final int DATEPART_YYYY = 10;
028            private static final int DATEPART_M = 11;
029            private static final int DATEPART_W = 12;
030            private static final int DATEPART_WW = DATEPART_W;
031            private static final int DATEPART_Q = 20;
032            
033            private static Calendar _cRight;
034            private static Calendar _cLeft;
035    
036    
037            /**
038             * @param pc
039             * @param s
040             * @param date
041             * @param date1
042             * @return
043             * @throws ExpressionException
044             */
045            public synchronized static double call(PageContext pc , String datePart, DateTime left, DateTime right) throws ExpressionException      {
046                    long msLeft = left.getTime();
047                    long msRight = right.getTime();
048                    TimeZone tz = pc.getTimeZone();
049                    //if(true)return 0;
050                    // Date Part
051                    datePart=datePart.toLowerCase().trim();
052                    int dp;
053                    if("s".equals(datePart))                return diffSeconds(msLeft, msRight);
054                    else if("n".equals(datePart))   return diffSeconds(msLeft, msRight)/60L;
055                    else if("h".equals(datePart))   return diffSeconds(msLeft, msRight)/3600L;
056                    else if("d".equals(datePart))   dp=DATEPART_D;
057                    else if("y".equals(datePart))   dp=DATEPART_Y;
058                    else if("yyyy".equals(datePart))dp=DATEPART_YYYY;
059                    else if("m".equals(datePart))   dp=DATEPART_M;
060                    else if("w".equals(datePart))   dp=DATEPART_W;
061                    else if("ww".equals(datePart))  dp=DATEPART_WW;
062                    else if("q".equals(datePart))   dp=DATEPART_Q;
063                    else throw new FunctionException(pc,"dateDiff",3,"datePart","invalid value ["+datePart+"], valid values has to be [q,s,n,h,d,m,y,yyyy,w,ww]");
064                    
065                    
066                    
067                    // dates
068                    if(_cLeft==null) _cLeft = JREDateTimeUtil.newInstance(tz);
069                    //synchronized(_cLeft){
070                            _cLeft.clear();
071                            _cLeft.setTimeZone(tz);
072                            _cLeft.setTimeInMillis(msLeft);
073                            //long msLeft = _cLeft.getTimeInMillis();
074                            
075                            if(_cRight==null) _cRight = JREDateTimeUtil.newInstance(tz);
076                            else {
077                                    _cRight.clear();
078                                    _cRight.setTimeZone(tz);
079                            }
080                            _cRight.setTimeInMillis(msRight);
081                            //long msRight = _cRight.getTimeInMillis();
082                            
083                            
084                            if(msLeft>msRight) 
085                                    return -_call(pc,dp, _cRight, msRight, _cLeft, msLeft);
086                            
087                            return _call(pc,dp, _cLeft, msLeft, _cRight, msRight);
088                    //}
089            }
090            
091            public static long diffSeconds(long msLeft, long msRight) {
092                    if(msLeft>msRight)
093                            return -(long)((msLeft-msRight)/1000D);
094                    return (long)((msRight-msLeft)/1000D);
095            }
096            
097            /*private static long _call(int datepart, long msLeft, long msRight) throws ExpressionException {
098                    
099                    long msDiff = msRight-msLeft;
100                    double diff = msDiff/1000D;
101                    if(DATEPART_S==datepart)        {
102                            return (long) diff;
103                    }
104                    if(DATEPART_N==datepart)        {
105                            return (long)(diff/60D);
106                    }
107                    if(DATEPART_H==datepart)        {
108                            return (long)(diff/3600D);
109                    }
110                    return 0;
111            }*/
112            
113            private static long _call(PageContext pc , int datepart, Calendar cLeft, long msLeft, Calendar cRight, long msRight) throws ExpressionException {
114                    
115                    //long msDiff = msRight-msLeft;
116                    //double diff = msDiff/1000D;
117                    /*if(DATEPART_S==datepart)      {
118                            return (long) diff;
119                    }
120                    if(DATEPART_N==datepart)        {
121                            return (long)(diff/60D);
122                    }
123                    if(DATEPART_H==datepart)        {
124                            return (long)(diff/3600D);
125                    }*/
126                    
127                    long dDiff = cRight.get(Calendar.DATE)-cLeft.get(Calendar.DATE);
128                    long hDiff = cRight.get(Calendar.HOUR_OF_DAY)-cLeft.get(Calendar.HOUR_OF_DAY);
129                    long nDiff = cRight.get(Calendar.MINUTE)-cLeft.get(Calendar.MINUTE);
130                    long sDiff = cRight.get(Calendar.SECOND)-cLeft.get(Calendar.SECOND);
131                    
132    
133                    if(DATEPART_D==datepart || DATEPART_W==datepart)        {
134    
135                            int tmp=0;
136                            if(hDiff<0)  tmp=-1;
137                            else if(hDiff>0);
138                            else if(nDiff<0)     tmp=-1;
139                            else if(nDiff>0);
140                            else if(sDiff<0)     tmp=-1;
141                            else if(sDiff>0);
142                            long rst = dayDiff(cLeft, cRight)+tmp;
143                            if(DATEPART_W==datepart)rst/=7;
144                            return rst;
145                    }
146                    
147                    long yDiff = cRight.get(Calendar.YEAR)-cLeft.get(Calendar.YEAR);
148                    long mDiff = cRight.get(Calendar.MONTH)-cLeft.get(Calendar.MONTH);
149                    if(DATEPART_YYYY==datepart)     {
150                            int tmp=0;
151                            if(mDiff<0)                  tmp=-1;
152                            else if(mDiff>0);
153                            else if(dDiff<0)     tmp=-1;
154                            else if(dDiff>0);
155                            else if(hDiff<0)     tmp=-1;
156                            else if(hDiff>0);
157                            else if(nDiff<0)     tmp=-1;
158                            else if(nDiff>0);
159                            else if(sDiff<0)     tmp=-1;
160                            else if(sDiff>0);
161                            return yDiff+tmp;
162                    }
163                    if(DATEPART_M==datepart || DATEPART_Q==datepart)        {
164    
165                            int tmp=0;
166                            if(dDiff<0)          tmp=-1;
167                            else if(dDiff>0);
168                            else if(hDiff<0)     tmp=-1;
169                            else if(hDiff>0);
170                            else if(nDiff<0)     tmp=-1;
171                            else if(nDiff>0);
172                            else if(sDiff<0)     tmp=-1;
173                            else if(sDiff>0);
174                            long rst = mDiff+(yDiff*12)+tmp;
175                            if(DATEPART_Q==datepart)rst/=3;
176                            return rst;
177                    }
178                    if(DATEPART_D==datepart)        {
179    
180                            long rst = dDiff;
181                            //if(DATEPART_Q==datepart)rst/=3;
182                            return rst;
183                    }
184                    
185                    
186                    throw new FunctionException(pc,"dateDiff",3,"datePart","invalid value, valid values has to be [q,s,n,h,d,m,y,yyyy,w,ww]");
187                    
188            }
189            
190    
191    
192            private static long dayDiff(Calendar l, Calendar r) {
193                    int lYear = l.get(Calendar.YEAR);
194                    int rYear = r.get(Calendar.YEAR);
195                    int lDayOfYear=l.get(Calendar.DAY_OF_YEAR);
196                    int rDayOfYear=r.get(Calendar.DAY_OF_YEAR);
197    
198                    
199                    // same year
200                    if(lYear==rYear){
201                            return rDayOfYear-lDayOfYear;
202                    }
203                    
204                    long diff=rDayOfYear;
205                    diff-=lDayOfYear;
206                    for(int year=lYear;year<rYear;year++){
207                            diff+=Decision.isLeapYear(year)?366L:365L;
208                    }
209                    return diff;
210            }
211    
212    }