blob: 6712b9c4fcdfba9d520f08e1d906ad5a29e4d231 [file] [log] [blame] [raw]
/*
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;
}
}