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