事实上,永远不可能使用写入单元格时定义的语言环境准确地获得格式化的单元格值。这是由于那里的语言环境观察者以及内部语言环境 excel 前缀在之后格式化时从未被重用的事实;
POI 3.17 的分析(可能会因为查看组件的内部完成方式而改变)
例如:Locale.US 的单元格样式的 dateConverted 格式(来自 CellStyle.getDataFormatString()),格式为 dd MMM yyyy hh:mm:ss 为:
“[$-0409]dd MMM yyyy hh:mm:ss; @" 其中本地 excel 内部前缀 = [$-0409]
它是从 DateFormatConverter.localPrefixes 私有静态映射中获得的。
这是一些解决此问题的代码:
/**
* Missing method in POI to enable the visualisation asIs of an cell with a
* different locale in a xls document.
*
* @param style
* the cell style localized.
* @return the Locale found using internal locationPrefixes.
*/
private final Locale extractLocaleFromDateCellStyle(final CellStyle style) {
final String reOpenedFormat = style.getDataFormatString();
LOGGER.info("Data Format of CellStyle : " + reOpenedFormat);
Locale locale = getLocaleFromPrefixes(extractPrefixeFromPattern(reOpenedFormat));
LOGGER.info("Found locale : " + locale);
return locale;
}
/**
* Extracts the internal prefix that represent the local of the style.
*
* @param pattern
* the DataFormatString of the cell style.
* @return the prefix found.
*/
private final String extractPrefixeFromPattern(final String pattern) {
Pattern regex = Pattern.compile(REGEX_PREFIX_PATTERN);
Matcher match = regex.matcher(pattern);
if (match.find()) {
LOGGER.info("Found prefix: " + match.group(1));
// return only the prefix
return match.group(1);
}
return null;
}
/**
* Reverse obtain the locale from the internal prefix from
* <code>DateFormatConverter.localePrefixes</code> private static field.
* <p>
* Uses reflection API.
*
* @param prefixes
* the prefixes
* @return the local corresponding tho the prefixes.
*/
public static Locale getLocaleFromPrefixes(final String prefixes) {
try {
@SuppressWarnings("unchecked")
Map<String, String> map = getStaticPrivateInternalMapLocalePrefix();
String localPrefix = null;
// find the language_Country value matching the internal excel
// prefix.
for (Map.Entry<String, String> entry : map.entrySet()) {
LOGGER.info("value : " + entry.getValue() + ", key :"
+ entry.getKey());
if (entry.getValue().equals(prefixes)
&& !StringUtils.isBlank(entry.getKey())) {
localPrefix = entry.getKey();
break;
}
}
// Generate a Locale with language, uppercase(country) info.
LOGGER.info(localPrefix);
if (localPrefix.indexOf('_') > 0) {
String[] languageCountry = localPrefix.split("_");
return new Locale(languageCountry[0],
StringUtils.defaultString(languageCountry[1]
.toUpperCase()));
}
// nothing found.
return null;
// factorized the multiples exceptions.
} catch (Exception e) {
throw new UnsupportedOperationException(e);
}
}
/**
* gets the internal code map for locale used by Excel.
*
* @return the internal map.
* @throws NoSuchFieldException
* if the private field name changes.
* @throws IllegalAccessException
* if the accessible is restricted.
*/
private static Map<String, String> getStaticPrivateInternalMapLocalePrefix()
throws NoSuchFieldException, IllegalAccessException {
// REFLECTION
Class<?> clazz = DateFormatConverter.class;
Field fieldlocalPrefixes = (Field) clazz
.getDeclaredField(DATE_CONVERTER_PRIVATE_PREFIXES_MAP);
// change from private to public.
fieldlocalPrefixes.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String, String> map = (Map<String, String>) fieldlocalPrefixes
.get(clazz);
LOGGER.info("MAP localPrefixes : " + map);
return map;
}
因此,下面的简单代码应该可以解决问题。请注意,代码未针对空值进行全面测试,并且取决于您使用的 POI 版本,直到它们在那里更改LOCALE OBSERVER MADNESS :)
....
final CellStyle cellStyle = reopenedCell.getCellStyle();
Locale locale = extractLocaleFromDateCellStyle(cellStyle);
LOGGER.info("FOUND LOCAL : " + locale);
// use the same local from the cell style during writing.
DataFormatter df = new DataFormatter(locale);
String reOpenValue = df.formatCellValue(reopenedCell);
问候。