001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019/**
020 * Implements the CFML Function datediff
021 */
022package lucee.runtime.functions.dateTime;
023
024import java.util.Calendar;
025import java.util.Locale;
026import java.util.TimeZone;
027
028import lucee.commons.date.JREDateTimeUtil;
029import lucee.runtime.PageContext;
030import lucee.runtime.exp.ExpressionException;
031import lucee.runtime.exp.FunctionException;
032import lucee.runtime.ext.function.Function;
033import lucee.runtime.op.Decision;
034import lucee.runtime.type.dt.DateTime;
035
036/**
037 * 
038 */
039public final class DateDiff implements Function {
040
041        //private static final int DATEPART_S = 0;
042        //private static final int DATEPART_N = 1;
043        //private static final int DATEPART_H = 2;
044        private static final int DATEPART_D = 3;
045        private static final int DATEPART_Y = DATEPART_D;
046        private static final int DATEPART_YYYY = 10;
047        private static final int DATEPART_M = 11;
048        private static final int DATEPART_W = 12;
049        private static final int DATEPART_WW = DATEPART_W;
050        private static final int DATEPART_Q = 20;
051        
052        //private static Calendar _cRight;
053        //private static Calendar _cLeft;
054
055
056        /**
057         * @param pc
058         * @param s
059         * @param date
060         * @param date1
061         * @return
062         * @throws ExpressionException
063         */
064        public synchronized static double call(PageContext pc , String datePart, DateTime left, DateTime right) throws ExpressionException      {
065                long msLeft = left.getTime();
066                long msRight = right.getTime();
067                TimeZone tz = pc.getTimeZone();
068                //if(true)return 0;
069                // Date Part
070                datePart=datePart.toLowerCase().trim();
071                int dp;
072                if("s".equals(datePart))                return diffSeconds(msLeft, msRight);
073                else if("n".equals(datePart))   return diffSeconds(msLeft, msRight)/60L;
074                else if("h".equals(datePart))   return diffSeconds(msLeft, msRight)/3600L;
075                else if("d".equals(datePart))   dp=DATEPART_D;
076                else if("y".equals(datePart))   dp=DATEPART_Y;
077                else if("yyyy".equals(datePart))dp=DATEPART_YYYY;
078                else if("m".equals(datePart))   dp=DATEPART_M;
079                else if("w".equals(datePart))   dp=DATEPART_W;
080                else if("ww".equals(datePart))  dp=DATEPART_WW;
081                else if("q".equals(datePart))   dp=DATEPART_Q;
082                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]");
083                
084                
085                
086                // dates
087                Calendar _cLeft = JREDateTimeUtil.getThreadCalendar(tz);
088                _cLeft.setTimeInMillis(msLeft);
089                
090                Calendar _cRight = JREDateTimeUtil.newInstance(tz,Locale.US);
091                _cRight.setTimeInMillis(msRight);
092                        
093                        
094                        if(msLeft>msRight) 
095                                return -_call(pc,dp, _cRight, msRight, _cLeft, msLeft);
096                        
097                        return _call(pc,dp, _cLeft, msLeft, _cRight, msRight);
098                //}
099        }
100        
101        public static long diffSeconds(long msLeft, long msRight) {
102                if(msLeft>msRight)
103                        return -(long)((msLeft-msRight)/1000D);
104                return (long)((msRight-msLeft)/1000D);
105        }
106        
107        /*private static long _call(int datepart, long msLeft, long msRight) throws ExpressionException {
108                
109                long msDiff = msRight-msLeft;
110                double diff = msDiff/1000D;
111                if(DATEPART_S==datepart)        {
112                        return (long) diff;
113                }
114                if(DATEPART_N==datepart)        {
115                        return (long)(diff/60D);
116                }
117                if(DATEPART_H==datepart)        {
118                        return (long)(diff/3600D);
119                }
120                return 0;
121        }*/
122        
123        private static long _call(PageContext pc , int datepart, Calendar cLeft, long msLeft, Calendar cRight, long msRight) throws ExpressionException {
124                
125                //long msDiff = msRight-msLeft;
126                //double diff = msDiff/1000D;
127                /*if(DATEPART_S==datepart)      {
128                        return (long) diff;
129                }
130                if(DATEPART_N==datepart)        {
131                        return (long)(diff/60D);
132                }
133                if(DATEPART_H==datepart)        {
134                        return (long)(diff/3600D);
135                }*/
136                
137                long dDiff = cRight.get(Calendar.DATE)-cLeft.get(Calendar.DATE);
138                long hDiff = cRight.get(Calendar.HOUR_OF_DAY)-cLeft.get(Calendar.HOUR_OF_DAY);
139                long nDiff = cRight.get(Calendar.MINUTE)-cLeft.get(Calendar.MINUTE);
140                long sDiff = cRight.get(Calendar.SECOND)-cLeft.get(Calendar.SECOND);
141                
142
143                if(DATEPART_D==datepart || DATEPART_W==datepart)        {
144
145                        int tmp=0;
146                        if(hDiff<0)  tmp=-1;
147                        else if(hDiff>0);
148                        else if(nDiff<0)     tmp=-1;
149                        else if(nDiff>0);
150                        else if(sDiff<0)     tmp=-1;
151                        else if(sDiff>0);
152                        long rst = dayDiff(cLeft, cRight)+tmp;
153                        if(DATEPART_W==datepart)rst/=7;
154                        return rst;
155                }
156                
157                long yDiff = cRight.get(Calendar.YEAR)-cLeft.get(Calendar.YEAR);
158                long mDiff = cRight.get(Calendar.MONTH)-cLeft.get(Calendar.MONTH);
159                if(DATEPART_YYYY==datepart)     {
160                        int tmp=0;
161                        if(mDiff<0)                  tmp=-1;
162                        else if(mDiff>0);
163                        else if(dDiff<0)     tmp=-1;
164                        else if(dDiff>0);
165                        else if(hDiff<0)     tmp=-1;
166                        else if(hDiff>0);
167                        else if(nDiff<0)     tmp=-1;
168                        else if(nDiff>0);
169                        else if(sDiff<0)     tmp=-1;
170                        else if(sDiff>0);
171                        return yDiff+tmp;
172                }
173                if(DATEPART_M==datepart || DATEPART_Q==datepart)        {
174
175                        int tmp=0;
176                        if(dDiff<0)          tmp=-1;
177                        else if(dDiff>0);
178                        else if(hDiff<0)     tmp=-1;
179                        else if(hDiff>0);
180                        else if(nDiff<0)     tmp=-1;
181                        else if(nDiff>0);
182                        else if(sDiff<0)     tmp=-1;
183                        else if(sDiff>0);
184                        long rst = mDiff+(yDiff*12)+tmp;
185                        if(DATEPART_Q==datepart)rst/=3;
186                        return rst;
187                }
188                if(DATEPART_D==datepart)        {
189
190                        long rst = dDiff;
191                        //if(DATEPART_Q==datepart)rst/=3;
192                        return rst;
193                }
194                
195                
196                throw new FunctionException(pc,"dateDiff",3,"datePart","invalid value, valid values has to be [q,s,n,h,d,m,y,yyyy,w,ww]");
197                
198        }
199        
200
201
202        private static long dayDiff(Calendar l, Calendar r) {
203                int lYear = l.get(Calendar.YEAR);
204                int rYear = r.get(Calendar.YEAR);
205                int lDayOfYear=l.get(Calendar.DAY_OF_YEAR);
206                int rDayOfYear=r.get(Calendar.DAY_OF_YEAR);
207
208                
209                // same year
210                if(lYear==rYear){
211                        return rDayOfYear-lDayOfYear;
212                }
213                
214                long diff=rDayOfYear;
215                diff-=lDayOfYear;
216                for(int year=lYear;year<rYear;year++){
217                        diff+=Decision.isLeapYear(year)?366L:365L;
218                }
219                return diff;
220        }
221
222}