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