001 package railo.commons.i18n; 002 003 import java.text.DateFormat; 004 import java.text.SimpleDateFormat; 005 import java.util.ArrayList; 006 import java.util.List; 007 import java.util.Locale; 008 import java.util.Map; 009 import java.util.TimeZone; 010 011 import org.apache.commons.collections.map.ReferenceMap; 012 013 import railo.commons.date.TimeZoneConstants; 014 import railo.commons.io.IOUtil; 015 import railo.commons.io.res.Resource; 016 import railo.commons.lang.StringUtil; 017 import railo.runtime.config.Config; 018 import railo.runtime.engine.ThreadLocalPageContext; 019 020 public class FormatUtil { 021 022 public static final short FORMAT_TYPE_DATE=1; 023 public static final short FORMAT_TYPE_TIME=2; 024 public static final short FORMAT_TYPE_DATE_TIME=3; 025 public static final short FORMAT_TYPE_DATE_ALL=4; 026 027 private final static Map<String,DateFormat[]> formats=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT); 028 029 public static DateFormat[] getDateTimeFormats(Locale locale,TimeZone tz,boolean lenient) { 030 031 String id="dt-"+locale.hashCode()+"-"+tz.getID()+"-"+lenient; 032 DateFormat[] df=formats.get(id); 033 if(df==null) { 034 List<DateFormat> list=new ArrayList<DateFormat>(); 035 list.add(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL,locale)); 036 list.add(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.LONG,locale)); 037 list.add(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.MEDIUM,locale)); 038 list.add(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.SHORT,locale)); 039 040 list.add(DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.FULL,locale)); 041 list.add(DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG,locale)); 042 list.add(DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.MEDIUM,locale)); 043 list.add(DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.SHORT,locale)); 044 045 list.add(DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.FULL,locale)); 046 list.add(DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.LONG,locale)); 047 list.add(DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.MEDIUM,locale)); 048 list.add(DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.SHORT,locale)); 049 050 list.add(DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.FULL,locale)); 051 list.add(DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.LONG,locale)); 052 list.add(DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.MEDIUM,locale)); 053 list.add(DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT,locale)); 054 add24(list, locale); 055 addCustom(list, locale, FORMAT_TYPE_DATE_TIME); 056 df=list.toArray(new DateFormat[list.size()]); 057 058 for(int i=0;i<df.length;i++){ 059 df[i].setLenient(lenient); 060 df[i].setTimeZone(tz); 061 } 062 063 formats.put(id, df); 064 } 065 066 return df; 067 } 068 069 070 public static DateFormat[] getDateFormats(Locale locale,TimeZone tz,boolean lenient) { 071 String id="d-"+locale.hashCode()+"-"+tz.getID()+"-"+lenient; 072 DateFormat[] df= formats.get(id); 073 if(df==null) { 074 List<DateFormat> list=new ArrayList<DateFormat>(); 075 list.add(DateFormat.getDateInstance(DateFormat.FULL,locale)); 076 list.add(DateFormat.getDateInstance(DateFormat.LONG,locale)); 077 list.add(DateFormat.getDateInstance(DateFormat.MEDIUM,locale)); 078 list.add(DateFormat.getDateInstance(DateFormat.SHORT,locale)); 079 addCustom(list, locale, FORMAT_TYPE_DATE); 080 df=list.toArray(new DateFormat[list.size()]); 081 082 for(int i=0;i<df.length;i++){ 083 df[i].setLenient(lenient); 084 df[i].setTimeZone(tz); 085 } 086 formats.put(id, df); 087 } 088 return df; 089 } 090 091 public static DateFormat[] getTimeFormats(Locale locale,TimeZone tz,boolean lenient) { 092 String id="t-"+locale.hashCode()+"-"+tz.getID()+"-"+lenient; 093 DateFormat[] df= formats.get(id); 094 if(df==null) { 095 List<DateFormat> list=new ArrayList<DateFormat>(); 096 list.add(DateFormat.getTimeInstance(DateFormat.FULL,locale)); 097 list.add(DateFormat.getTimeInstance(DateFormat.LONG,locale)); 098 list.add(DateFormat.getTimeInstance(DateFormat.MEDIUM,locale)); 099 list.add(DateFormat.getTimeInstance(DateFormat.SHORT,locale)); 100 add24(list, locale); 101 addCustom(list, locale, FORMAT_TYPE_TIME); 102 df=list.toArray(new DateFormat[list.size()]); 103 104 for(int i=0;i<df.length;i++){ 105 df[i].setLenient(lenient); 106 df[i].setTimeZone(tz); 107 } 108 formats.put(id, df); 109 } 110 return df; 111 } 112 113 114 private static void add24(List<DateFormat> list,Locale locale) { 115 116 // if found h:mm:ss a add H:mm:ss ... 117 String p; 118 int index; 119 SimpleDateFormat sdf; 120 DateFormat[] df=list.toArray(new DateFormat[list.size()]); 121 for(int i=0;i<df.length;i++){ 122 if(df[i] instanceof SimpleDateFormat) { 123 p=((SimpleDateFormat) df[i]).toPattern()+""; 124 125 if(check(list,p,locale,"hh:mm:ss a","HH:mm:ss")) continue; 126 if(check(list,p,locale,"h:mm:ss a","H:mm:ss")) continue; 127 if(check(list,p,locale,"hh:mm a","HH:mm")) continue; 128 if(check(list,p,locale,"h:mm a","H:mm")) continue; 129 130 if(check(list,p,locale,"hh:mm:ssa","HH:mm:ss")) continue; 131 if(check(list,p,locale,"h:mm:ssa","H:mm:ss")) continue; 132 if(check(list,p,locale,"hh:mma","HH:mm")) continue; 133 if(check(list,p,locale,"h:mma","H:mm")) continue; 134 135 //if(check(list,p,locale,"HH:mm:ss","hh:mm:ss a")) continue; 136 //if(check(list,p,locale,"H:mm:ss","h:mm:ss a")) continue; 137 //if(check(list,p,locale,"HH:mm","hh:mm a")) continue; 138 //if(check(list,p,locale,"H:mm","h:mm a")) continue; 139 } 140 } 141 } 142 143 private static boolean check(List<DateFormat> list, String p,Locale locale, String from, String to) { 144 int index = p.indexOf(from); 145 if(index!=-1) { 146 p=StringUtil.replace(p, from, to, true); 147 SimpleDateFormat sdf = new SimpleDateFormat(p,locale); 148 if(!list.contains(sdf))list.add(sdf); 149 return true; 150 } 151 return false; 152 } 153 154 155 private static void addCustom(List<DateFormat> list,Locale locale,short formatType) { 156 // get custom formats from file 157 Config config = ThreadLocalPageContext.getConfig(); 158 Resource dir=config.getConfigDir().getRealResource("locales"); 159 if(dir.isDirectory()) { 160 String appendix="-datetime"; 161 if(formatType==FORMAT_TYPE_DATE)appendix="-date"; 162 if(formatType==FORMAT_TYPE_TIME)appendix="-time"; 163 164 Resource file = dir.getRealResource(locale.getLanguage()+"-"+locale.getCountry()+appendix+".df"); 165 if(file.isFile()) { 166 try { 167 String content=IOUtil.toString(file, null); 168 String[] arr = railo.runtime.type.util.ListUtil.listToStringArray(content, '\n'); 169 String line; 170 SimpleDateFormat sdf; 171 for(int i=0;i<arr.length;i++){ 172 line=arr[i].trim(); 173 if(StringUtil.isEmpty(line)) continue; 174 sdf = new SimpleDateFormat(line,locale); 175 if(!list.contains(sdf))list.add(sdf); 176 } 177 178 } 179 catch (Throwable t) {} 180 } 181 } 182 } 183 184 /** 185 * CFML Supported LS Formats 186 * @param locale 187 * @param tz 188 * @param lenient 189 * @return 190 */ 191 public static DateFormat[] getCFMLFormats(TimeZone tz,boolean lenient) { 192 String id="cfml-"+Locale.ENGLISH.hashCode()+"-"+tz.getID()+"-"+lenient; 193 DateFormat[] df= formats.get(id); 194 if(df==null) { 195 df= new SimpleDateFormat[]{ 196 new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy",Locale.ENGLISH) 197 ,new SimpleDateFormat("MMMM dd, yyyy HH:mm:ss a zzz",Locale.ENGLISH) 198 ,new SimpleDateFormat("MMM dd, yyyy HH:mm:ss a",Locale.ENGLISH) 199 ,new SimpleDateFormat("MMM dd, yyyy HH:mm:ss",Locale.ENGLISH) 200 ,new SimpleDateFormat("MMMM d yyyy HH:mm:ssZ",Locale.ENGLISH) 201 ,new SimpleDateFormat("MMMM d yyyy HH:mm:ss",Locale.ENGLISH) 202 ,new SimpleDateFormat("MMMM d yyyy HH:mm",Locale.ENGLISH) 203 ,new SimpleDateFormat("EEE, MMM dd, yyyy HH:mm:ssZ",Locale.ENGLISH) 204 ,new SimpleDateFormat("EEE, MMM dd, yyyy HH:mm:ss",Locale.ENGLISH) 205 ,new SimpleDateFormat("EEEE, MMMM dd, yyyy H:mm:ss a zzz",Locale.ENGLISH) 206 ,new SimpleDateFormat("dd-MMM-yy HH:mm a",Locale.ENGLISH) 207 ,new SimpleDateFormat("dd-MMMM-yy HH:mm a",Locale.ENGLISH) 208 ,new SimpleDateFormat("EE, dd MMM yyyy HH:mm:ss zz",Locale.ENGLISH) 209 ,new SimpleDateFormat("EEE d, MMM yyyy HH:mm:ss zz",Locale.ENGLISH) 210 ,new SimpleDateFormat("dd-MMM-yyyy",Locale.ENGLISH) 211 ,new SimpleDateFormat("MMMM, dd yyyy HH:mm:ssZ",Locale.ENGLISH) 212 ,new SimpleDateFormat("MMMM, dd yyyy HH:mm:ss",Locale.ENGLISH) 213 ,new SimpleDateFormat("yyyy/MM/dd HH:mm:ss zz",Locale.ENGLISH) 214 ,new SimpleDateFormat("dd MMM yyyy HH:mm:ss zz",Locale.ENGLISH) 215 ,new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZ (z)",Locale.ENGLISH) 216 ,new SimpleDateFormat("dd MMM, yyyy HH:mm:ss",Locale.ENGLISH) 217 //,new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",Locale.ENGLISH) 218 }; 219 220 for(int i=0;i<df.length;i++){ 221 df[i].setLenient(lenient); 222 df[i].setTimeZone(tz); 223 } 224 formats.put(id, df); 225 } 226 return df; 227 } 228 229 public static DateFormat[] getFormats(Locale locale,TimeZone tz,boolean lenient, short formatType) { 230 if(FORMAT_TYPE_DATE_TIME==formatType)return getDateTimeFormats(locale,TimeZoneConstants.GMT,true); 231 if(FORMAT_TYPE_DATE==formatType)return getDateFormats(locale,TimeZoneConstants.GMT,true); 232 if(FORMAT_TYPE_TIME==formatType)return getTimeFormats(locale,TimeZoneConstants.GMT,true); 233 234 DateFormat[] dt = getDateTimeFormats(locale,TimeZoneConstants.GMT,true); 235 DateFormat[] d = getDateFormats(locale,TimeZoneConstants.GMT,true); 236 DateFormat[] t = getTimeFormats(locale,TimeZoneConstants.GMT,true); 237 238 DateFormat[] all=new DateFormat[dt.length+d.length+t.length]; 239 for(int i=0;i<dt.length;i++){ 240 all[i]=dt[i]; 241 } 242 for(int i=0;i<d.length;i++){ 243 all[i+dt.length]=d[i]; 244 } 245 for(int i=0;i<t.length;i++){ 246 all[i+dt.length+d.length]=t[i]; 247 } 248 return getDateTimeFormats(locale,TimeZoneConstants.GMT,true); 249 } 250 251 public static String[] getSupportedPatterns(Locale locale, short formatType) { 252 DateFormat[] _formats = getFormats(locale,TimeZoneConstants.GMT,true,formatType); 253 String[] patterns=new String[_formats.length]; 254 for(int i=0;i<_formats.length;i++){ 255 if(!(_formats[i] instanceof SimpleDateFormat))return null; // all or nothing 256 patterns[i]=((SimpleDateFormat)_formats[i]).toPattern(); 257 } 258 259 return patterns; 260 } 261 262 263 264 }