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 dateadd
021 */
022package lucee.runtime.functions.dateTime;
023
024import java.util.Calendar;
025import java.util.TimeZone;
026
027import lucee.commons.date.JREDateTimeUtil;
028import lucee.runtime.PageContext;
029import lucee.runtime.exp.ExpressionException;
030import lucee.runtime.ext.function.Function;
031import lucee.runtime.type.dt.DateTime;
032import lucee.runtime.type.dt.DateTimeImpl;
033
034public final class DateAdd implements Function {
035
036        private static final long serialVersionUID = -5827644560609841341L;
037
038        public static DateTime call(PageContext pc , String datepart, double number, DateTime date) throws ExpressionException {
039                return _call(pc,pc.getTimeZone(), datepart, number, date);
040        }
041        
042        public synchronized static DateTime _call(PageContext pc ,TimeZone tz, String datepart, double number, DateTime date) throws ExpressionException {
043                datepart=datepart.toLowerCase();
044                long l=(long)number;
045                int n=(int) l;
046                char first=datepart.length()==1?datepart.charAt(0):(char)0;
047
048                if(first=='l')                  return new DateTimeImpl(pc,date.getTime()+l,false);
049                else if(first=='s')     return new DateTimeImpl(pc,date.getTime()+(l*1000),false);
050                else if(first=='n')             return new DateTimeImpl(pc,date.getTime()+(l*60000),false);
051                else if(first=='h')             return new DateTimeImpl(pc,date.getTime()+(l*3600000),false);
052                
053                
054                Calendar c=JREDateTimeUtil.getThreadCalendar();
055                //if (c == null)c=JREDateTimeUtil.newInstance();
056        //synchronized (c) {
057                //c.clear();
058                c.setTimeZone(tz);
059                c.setTimeInMillis(date.getTime());
060                        
061                        if(datepart.equals("yyyy")) {
062                                c.set(Calendar.YEAR,c.get(Calendar.YEAR)+n);
063                        }
064                        else if(datepart.equals("ww")) c.add(Calendar.WEEK_OF_YEAR,n);
065                        else if(first=='q') c.add(Calendar.MONTH,(n*3));
066                        else if(first=='m') c.add(Calendar.MONTH,n);
067                        else if(first=='y') c.add(Calendar.DAY_OF_YEAR,n);
068                        else if(first=='d') c.add(Calendar.DATE,n);
069                        else if(first=='w') {
070                                int dow = c.get(Calendar.DAY_OF_WEEK);
071                    int offset;
072                    // -
073                    if(n < 0) {
074                        if(Calendar.SUNDAY==dow) offset=2;
075                        else offset=-(6-dow);
076                    } 
077                    // +
078                    else {
079                        if(Calendar.SATURDAY==dow) offset=-2;
080                        else offset=dow-2;
081                    }
082                    c.add(Calendar.DAY_OF_WEEK, -offset);
083                    
084                    if(dow==Calendar.SATURDAY || dow==Calendar.SUNDAY) {
085                        if(n>0) n--;
086                        else if(n<0) n++;
087                    }
088                    else n+=offset;
089                    c.add(Calendar.DAY_OF_WEEK, (n / 5) * 7 + n % 5);
090                    
091                        }
092                        
093                        else {
094                                throw new ExpressionException("invalid datepart identifier ["+datepart+"] for function dateAdd");
095                        }
096                        return new DateTimeImpl(pc,c.getTimeInMillis(),false);
097        //}
098        }
099}