1 31 package org.jruby.util; 32 33 import java.text.DateFormat ; 34 import java.text.DateFormatSymbols ; 35 import java.text.FieldPosition ; 36 import java.text.ParsePosition ; 37 import java.util.Calendar ; 38 import java.util.Date ; 39 import java.util.Iterator ; 40 import java.util.LinkedList ; 41 import java.util.List ; 42 import java.util.Locale ; 43 import java.util.TimeZone ; 44 45 public class RubyDateFormat extends DateFormat { 46 private static final long serialVersionUID = -250429218019023997L; 47 48 private List compiledPattern; 49 50 private DateFormatSymbols formatSymbols; 51 52 private static final int FORMAT_STRING = 0; 53 private static final int FORMAT_WEEK_LONG = 1; 54 private static final int FORMAT_WEEK_SHORT = 2; 55 private static final int FORMAT_MONTH_LONG = 3; 56 private static final int FORMAT_MONTH_SHORT = 4; 57 private static final int FORMAT_DAY = 5; 58 private static final int FORMAT_HOUR = 6; 59 private static final int FORMAT_HOUR_M = 7; 60 private static final int FORMAT_DAY_YEAR = 8; 61 private static final int FORMAT_MINUTES = 9; 62 private static final int FORMAT_MONTH = 10; 63 private static final int FORMAT_MERIDIAN = 11; 64 private static final int FORMAT_SECONDS = 12; 65 private static final int FORMAT_WEEK_YEAR_S = 13; 66 private static final int FORMAT_WEEK_YEAR_M = 14; 67 private static final int FORMAT_DAY_WEEK = 15; 68 private static final int FORMAT_YEAR_LONG = 16; 69 private static final int FORMAT_YEAR_SHORT = 17; 70 private static final int FORMAT_ZONE_OFF = 18; 71 private static final int FORMAT_ZONE_ID = 19; 72 73 private static class Token { 74 private int format; 75 private Object data; 76 77 public Token(int format) { 78 this(format, null); 79 } 80 81 public Token(int format, Object data) { 82 this.format = format; 83 this.data = data; 84 } 85 86 90 public Object getData() { 91 return data; 92 } 93 94 98 public int getFormat() { 99 return format; 100 } 101 } 102 103 106 public RubyDateFormat() { 107 this("", new DateFormatSymbols ()); 108 } 109 110 public RubyDateFormat(String pattern, Locale aLocale) { 111 this(pattern, new DateFormatSymbols (aLocale)); 112 } 113 114 public RubyDateFormat(String pattern, DateFormatSymbols formatSymbols) { 115 super(); 116 117 this.formatSymbols = formatSymbols; 118 applyPattern(pattern); 119 } 120 121 public void applyPattern(String pattern) { 122 compilePattern(pattern); 123 } 124 125 private void compilePattern(String pattern) { 126 compiledPattern = new LinkedList (); 127 128 int len = pattern.length(); 129 for (int i = 0; i < len;) { 130 if (pattern.charAt(i) == '%') { 131 i++; 132 switch (pattern.charAt(i)) { 133 case 'A' : 134 compiledPattern.add(new Token(FORMAT_WEEK_LONG)); 135 break; 136 case 'a' : 137 compiledPattern.add(new Token(FORMAT_WEEK_SHORT)); 138 break; 139 case 'B' : 140 compiledPattern.add(new Token(FORMAT_MONTH_LONG)); 141 break; 142 case 'b' : 143 compiledPattern.add(new Token(FORMAT_MONTH_SHORT)); 144 break; 145 case 'c' : 146 compiledPattern.add(new Token(FORMAT_WEEK_SHORT)); 147 compiledPattern.add(new Token(FORMAT_STRING, " ")); 148 compiledPattern.add(new Token(FORMAT_MONTH_SHORT)); 149 compiledPattern.add(new Token(FORMAT_STRING, " ")); 150 compiledPattern.add(new Token(FORMAT_DAY)); 151 compiledPattern.add(new Token(FORMAT_STRING, " ")); 152 compiledPattern.add(new Token(FORMAT_HOUR)); 153 compiledPattern.add(new Token(FORMAT_STRING, ":")); 154 compiledPattern.add(new Token(FORMAT_MINUTES)); 155 compiledPattern.add(new Token(FORMAT_STRING, ":")); 156 compiledPattern.add(new Token(FORMAT_SECONDS)); 157 compiledPattern.add(new Token(FORMAT_STRING, " ")); 158 compiledPattern.add(new Token(FORMAT_YEAR_LONG)); 159 break; 160 case 'd': 161 compiledPattern.add(new Token(FORMAT_DAY)); 162 break; 163 case 'H': 164 compiledPattern.add(new Token(FORMAT_HOUR)); 165 break; 166 case 'I': 167 compiledPattern.add(new Token(FORMAT_HOUR_M)); 168 break; 169 case 'j': 170 compiledPattern.add(new Token(FORMAT_DAY_YEAR)); 171 break; 172 case 'M': 173 compiledPattern.add(new Token(FORMAT_MINUTES)); 174 break; 175 case 'm': 176 compiledPattern.add(new Token(FORMAT_MONTH)); 177 break; 178 case 'p': 179 compiledPattern.add(new Token(FORMAT_MERIDIAN)); 180 break; 181 case 'S': 182 compiledPattern.add(new Token(FORMAT_SECONDS)); 183 break; 184 case 'U': 185 compiledPattern.add(new Token(FORMAT_WEEK_YEAR_S)); 186 break; 187 case 'W': 188 compiledPattern.add(new Token(FORMAT_WEEK_YEAR_M)); 189 break; 190 case 'w': 191 compiledPattern.add(new Token(FORMAT_DAY_WEEK)); 192 break; 193 case 'X': 194 compiledPattern.add(new Token(FORMAT_HOUR)); 195 compiledPattern.add(new Token(FORMAT_STRING, ":")); 196 compiledPattern.add(new Token(FORMAT_MINUTES)); 197 compiledPattern.add(new Token(FORMAT_STRING, ":")); 198 compiledPattern.add(new Token(FORMAT_SECONDS)); 199 break; 200 case 'x': 201 compiledPattern.add(new Token(FORMAT_MONTH)); 202 compiledPattern.add(new Token(FORMAT_STRING, "/")); 203 compiledPattern.add(new Token(FORMAT_DAY)); 204 compiledPattern.add(new Token(FORMAT_STRING, "/")); 205 compiledPattern.add(new Token(FORMAT_YEAR_SHORT)); 206 break; 207 case 'Y': 208 compiledPattern.add(new Token(FORMAT_YEAR_LONG)); 209 break; 210 case 'y': 211 compiledPattern.add(new Token(FORMAT_YEAR_SHORT)); 212 break; 213 case 'Z': 214 compiledPattern.add(new Token(FORMAT_ZONE_ID)); 215 break; 216 case 'z': 217 compiledPattern.add(new Token(FORMAT_ZONE_OFF)); 218 break; 219 case '%': 220 compiledPattern.add(new Token(FORMAT_STRING, "%")); 221 break; 222 default: 223 compiledPattern.add(new Token(FORMAT_STRING, "%" + pattern.charAt(i))); 224 } 225 i++; 226 } else { 227 StringBuffer sb = new StringBuffer (); 228 for (;i < len && pattern.charAt(i) != '%'; i++) { 229 sb.append(pattern.charAt(i)); 230 } 231 compiledPattern.add(new Token(FORMAT_STRING, sb.toString())); 232 } 233 } 234 } 235 236 239 public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { 240 calendar.setTime(date); 241 calendar.setMinimalDaysInFirstWeek(1); 242 243 Iterator iter = compiledPattern.iterator(); 244 while (iter.hasNext()) { 245 Token token = (Token) iter.next(); 246 247 switch (token.getFormat()) { 248 case FORMAT_STRING: 249 toAppendTo.append(token.getData()); 250 break; 251 case FORMAT_WEEK_LONG: 252 toAppendTo.append(formatSymbols.getWeekdays()[calendar.get(Calendar.DAY_OF_WEEK)]); 253 break; 254 case FORMAT_WEEK_SHORT: 255 toAppendTo.append(formatSymbols.getShortWeekdays()[calendar.get(Calendar.DAY_OF_WEEK)]); 256 break; 257 case FORMAT_MONTH_LONG: 258 toAppendTo.append(formatSymbols.getMonths()[calendar.get(Calendar.MONTH)]); 259 break; 260 case FORMAT_MONTH_SHORT: 261 toAppendTo.append(formatSymbols.getShortMonths()[calendar.get(Calendar.MONTH)]); 262 break; 263 case FORMAT_DAY: 264 int value = calendar.get(Calendar.DAY_OF_MONTH); 265 if (value < 10) { 266 toAppendTo.append('0'); 267 } 268 toAppendTo.append(value); 269 break; 270 case FORMAT_HOUR: 271 value = calendar.get(Calendar.HOUR_OF_DAY); 272 if (value < 10) { 273 toAppendTo.append('0'); 274 } 275 toAppendTo.append(value); 276 break; 277 case FORMAT_HOUR_M: 278 value = calendar.get(Calendar.HOUR); 279 if (value < 10) { 280 toAppendTo.append('0'); 281 } 282 toAppendTo.append(value); 283 break; 284 case FORMAT_DAY_YEAR: 285 value = calendar.get(Calendar.DAY_OF_YEAR); 286 if (value < 10) { 287 toAppendTo.append("00"); 288 } else if (value < 100) { 289 toAppendTo.append('0'); 290 } 291 toAppendTo.append(value); 292 break; 293 case FORMAT_MINUTES: 294 value = calendar.get(Calendar.MINUTE); 295 if (value < 10) { 296 toAppendTo.append('0'); 297 } 298 toAppendTo.append(value); 299 break; 300 case FORMAT_MONTH: 301 value = calendar.get(Calendar.MONTH) + 1; 302 if (value < 10) { 303 toAppendTo.append('0'); 304 } 305 toAppendTo.append(value); 306 break; 307 case FORMAT_MERIDIAN: 308 if (calendar.get(Calendar.AM_PM) == Calendar.AM) { 309 toAppendTo.append("AM"); 310 } else { 311 toAppendTo.append("PM"); 312 } 313 break; 314 case FORMAT_SECONDS: 315 value = calendar.get(Calendar.SECOND); 316 if (value < 10) { 317 toAppendTo.append('0'); 318 } 319 toAppendTo.append(value); 320 break; 321 case FORMAT_WEEK_YEAR_M: 322 formatWeekYear(Calendar.MONDAY, toAppendTo); 323 break; 324 case FORMAT_WEEK_YEAR_S: 326 formatWeekYear(Calendar.SUNDAY, toAppendTo); 327 break; 328 case FORMAT_DAY_WEEK: 329 value = calendar.get(Calendar.DAY_OF_WEEK) - 1; 330 toAppendTo.append(value); 331 break; 332 case FORMAT_YEAR_LONG: 333 value = calendar.get(Calendar.YEAR); 334 if (value < 10) { 335 toAppendTo.append("000"); 336 } else if (value < 100) { 337 toAppendTo.append("00"); 338 } else if (value < 1000) { 339 toAppendTo.append('0'); 340 } 341 toAppendTo.append(value); 342 break; 343 case FORMAT_YEAR_SHORT: 344 value = calendar.get(Calendar.YEAR) % 100; 345 if (value < 10) { 346 toAppendTo.append('0'); 347 } 348 toAppendTo.append(value); 349 break; 350 case FORMAT_ZONE_OFF: 351 value = calendar.getTimeZone().getOffset(calendar.getTimeInMillis()); 352 if (value <= 0) { 353 toAppendTo.append('+'); 354 } else { 355 toAppendTo.append('-'); 356 } 357 value = Math.abs(value); 358 if (value / 3600000 < 10) { 359 toAppendTo.append('0'); 360 } 361 toAppendTo.append(value / 3600000); 362 value = value % 3600000 / 60000; 363 if (value < 10) { 364 toAppendTo.append('0'); 365 } 366 toAppendTo.append(value); 367 break; 368 case FORMAT_ZONE_ID: 369 toAppendTo.append(calendar.getTimeZone().getDisplayName(calendar.get(Calendar.DST_OFFSET) != 0, TimeZone.SHORT)); 370 break; 371 } 372 } 373 374 return toAppendTo; 375 } 376 377 private void formatWeekYear(int firstDayOfWeek, StringBuffer toAppendTo) { 378 calendar.setFirstDayOfWeek(firstDayOfWeek); 379 int value = calendar.get(Calendar.WEEK_OF_YEAR); 380 if (calendar.get(Calendar.DAY_OF_WEEK) != firstDayOfWeek) { 381 value--; 382 } 383 if (value < 10) { 384 toAppendTo.append('0'); 385 } 386 toAppendTo.append(value); 387 calendar.setFirstDayOfWeek(Calendar.SUNDAY); 388 } 389 390 393 public Date parse(String source, ParsePosition pos) { 394 throw new UnsupportedOperationException (); 395 } 396 } 397 | Popular Tags |