001 package railo.runtime.format; 002 003 import java.util.Calendar; 004 import java.util.Date; 005 import java.util.Locale; 006 import java.util.TimeZone; 007 008 import railo.commons.date.JREDateTimeUtil; 009 import railo.commons.lang.StringUtil; 010 import railo.runtime.engine.ThreadLocalPageContext; 011 import railo.runtime.op.Caster; 012 013 public final class DateTimeFormat extends BaseFormat implements Format { 014 015 private final Calendar calendar; 016 017 /** 018 * constructor of the class 019 * @param locale 020 */ 021 public DateTimeFormat(Locale locale) { 022 super(locale); 023 calendar=JREDateTimeUtil.newInstance(locale); 024 } 025 026 027 /** 028 * formats a date to a cfml date format (short) 029 * @param date 030 * @return formated date 031 */ 032 public String format(Date date) { 033 return format(date,"medium"); 034 } 035 036 /** 037 * formats a date to a cfml date format 038 * @param date 039 * @param mask 040 * @return formated date as string 041 */ 042 public String format(Date date,String mask) { 043 return format(date,mask,null); 044 } 045 public String format(Date date,String mask, TimeZone tz) { 046 //DateUtil.setTimeZone(null,calendar,date); 047 calendar.setTimeZone(tz=ThreadLocalPageContext.getTimeZone(tz)); 048 calendar.setTime(date); 049 050 051 String lcMask=StringUtil.toLowerCase(mask); 052 if(lcMask.equals("short")) return getAsString(java.text.DateFormat.SHORT,tz); 053 else if(lcMask.equals("medium")) return getAsString(java.text.DateFormat.MEDIUM,tz); 054 else if(lcMask.equals("long")) return getAsString(java.text.DateFormat.LONG,tz); 055 else if(lcMask.equals("full")) return getAsString(java.text.DateFormat.FULL,tz); 056 057 int len=mask.length(); 058 int pos=0; 059 if(len==0) return ""; 060 061 StringBuffer formated=new StringBuffer(); 062 063 064 065 for(;pos<len;pos++) { 066 char c=mask.charAt(pos); 067 char next=(len>pos+1)?mask.charAt(pos+1):(char)0; 068 switch(c) { 069 070 // d: Day of month. Digits; no leading zero for single-digit days 071 // dd: Day of month. Digits; leading zero for single-digit days 072 // ddd: Day of week, abbreviation 073 // dddd: Day of week. Full name 074 case 'd': 075 case 'D': 076 char next2=(len>pos+2)?mask.charAt(pos+2):(char)0; 077 char next3=(len>pos+3)?mask.charAt(pos+3):(char)0; 078 079 int day=calendar.get(Calendar.DATE); 080 if(next=='d' || next=='D') { 081 if(next2=='d' || next2=='D') { 082 if(next3=='d' || next3=='D') { 083 formated.append(getDayOfWeekAsString(calendar.get(Calendar.DAY_OF_WEEK))); 084 pos+=3; 085 } 086 else { 087 formated.append(getDayOfWeekShortAsString(calendar.get(Calendar.DAY_OF_WEEK))); 088 pos+=2; 089 } 090 } 091 else { 092 formated.append(day<10?"0"+day:""+day); 093 pos++; 094 } 095 } 096 else { 097 formated.append(day); 098 } 099 break; 100 101 // m: Month. Digits; no leading zero for single-digit months 102 // mm: Month. Digits; leading zero for single-digit months 103 // mmm: Month. abbreviation (if appropriate) 104 // mmmm: Month. Full name 105 case 'm': 106 case 'M': 107 char next_2=(len>pos+2)?mask.charAt(pos+2):(char)0; 108 char next_3=(len>pos+3)?mask.charAt(pos+3):(char)0; 109 110 int month=calendar.get(Calendar.MONTH)+1; 111 if(next=='m' || next=='M') { 112 if(next_2=='m' || next_2=='M') { 113 if(next_3=='m' || next_3=='M') { 114 formated.append(getMonthAsString(month)); 115 pos+=3; 116 } 117 else { 118 formated.append(getMonthShortAsString(month)); 119 pos+=2; 120 } 121 } 122 else { 123 formated.append(month<10?"0"+month:""+month); 124 pos++; 125 } 126 } 127 else { 128 formated.append(month); 129 } 130 break; 131 132 // y: Year. Last two digits; no leading zero for years less than 10 133 // yy: Year. Last two digits; leading zero for years less than 10 134 // yyyy: Year. Four digits 135 case 'y': 136 case 'Y': 137 char next__2=(len>pos+2)?mask.charAt(pos+2):(char)0; 138 char next__3=(len>pos+3)?mask.charAt(pos+3):(char)0; 139 140 int year4=calendar.get(Calendar.YEAR); 141 int year2=year4%100; 142 if(next=='y' || next=='Y') { 143 if((next__2=='y' || next__2=='Y') && (next__3=='y' || next__3=='Y')) { 144 formated.append(year4); 145 pos+=3; 146 } 147 else { 148 formated.append(year2<10?"0"+year2:""+year2); 149 pos++; 150 } 151 } 152 else { 153 formated.append(year2); 154 } 155 break; 156 157 158 159 // h: Hours; no leading zero for single-digit hours (12-hour clock) 160 // hh: Hours; leading zero for single-digit hours. (12-hour clock) 161 case 'h': 162 int hour1=calendar.get(Calendar.HOUR_OF_DAY); 163 if(hour1==0)hour1=12; 164 if(hour1>12)hour1=hour1-12; 165 if(next=='h') { 166 formated.append(hour1<10?"0"+hour1:""+hour1); 167 pos++; 168 } 169 else { 170 formated.append(hour1); 171 } 172 break; 173 174 // H: Hours; no leading zero for single-digit hours (24-hour clock) 175 // HH: Hours; leading zero for single-digit hours (24-hour clock) 176 case 'H': 177 int hour2=calendar.get(Calendar.HOUR_OF_DAY); 178 if(next=='H') { 179 formated.append(hour2<10?"0"+hour2:""+hour2); 180 pos++; 181 } 182 else { 183 formated.append(hour2); 184 } 185 break; 186 187 // n: Minutes; no leading zero for single-digit minutes 188 // nn: Minutes; leading zero for single-digit minutes 189 case 'N': 190 case 'n': 191 int minute=calendar.get(Calendar.MINUTE); 192 if(next=='N' || next=='n') { 193 formated.append(minute<10?"0"+minute:""+minute); 194 pos++; 195 } 196 else { 197 formated.append(minute); 198 } 199 break; 200 201 // s: Seconds; no leading zero for single-digit seconds 202 // ss: Seconds; leading zero for single-digit seconds 203 case 's': 204 case 'S': 205 int second=calendar.get(Calendar.SECOND); 206 if(next=='S' || next=='s') { 207 formated.append(second<10?"0"+second:""+second); 208 pos++; 209 } 210 else { 211 formated.append(second); 212 } 213 break; 214 215 // l: Milliseconds 216 case 'l': 217 case 'L': 218 char nextnext=(len>pos+2)?mask.charAt(pos+2):(char)0; 219 220 String millis=Caster.toString(calendar.get(Calendar.MILLISECOND)); 221 if(next=='L' || next=='l') { 222 if(millis.length()==1)millis="0"+millis; 223 pos++; 224 } 225 if(nextnext=='L' || nextnext=='l') { 226 if(millis.length()==2)millis="0"+millis; 227 pos++; 228 } 229 formated.append(millis); 230 231 232 233 break; 234 235 // t: One-character time marker string, such as A or P. 236 // tt: Multiple-character time marker string, such as AM or PM 237 case 't': 238 case 'T': 239 boolean isAm=calendar.get(Calendar.HOUR_OF_DAY)<12; 240 if(next=='T' || next=='t') { 241 formated.append(isAm?"AM":"PM"); 242 pos++; 243 } 244 else { 245 formated.append(isAm?"A":"P"); 246 } 247 break; 248 case 'z': 249 case 'Z': 250 // count next z and jump to last z (max 6) 251 int start=pos; 252 while((pos+1)<len && Character.toLowerCase(mask.charAt(pos+1))=='z'){ 253 pos++; 254 if(pos-start>4)break; 255 } 256 if(pos-start>2)formated.append(tz.getDisplayName(getLocale())); 257 else formated.append(tz.getID()); 258 259 break; 260 261 262 263 // Otherwise 264 default: 265 formated.append(c); 266 } 267 } 268 return formated.toString(); 269 } 270 271 272 private String getAsString(int style, TimeZone tz) { 273 java.text.DateFormat df = java.text.DateFormat.getDateTimeInstance(style,style,getLocale()); 274 df.setTimeZone(tz); 275 return df.format(calendar.getTime()); 276 } 277 }