/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ /** * Implements the CFML Function datediff */ package lucee.runtime.functions.dateTime; import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; import lucee.commons.date.JREDateTimeUtil; import lucee.runtime.PageContext; import lucee.runtime.engine.ThreadLocalPageContext; import lucee.runtime.exp.ExpressionException; import lucee.runtime.exp.FunctionException; import lucee.runtime.exp.PageException; import lucee.runtime.ext.function.BIF; import lucee.runtime.op.Caster; import lucee.runtime.op.Decision; import lucee.runtime.type.dt.DateTime; /** * */ public final class DateDiff extends BIF { private static final long serialVersionUID = 4243793930337910884L; //private static final int DATEPART_S = 0; //private static final int DATEPART_N = 1; //private static final int DATEPART_H = 2; private static final int DATEPART_D = 3; private static final int DATEPART_Y = DATEPART_D; private static final int DATEPART_YYYY = 10; private static final int DATEPART_M = 11; private static final int DATEPART_W = 12; private static final int DATEPART_WW = DATEPART_W; private static final int DATEPART_Q = 20; /** * @param pc * @param s * @param date * @param date1 * @return * @throws ExpressionException */ public synchronized static double call(PageContext pc , String datePart, DateTime left, DateTime right) throws ExpressionException { long msLeft = left.getTime(); long msRight = right.getTime(); TimeZone tz =ThreadLocalPageContext.getTimeZone(pc); // Date Part datePart=datePart.toLowerCase().trim(); int dp; if("s".equals(datePart)) return diffSeconds(msLeft, msRight); else if("n".equals(datePart)) return diffSeconds(msLeft, msRight)/60L; else if("h".equals(datePart)) return diffSeconds(msLeft, msRight)/3600L; else if("d".equals(datePart)) dp=DATEPART_D; else if("y".equals(datePart)) dp=DATEPART_Y; else if("yyyy".equals(datePart))dp=DATEPART_YYYY; else if("m".equals(datePart)) dp=DATEPART_M; else if("w".equals(datePart)) dp=DATEPART_W; else if("ww".equals(datePart)) dp=DATEPART_WW; else if("q".equals(datePart)) dp=DATEPART_Q; 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]"); // dates Calendar _cLeft = JREDateTimeUtil.getThreadCalendar(tz); _cLeft.setTimeInMillis(msLeft); Calendar _cRight = JREDateTimeUtil.newInstance(tz,Locale.US); _cRight.setTimeInMillis(msRight); if(msLeft>msRight) return -_call(pc,dp, _cRight, msRight, _cLeft, msLeft); return _call(pc,dp, _cLeft, msLeft, _cRight, msRight); //} } public static long diffSeconds(long msLeft, long msRight) { if(msLeft>msRight) return -(long)((msLeft-msRight)/1000D); return (long)((msRight-msLeft)/1000D); } private static long _call(PageContext pc , int datepart, Calendar cLeft, long msLeft, Calendar cRight, long msRight) throws ExpressionException { long dDiff = cRight.get(Calendar.DATE)-cLeft.get(Calendar.DATE); long hDiff = cRight.get(Calendar.HOUR_OF_DAY)-cLeft.get(Calendar.HOUR_OF_DAY); long nDiff = cRight.get(Calendar.MINUTE)-cLeft.get(Calendar.MINUTE); long sDiff = cRight.get(Calendar.SECOND)-cLeft.get(Calendar.SECOND); if(DATEPART_D==datepart || DATEPART_W==datepart) { int tmp=0; if(hDiff<0) tmp=-1; else if(hDiff>0); else if(nDiff<0) tmp=-1; else if(nDiff>0); else if(sDiff<0) tmp=-1; else if(sDiff>0); long rst = dayDiff(cLeft, cRight)+tmp; if(DATEPART_W==datepart)rst/=7; return rst; } long yDiff = cRight.get(Calendar.YEAR)-cLeft.get(Calendar.YEAR); long mDiff = cRight.get(Calendar.MONTH)-cLeft.get(Calendar.MONTH); if(DATEPART_YYYY==datepart) { int tmp=0; if(mDiff<0) tmp=-1; else if(mDiff>0); else if(dDiff<0) tmp=-1; else if(dDiff>0); else if(hDiff<0) tmp=-1; else if(hDiff>0); else if(nDiff<0) tmp=-1; else if(nDiff>0); else if(sDiff<0) tmp=-1; else if(sDiff>0); return yDiff+tmp; } if(DATEPART_M==datepart || DATEPART_Q==datepart) { int tmp=0; if(dDiff<0 && isEndOfMonth(cRight)) dDiff=0; if(dDiff<0) tmp=-1; else if(dDiff>0); else if(hDiff<0) tmp=-1; else if(hDiff>0); else if(nDiff<0) tmp=-1; else if(nDiff>0); else if(sDiff<0) tmp=-1; else if(sDiff>0); long rst = mDiff+(yDiff*12)+tmp; if(DATEPART_Q==datepart)rst/=3; return rst; } if(DATEPART_D==datepart) { return dDiff; } throw new FunctionException(pc,"dateDiff",3,"datePart","invalid value, valid values has to be [q,s,n,h,d,m,y,yyyy,w,ww]"); } private static boolean isEndOfMonth(Calendar cal) { return cal.get(Calendar.DATE) == cal.getActualMaximum(Calendar.DATE); } private static long dayDiff(Calendar l, Calendar r) { int lYear = l.get(Calendar.YEAR); int rYear = r.get(Calendar.YEAR); int lDayOfYear=l.get(Calendar.DAY_OF_YEAR); int rDayOfYear=r.get(Calendar.DAY_OF_YEAR); // same year if(lYear==rYear){ return rDayOfYear-lDayOfYear; } long diff=rDayOfYear; diff-=lDayOfYear; for(int year=lYear;year<rYear;year++){ diff+=Decision.isLeapYear(year)?366L:365L; } return diff; } public Object invokeo(PageContext pc, Object[] args) throws PageException { // public synchronized static double call(PageContext pc , String datePart, DateTime left, DateTime right) throws ExpressionException { return null; } @Override public Object invoke(PageContext pc, Object[] args) throws PageException { if(args.length==3) return call(pc, Caster.toString(args[0]), Caster.toDateTime(args[1],null), Caster.toDateTime(args[2],null)); throw new FunctionException(pc,"DateDiff",3,3,args.length); } }