| /* |
| Copyright 2015-2022 Rivoreo |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| "Software"), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE |
| FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| package rivoreo.util; |
| |
| import java.text.DateFormat; |
| import java.text.SimpleDateFormat; |
| import java.text.spi.DateFormatProvider; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.ref.SoftReference; |
| import java.lang.ref.ReferenceQueue; |
| import java.util.Hashtable; |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.Map; |
| import java.util.Calendar; |
| import java.util.Locale; |
| import java.util.ResourceBundle; |
| |
| public class DateTimeFormatHelper { |
| private static String[] time_patterns; |
| |
| private static String[] get_time_patterns() { |
| return new String[] { |
| "HH:mm:ss z", |
| "HH:mm:ss z", |
| "HH:mm:ss", |
| "H:mm" |
| }; |
| } |
| |
| public static boolean modify_simpledateformat_to_24hour_format() { |
| Field cached_locale_data_field; |
| Class<?> field_type; |
| Object map; |
| try { |
| cached_locale_data_field = SimpleDateFormat.class.getDeclaredField("cachedLocaleData"); |
| field_type = cached_locale_data_field.getType(); |
| if(field_type != Hashtable.class && field_type != ConcurrentMap.class) return false; |
| cached_locale_data_field.setAccessible(true); |
| map = cached_locale_data_field.get(null); |
| ((Map)map).clear(); |
| } catch(NoSuchFieldException e) { |
| return false; |
| } catch(IllegalAccessException e) { |
| return false; |
| } |
| |
| if(time_patterns == null) time_patterns = get_time_patterns(); |
| |
| Method get_date_format_data_method = null; |
| try { |
| Class<?> sun_locale_data_class = Class.forName("sun.util.resources.LocaleData"); |
| get_date_format_data_method = sun_locale_data_class.getDeclaredMethod("getDateFormatData", Locale.class); |
| } catch(ClassNotFoundException e) { |
| } catch(NoSuchMethodException e) { |
| } |
| |
| for(Locale locale : DateFormat.getAvailableLocales()) { |
| String[] bundle_formats = null; |
| if(get_date_format_data_method != null) try { |
| Object o = get_date_format_data_method.invoke(null, locale); |
| if(o instanceof ResourceBundle) { |
| ResourceBundle r = (ResourceBundle)o; |
| bundle_formats = r.getStringArray("DateTimePatterns"); |
| if(bundle_formats.length < 9) bundle_formats = null; |
| } |
| } catch(IllegalAccessException e) { |
| e.printStackTrace(); |
| } catch(InvocationTargetException e) { |
| } |
| String[] formats = new String[9]; |
| formats[0] = time_patterns[0]; |
| formats[1] = time_patterns[1]; |
| formats[2] = time_patterns[2]; |
| formats[3] = time_patterns[3]; |
| if(bundle_formats == null) { |
| formats[4] = "EEEE MMMM d, yyyy G"; |
| formats[5] = "MMMM d, yyyy"; |
| formats[6] = "d MMM yyyy"; |
| formats[7] = "d/M/yyyy"; |
| formats[8] = "{1} {0}"; |
| } else { |
| formats[4] = bundle_formats[4]; |
| formats[5] = bundle_formats[5]; |
| formats[6] = bundle_formats[6]; |
| formats[7] = bundle_formats[7]; |
| formats[8] = bundle_formats[8]; |
| } |
| if(field_type == Hashtable.class) { |
| StringBuilder key = new StringBuilder(); |
| key.append(Calendar.getInstance(locale).getClass().getName()); |
| key.append('.'); |
| key.append(locale.getLanguage()); |
| key.append('_'); |
| key.append(locale.getCountry()); |
| key.append('_'); |
| key.append(locale.getVariant()); |
| ((Hashtable<String, String[]>)map).put(key.toString(), formats); |
| } else { |
| ((ConcurrentMap<Locale, String[]>)map).put(locale, formats); |
| } |
| } |
| |
| if(field_type == ConcurrentMap.class) { |
| Locale current_locale = Locale.getDefault(Locale.Category.FORMAT); |
| ConcurrentMap<Locale, String[]> format_map = (ConcurrentMap<Locale, String[]>)map; |
| if(!format_map.containsKey(current_locale)) { |
| format_map.put(current_locale, new String[] { |
| time_patterns[0], |
| time_patterns[1], |
| time_patterns[2], |
| time_patterns[3], |
| "EEEE MMMM d, yyyy G", |
| "MMMM d, yyyy", |
| "d MMM yyyy", |
| "d/M/yyyy", |
| "{1} {0}" |
| }); |
| } |
| } |
| |
| return true; |
| } |
| |
| public static boolean add_24hour_time_formats_sun_localeresources_cache() { |
| final String resource_key = "TimePatterns"; |
| Locale[] locales; |
| Method get_locale_resources_method; |
| Object adapter; |
| Field cache_field; |
| /* |
| Method get_date_format_data_method; |
| Field locale_data_field; |
| */ |
| String map_key_dtp; |
| Constructor<?> localeresources_resourcereference_constructor; |
| try { |
| Class<?> localeserviceproviderpool_class = Class.forName("sun.util.locale.provider.LocaleServiceProviderPool"); |
| Method get_pool_method = localeserviceproviderpool_class.getDeclaredMethod("getPool", Class.class); |
| Object o = get_pool_method.invoke(null, DateFormatProvider.class); |
| Method get_available_locales_method = localeserviceproviderpool_class.getDeclaredMethod("getAvailableLocales"); |
| o = get_available_locales_method.invoke(o); |
| if(!o.getClass().getName().equals("[Ljava.util.Locale;")) return false; |
| locales = (Locale[])o; |
| |
| Class<?> localeprovideradapter_class = Class.forName("sun.util.locale.provider.LocaleProviderAdapter"); |
| Method get_resource_bundle_based_method = localeprovideradapter_class.getDeclaredMethod("getResourceBundleBased"); |
| adapter = get_resource_bundle_based_method.invoke(null); |
| get_locale_resources_method = localeprovideradapter_class.getDeclaredMethod("getLocaleResources", Locale.class); |
| |
| Class<?> localeresources_class = Class.forName("sun.util.locale.provider.LocaleResources"); |
| cache_field = localeresources_class.getDeclaredField("cache"); |
| /* |
| try { |
| Class<?> localedata_class = Class.forName("sun.util.resources.LocaleData"); |
| get_date_format_data_method = localedata_class.getDeclaredMethod("getDateFormatData", Locale.class); |
| locale_data_field = localeresources_class.getDeclaredField("localeData"); |
| locale_data_field.setAccessible(true); |
| } catch(Exception e) { |
| locale_data_field = null; |
| get_date_format_data_method = null; |
| } |
| */ |
| try { |
| Field dtp_field = localeresources_class.getDeclaredField("DATE_TIME_PATTERN"); |
| dtp_field.setAccessible(true); |
| o = dtp_field.get(null); |
| if(!(o instanceof String)) throw new Exception("e"); |
| map_key_dtp = (String)o; |
| } catch(Exception e) { |
| map_key_dtp = "DTP."; |
| } |
| Class<?> localeresources_resourcereference_class = Class.forName("sun.util.locale.provider.LocaleResources$ResourceReference"); |
| localeresources_resourcereference_constructor = localeresources_resourcereference_class.getDeclaredConstructor(String.class, Object.class, ReferenceQueue.class); |
| localeresources_resourcereference_constructor.setAccessible(true); |
| } catch(ClassNotFoundException e) { |
| return false; |
| } catch(NoSuchMethodException e) { |
| return false; |
| } catch(NoSuchFieldException e) { |
| return false; |
| } catch(IllegalAccessException e) { |
| return false; |
| } catch(InvocationTargetException e) { |
| return false; |
| } |
| if(cache_field.getType() != ConcurrentMap.class) return false; |
| cache_field.setAccessible(true); |
| |
| if(time_patterns == null) time_patterns = get_time_patterns(); |
| |
| for(Locale locale : locales) try { |
| Object locale_resources = get_locale_resources_method.invoke(adapter, locale); |
| ConcurrentMap<String, SoftReference<Object>> map = (ConcurrentMap<String, SoftReference<Object>>)cache_field.get(locale_resources); |
| String key = map_key_dtp + resource_key; |
| /* |
| String[] bundle_formats = null; |
| if(get_date_format_data_method != null && locale_data_field != null) try { |
| Object locale_data = locale_data_field.get(locale_resources); |
| Object o = get_date_format_data_method.invoke(locale_data, locale); |
| if(o instanceof ResourceBundle) { |
| ResourceBundle r = (ResourceBundle)o; |
| if(r.containsKey(resource_key)) bundle_formats = (String[])r.getStringArray(resource_key); |
| } |
| } catch(IllegalAccessException e) { |
| } catch(InvocationTargetException e) { |
| } |
| */ |
| Object value = localeresources_resourcereference_constructor.newInstance(key, time_patterns, null); |
| map.put(key, (SoftReference<Object>)value); |
| } catch(IllegalAccessException e) { |
| e.printStackTrace(); |
| } catch(InvocationTargetException e) { |
| e.printStackTrace(); |
| } catch(InstantiationException e) { |
| e.printStackTrace(); |
| } |
| |
| return true; |
| } |
| } |