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 **/
019package lucee.runtime.format;
020
021import java.text.DateFormat;
022import java.util.Calendar;
023import java.util.Date;
024import java.util.Locale;
025import java.util.TimeZone;
026
027import lucee.commons.date.JREDateTimeUtil;
028import lucee.commons.lang.StringUtil;
029import lucee.runtime.functions.dateTime.Beat;
030import lucee.runtime.op.Caster;
031import lucee.runtime.type.dt.DateTime;
032import lucee.runtime.type.dt.DateTimeImpl;
033
034public final class TimeFormat extends BaseFormat implements Format {
035        
036        
037        
038        /**
039         * constructor of the class
040         * @param locale
041         */
042        public TimeFormat(Locale locale) {
043                super(locale);
044        }
045        
046
047        /**
048         * formats a date to a cfml date format (short)
049         * @param date
050         * @return formated date
051         */
052        public String format(Date date) {
053                return format(date,"short");
054        }
055        
056        /**
057         * formats a date to a cfml date format
058         * @param date
059         * @param mask
060         * @return formated date
061         */
062        public String format(Date date,String mask) {
063                DateTime dt=(date instanceof DateTime)?(DateTime)date:new DateTimeImpl(date.getTime(),false);
064                return format(dt,mask,null);
065        }
066        
067
068        public String format(DateTime date,String mask, TimeZone tz) {
069                return format(date.getTime(), mask, tz);
070        }
071        public String format(long time,String mask, TimeZone tz) {
072                Calendar calendar = JREDateTimeUtil.getThreadCalendar(getLocale(),tz);
073                calendar.setTimeInMillis(time);
074
075                String lcMask=StringUtil.toLowerCase(mask);
076                if(lcMask.equals("short"))                      return getAsString(calendar,DateFormat.SHORT,tz);
077                else if(lcMask.equals("medium"))        return getAsString(calendar,DateFormat.MEDIUM,tz);
078                else if(lcMask.equals("long"))          return getAsString(calendar,DateFormat.LONG,tz);
079                else if(lcMask.equals("full"))          return getAsString(calendar,DateFormat.FULL,tz);
080                else if(lcMask.equals("beat"))  {
081                        return Caster.toString(Beat.format(time)); 
082                }
083                
084                int len=mask.length();
085                int pos=0;
086                if(len==0) return "";
087                
088                StringBuilder formated=new StringBuilder();
089                
090                
091                
092                for(;pos<len;pos++) {
093                        char c=mask.charAt(pos);
094                        char next=(len>pos+1)?mask.charAt(pos+1):(char)0;
095                        
096                        switch(c) {
097
098                        // h: Hours; no leading zero for single-digit hours (12-hour clock) 
099                        // hh: Hours; leading zero for single-digit hours. (12-hour clock) 
100                                case 'h':
101                                        int hour1=calendar.get(Calendar.HOUR_OF_DAY);
102                                        if(hour1==0)hour1=12;
103                                        if(hour1>12)hour1=hour1-12;
104                                        if(next=='h') {
105                                                formated.append(hour1<10?"0"+hour1:""+hour1);
106                                                pos++;
107                                        }
108                                        else {
109                                                formated.append(hour1);
110                                        }                                       
111                                break;
112
113                        // H: Hours; no leading zero for single-digit hours (24-hour clock) 
114                        // HH: Hours; leading zero for single-digit hours (24-hour clock) 
115                                case 'H':
116                                        int hour2=calendar.get(Calendar.HOUR_OF_DAY);
117                                        if(next=='H') {
118                                                formated.append(hour2<10?"0"+hour2:""+hour2);
119                                                pos++;
120                                        }
121                                        else {
122                                                formated.append(hour2);
123                                        }                                       
124                                break;
125
126                        // m: Minutes; no leading zero for single-digit minutes 
127                        // mm: Minutes; leading zero for single-digit minutes 
128                                case 'M':
129                                case 'm':
130                                        int minute=calendar.get(Calendar.MINUTE);
131                                        if(next=='M' || next=='m') {
132                                                formated.append(minute<10?"0"+minute:""+minute);
133                                                pos++;
134                                        }
135                                        else {
136                                                formated.append(minute);
137                                        }                                       
138                                break;
139
140                        // s: Seconds; no leading zero for single-digit seconds 
141                        // ss: Seconds; leading zero for single-digit seconds 
142                                case 's':
143                                case 'S':
144                                        int second=calendar.get(Calendar.SECOND);
145                                        if(next=='S' || next=='s') {
146                                                formated.append(second<10?"0"+second:""+second);
147                                                pos++;
148                                        }
149                                        else {
150                                                formated.append(second);
151                                        }                                       
152                                break;
153
154                        // l: Milliseconds 
155                                case 'l':
156                                case 'L':
157                                        char nextnext=(len>pos+2)?mask.charAt(pos+2):(char)0;
158
159                                        String millis=Caster.toString(calendar.get(Calendar.MILLISECOND));
160                                        if(next=='L' || next=='l') {
161                                                if(millis.length()==1)millis="0"+millis;
162                                                pos++;
163                                        }
164                                        if(nextnext=='L' || nextnext=='l') {
165                                                if(millis.length()==2)millis="0"+millis;
166                                                pos++;
167                                        }
168                                        formated.append(millis);        
169                                        
170                                        
171                                        
172                                break;
173
174                        // t: One-character time marker string, such as A or P. 
175                        // tt: Multiple-character time marker string, such as AM or PM 
176                                case 't':
177                                case 'T':
178                                        boolean isAm=calendar.get(Calendar.HOUR_OF_DAY)<12;
179                                        if(next=='T' || next=='t') {
180                                                formated.append(isAm?"AM":"PM");
181                                                pos++;
182                                        }
183                                        else {
184                                                formated.append(isAm?"A":"P");
185                                        }                                       
186                                break;
187                                case 'z':
188                                case 'Z':
189                                        // count next z and jump to last z (max 6)
190                                        int start=pos;
191                                        while((pos+1)<len && Character.toLowerCase(mask.charAt(pos+1))=='z'){
192                                                pos++;
193                                                if(pos-start>4)break;
194                                        }
195                                        if(pos-start>2)formated.append(tz.getDisplayName(getLocale()));      
196                                        else formated.append(tz.getID());       
197                                        
198                                break;
199                                
200                        // Otherwise
201                                default:
202                                        formated.append(c);
203                        }
204                }
205                return formated.toString();
206        }
207
208        private String getAsString(Calendar c, int style,TimeZone tz) {
209                DateFormat df = DateFormat.getTimeInstance(style,getLocale());
210                df.setTimeZone(tz);
211                return df.format(c.getTime());  
212        }
213
214}