Bugzilla >52928 - DateFormatConverter: an utility to convert instances of java.text.DateFormat to Excel format patterns

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1301923 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2012-03-17 12:16:45 +00:00
parent 5a6b2f2299
commit 0d752498a2
3 changed files with 557 additions and 0 deletions

View File

@ -34,6 +34,7 @@
<changes>
<release version="3.8-beta6" date="2012-??-??">
<action dev="poi-developers" type="add">52928 - DateFormatConverter: an utility to convert instances of java.text.DateFormat to Excel format patterns</action>
<action dev="poi-developers" type="fix">52895 - show SSTIndex instead of XFIndex in LabelSSTRecord.toString()</action>
<action dev="poi-developers" type="fix">52835 - Tolerate missing Count and UniqueCount attributes when parsing shared strings table in XSSF eventusermodel</action>
<action dev="poi-developers" type="add">52818 - Added implementation for RANK()</action>

View File

@ -0,0 +1,426 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.util;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Convert java DateFormat patterns into Excel custom number formats.
* For example, to format a date in excel using the "dd MMMM, yyyy" pattern and Japanese
* locale, use the following code:
*
* <pre><code>
* // returns "[$-0411]dd MMMM, yyyy;@" where the [$-0411] prefix tells Excel to use the Japanese locale
* String excelFormatPattern = DateFormatConverter.convert(Locale.JAPANESE, "dd MMMM, yyyy");
*
* CellStyle cellStyle = workbook.createCellStyle();
*
* DataFormat poiFormat = workbook.createDataFormat();
* cellStyle.setDataFormat(poiFormat.getFormat(excelFormatPattern));
* cell.setCellValue(new Date());
* cell.setCellStyle(cellStyle); // formats date as '2012\u5e743\u670817\u65e5'
*
* </code></pre>
*
*
*/
public class DateFormatConverter {
public static class DateFormatTokenizer {
String format;
int pos;
public DateFormatTokenizer(String format) {
this.format = format;
}
public String getNextToken() {
if( pos >= format.length() ) {
return null;
}
int subStart = pos;
char curChar = format.charAt(pos);
++pos;
if( curChar == '\'' ) {
while( ( pos < format.length() ) && ( ( curChar = format.charAt(pos) ) != '\'' ) ) {
++pos;
}
if( pos < format.length() ) {
++pos;
}
} else {
char activeChar = curChar;
while( ( pos < format.length() ) && ( ( curChar = format.charAt(pos) ) == activeChar ) ) {
++pos;
}
}
return format.substring(subStart,pos);
}
public static String[] tokenize( String format ) {
List<String> result = new ArrayList<String>();
DateFormatTokenizer tokenizer = new DateFormatTokenizer(format);
String token;
while( ( token = tokenizer.getNextToken() ) != null ) {
result.add(token);
}
return result.toArray(new String[0]);
}
public String toString() {
StringBuilder result = new StringBuilder();
DateFormatTokenizer tokenizer = new DateFormatTokenizer(format);
String token;
while( ( token = tokenizer.getNextToken() ) != null ) {
if( result.length() > 0 ) {
result.append( ", " );
}
result.append("[").append(token).append("]");
}
return result.toString();
}
}
private static Map<String,String> tokenConversions = prepareTokenConversions();
private static Map<String,String> localePrefixes = prepareLocalePrefixes();
private static Map<String,String> prepareTokenConversions() {
Map<String,String> result = new HashMap<String,String>();
result.put( "EEEE", "dddd" );
result.put( "EEE", "ddd" );
result.put( "EE", "ddd" );
result.put( "E", "d" );
result.put( "Z", "" );
result.put( "z", "" );
result.put( "a", "am/pm" );
result.put( "A", "AM/PM" );
result.put( "K", "H" );
result.put( "KK", "HH" );
result.put( "k", "h" );
result.put( "kk", "hh" );
result.put( "S", "0" );
result.put( "SS", "00" );
result.put( "SSS", "000" );
return result;
}
private static Map<String,String> prepareLocalePrefixes() {
Map<String,String> result = new HashMap<String,String>();
result.put( "af", "[$-0436]" );
result.put( "am", "[$-45E]" );
result.put( "ar_ae", "[$-3801]" );
result.put( "ar_bh", "[$-3C01]" );
result.put( "ar_dz", "[$-1401]" );
result.put( "ar_eg", "[$-C01]" );
result.put( "ar_iq", "[$-0801]" );
result.put( "ar_jo", "[$-2C01]" );
result.put( "ar_kw", "[$-3401]" );
result.put( "ar_lb", "[$-3001]" );
result.put( "ar_ly", "[$-1001]" );
result.put( "ar_ma", "[$-1801]" );
result.put( "ar_om", "[$-2001]" );
result.put( "ar_qa", "[$-4001]" );
result.put( "ar_sa", "[$-0401]" );
result.put( "ar_sy", "[$-2801]" );
result.put( "ar_tn", "[$-1C01]" );
result.put( "ar_ye", "[$-2401]" );
result.put( "as", "[$-44D]" );
result.put( "az_az", "[$-82C]" );
result.put( "az_az", "[$-42C]" );
result.put( "be", "[$-0423]" );
result.put( "bg", "[$-0402]" );
result.put( "bn", "[$-0845]" );
result.put( "bn", "[$-0445]" );
result.put( "bo", "[$-0451]" );
result.put( "bs", "[$-141A]" );
result.put( "ca", "[$-0403]" );
result.put( "cs", "[$-0405]" );
result.put( "cy", "[$-0452]" );
result.put( "da", "[$-0406]" );
result.put( "de_at", "[$-C07]" );
result.put( "de_ch", "[$-0807]" );
result.put( "de_de", "[$-0407]" );
result.put( "de_li", "[$-1407]" );
result.put( "de_lu", "[$-1007]" );
result.put( "dv", "[$-0465]" );
result.put( "el", "[$-0408]" );
result.put( "en_au", "[$-C09]" );
result.put( "en_bz", "[$-2809]" );
result.put( "en_ca", "[$-1009]" );
result.put( "en_cb", "[$-2409]" );
result.put( "en_gb", "[$-0809]" );
result.put( "en_ie", "[$-1809]" );
result.put( "en_in", "[$-4009]" );
result.put( "en_jm", "[$-2009]" );
result.put( "en_nz", "[$-1409]" );
result.put( "en_ph", "[$-3409]" );
result.put( "en_tt", "[$-2C09]" );
result.put( "en_us", "[$-0409]" );
result.put( "en_za", "[$-1C09]" );
result.put( "es_ar", "[$-2C0A]" );
result.put( "es_bo", "[$-400A]" );
result.put( "es_cl", "[$-340A]" );
result.put( "es_co", "[$-240A]" );
result.put( "es_cr", "[$-140A]" );
result.put( "es_do", "[$-1C0A]" );
result.put( "es_ec", "[$-300A]" );
result.put( "es_es", "[$-40A]" );
result.put( "es_gt", "[$-100A]" );
result.put( "es_hn", "[$-480A]" );
result.put( "es_mx", "[$-80A]" );
result.put( "es_ni", "[$-4C0A]" );
result.put( "es_pa", "[$-180A]" );
result.put( "es_pe", "[$-280A]" );
result.put( "es_pr", "[$-500A]" );
result.put( "es_py", "[$-3C0A]" );
result.put( "es_sv", "[$-440A]" );
result.put( "es_uy", "[$-380A]" );
result.put( "es_ve", "[$-200A]" );
result.put( "et", "[$-0425]" );
result.put( "eu", "[$-42D]" );
result.put( "fa", "[$-0429]" );
result.put( "fi", "[$-40B]" );
result.put( "fo", "[$-0438]" );
result.put( "fr_be", "[$-80C]" );
result.put( "fr_ca", "[$-C0C]" );
result.put( "fr_ch", "[$-100C]" );
result.put( "fr_fr", "[$-40C]" );
result.put( "fr_lu", "[$-140C]" );
result.put( "gd", "[$-43C]" );
result.put( "gd_ie", "[$-83C]" );
result.put( "gn", "[$-0474]" );
result.put( "gu", "[$-0447]" );
result.put( "he", "[$-40D]" );
result.put( "hi", "[$-0439]" );
result.put( "hr", "[$-41A]" );
result.put( "hu", "[$-40E]" );
result.put( "hy", "[$-42B]" );
result.put( "id", "[$-0421]" );
result.put( "is", "[$-40F]" );
result.put( "it_ch", "[$-0810]" );
result.put( "it_it", "[$-0410]" );
result.put( "ja", "[$-0411]" );
result.put( "kk", "[$-43F]" );
result.put( "km", "[$-0453]" );
result.put( "kn", "[$-44B]" );
result.put( "ko", "[$-0412]" );
result.put( "ks", "[$-0460]" );
result.put( "la", "[$-0476]" );
result.put( "lo", "[$-0454]" );
result.put( "lt", "[$-0427]" );
result.put( "lv", "[$-0426]" );
result.put( "mi", "[$-0481]" );
result.put( "mk", "[$-42F]" );
result.put( "ml", "[$-44C]" );
result.put( "mn", "[$-0850]" );
result.put( "mn", "[$-0450]" );
result.put( "mr", "[$-44E]" );
result.put( "ms_bn", "[$-83E]" );
result.put( "ms_my", "[$-43E]" );
result.put( "mt", "[$-43A]" );
result.put( "my", "[$-0455]" );
result.put( "ne", "[$-0461]" );
result.put( "nl_be", "[$-0813]" );
result.put( "nl_nl", "[$-0413]" );
result.put( "no_no", "[$-0814]" );
result.put( "or", "[$-0448]" );
result.put( "pa", "[$-0446]" );
result.put( "pl", "[$-0415]" );
result.put( "pt_br", "[$-0416]" );
result.put( "pt_pt", "[$-0816]" );
result.put( "rm", "[$-0417]" );
result.put( "ro", "[$-0418]" );
result.put( "ro_mo", "[$-0818]" );
result.put( "ru", "[$-0419]" );
result.put( "ru_mo", "[$-0819]" );
result.put( "sa", "[$-44F]" );
result.put( "sb", "[$-42E]" );
result.put( "sd", "[$-0459]" );
result.put( "si", "[$-45B]" );
result.put( "sk", "[$-41B]" );
result.put( "sl", "[$-0424]" );
result.put( "so", "[$-0477]" );
result.put( "sq", "[$-41C]" );
result.put( "sr_sp", "[$-C1A]" );
result.put( "sr_sp", "[$-81A]" );
result.put( "sv_fi", "[$-81D]" );
result.put( "sv_se", "[$-41D]" );
result.put( "sw", "[$-0441]" );
result.put( "ta", "[$-0449]" );
result.put( "te", "[$-44A]" );
result.put( "tg", "[$-0428]" );
result.put( "th", "[$-41E]" );
result.put( "tk", "[$-0442]" );
result.put( "tn", "[$-0432]" );
result.put( "tr", "[$-41F]" );
result.put( "ts", "[$-0431]" );
result.put( "tt", "[$-0444]" );
result.put( "uk", "[$-0422]" );
result.put( "ur", "[$-0420]" );
result.put( "UTF_8", "[$-0000]" );
result.put( "uz_uz", "[$-0843]" );
result.put( "uz_uz", "[$-0443]" );
result.put( "vi", "[$-42A]" );
result.put( "xh", "[$-0434]" );
result.put( "yi", "[$-43D]" );
result.put( "zh_cn", "[$-0804]" );
result.put( "zh_hk", "[$-C04]" );
result.put( "zh_mo", "[$-1404]" );
result.put( "zh_sg", "[$-1004]" );
result.put( "zh_tw", "[$-0404]" );
result.put( "zu", "[$-0435]" );
result.put( "ar", "[$-0401]" );
result.put( "bn", "[$-0845]" );
result.put( "de", "[$-0407]" );
result.put( "en", "[$-0409]" );
result.put( "es", "[$-40A]" );
result.put( "fr", "[$-40C]" );
result.put( "it", "[$-0410]" );
result.put( "ms", "[$-43E]" );
result.put( "nl", "[$-0413]" );
result.put( "nn", "[$-0814]" );
result.put( "no", "[$-0414]" );
result.put( "pt", "[$-0816]" );
result.put( "sr", "[$-C1A]" );
result.put( "sv", "[$-41D]" );
result.put( "uz", "[$-0843]" );
result.put( "zh", "[$-0804]" );
result.put( "ga", "[$-43C]" );
result.put( "ga_ie", "[$-83C]" );
result.put( "in", "[$-0421]" );
result.put( "iw", "[$-40D]" );
return result;
}
public static String getPrefixForLocale( Locale locale ) {
String localeString = locale.toString().toLowerCase();
String result = localePrefixes.get( localeString );
if( result == null ) {
result = localePrefixes.get( localeString.substring( 0, 2 ) );
if( result == null ) {
Locale parentLocale = new Locale(localeString.substring( 0, 2 ));
System.out.println( "Unable to find prefix for " + locale + "(" + locale.getDisplayName() + ") or "
+ localeString.substring( 0, 2 ) + "(" + parentLocale.getDisplayName() + ")" );
return "";
}
}
return result;
}
public static String convert( Locale locale, DateFormat df ) {
String ptrn = ((SimpleDateFormat)df).toPattern();
return convert(locale, ptrn);
}
public static String convert( Locale locale, String format ) {
StringBuilder result = new StringBuilder();
result.append(getPrefixForLocale(locale));
DateFormatTokenizer tokenizer = new DateFormatTokenizer(format);
String token;
while( ( token = tokenizer.getNextToken() ) != null ) {
if( token.startsWith("'") ) {
result.append( token.replaceAll("'", "\"") );
} else if( ! Character.isLetter( token.charAt( 0 ) ) ) {
result.append( token );
} else {
// It's a code, translate it if necessary
String mappedToken = tokenConversions.get(token);
result.append( mappedToken == null ? token : mappedToken );
}
}
result.append(";@");
return result.toString().trim();
}
public static String getJavaDatePattern(int style, Locale locale) {
DateFormat df = DateFormat.getDateInstance(style, locale);
if( df instanceof SimpleDateFormat ) {
return ((SimpleDateFormat)df).toPattern();
} else {
switch( style ) {
case DateFormat.SHORT:
return "d/MM/yy";
case DateFormat.MEDIUM:
return "MMM d, yyyy";
case DateFormat.LONG:
return "MMMM d, yyyy";
case DateFormat.FULL:
return "dddd, MMMM d, yyyy";
default:
return "MMM d, yyyy";
}
}
}
public static String getJavaTimePattern(int style, Locale locale) {
DateFormat df = DateFormat.getTimeInstance(style, locale);
if( df instanceof SimpleDateFormat ) {
return ((SimpleDateFormat)df).toPattern();
} else {
switch( style ) {
case DateFormat.SHORT:
return "h:mm a";
case DateFormat.MEDIUM:
return "h:mm:ss a";
case DateFormat.LONG:
return "h:mm:ss a";
case DateFormat.FULL:
return "h:mm:ss a";
default:
return "h:mm:ss a";
}
}
}
public static String getJavaDateTimePattern(int style, Locale locale) {
DateFormat df = DateFormat.getDateTimeInstance(style, style, locale);
if( df instanceof SimpleDateFormat ) {
return ((SimpleDateFormat)df).toPattern();
} else {
switch( style ) {
case DateFormat.SHORT:
return "M/d/yy h:mm a";
case DateFormat.MEDIUM:
return "MMM d, yyyy h:mm:ss a";
case DateFormat.LONG:
return "MMMM d, yyyy h:mm:ss a";
case DateFormat.FULL:
return "dddd, MMMM d, yyyy h:mm:ss a";
default:
return "MMM d, yyyy h:mm:ss a";
}
}
}
}

View File

@ -0,0 +1,130 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.ss.util;
import junit.framework.TestCase;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.TempFile;
import java.io.File;
import java.io.FileOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public final class TestDateFormatConverter extends TestCase {
private void outputLocaleDataFormats( Date date, boolean dates, boolean times, int style, String styleName ) throws Exception {
Workbook workbook = new HSSFWorkbook();
String sheetName;
if( dates ) {
if( times ) {
sheetName = "DateTimes";
} else {
sheetName = "Dates";
}
} else {
sheetName = "Times";
}
Sheet sheet = workbook.createSheet(sheetName);
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("locale");
header.createCell(1).setCellValue("DisplayName");
header.createCell(2).setCellValue("Excel " + styleName);
header.createCell(3).setCellValue("java.text.DateFormat");
header.createCell(4).setCellValue("Equals");
header.createCell(5).setCellValue("Java pattern");
header.createCell(6).setCellValue("Excel pattern");
int rowNum = 1;
for( Locale locale : DateFormat.getAvailableLocales() ) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(locale.toString());
row.createCell(1).setCellValue(locale.getDisplayName());
DateFormat dateFormat;
if( dates ) {
if( times ) {
dateFormat = DateFormat.getDateTimeInstance(style, style, locale);
} else {
dateFormat = DateFormat.getDateInstance(style, locale);
}
} else {
dateFormat = DateFormat.getTimeInstance(style, locale);
}
Cell cell = row.createCell(2);
cell.setCellValue(date);
CellStyle cellStyle = row.getSheet().getWorkbook().createCellStyle();
String javaDateFormatPattern = ((SimpleDateFormat)dateFormat).toPattern();
String excelFormatPattern = DateFormatConverter.convert(locale, javaDateFormatPattern);
DataFormat poiFormat = row.getSheet().getWorkbook().createDataFormat();
cellStyle.setDataFormat(poiFormat.getFormat(excelFormatPattern));
row.createCell(3).setCellValue(dateFormat.format(date));
cell.setCellStyle(cellStyle);
// the formula returns TRUE is the formatted date in column C equals to the string in column D
row.createCell(4).setCellFormula("TEXT(C"+rowNum+",G"+rowNum+")=D" + rowNum);
row.createCell(5).setCellValue(javaDateFormatPattern);
row.createCell(6).setCellValue(excelFormatPattern);
}
File outputFile = TempFile.createTempFile("Locale" + sheetName + styleName, ".xlsx");
FileOutputStream outputStream = new FileOutputStream(outputFile);
try {
workbook.write(outputStream);
} finally {
outputStream.close();
}
System.out.println("Open " + outputFile.getAbsolutePath()+" in Excel");
}
public void testJavaDateFormatsInExcel() throws Exception {
Date date = new Date();
outputLocaleDataFormats(date, true, false, DateFormat.DEFAULT, "Default" );
outputLocaleDataFormats(date, true, false, DateFormat.SHORT, "Short" );
outputLocaleDataFormats(date, true, false, DateFormat.MEDIUM, "Medium" );
outputLocaleDataFormats(date, true, false, DateFormat.LONG, "Long" );
outputLocaleDataFormats(date, true, false, DateFormat.FULL, "Full" );
outputLocaleDataFormats(date, true, true, DateFormat.DEFAULT, "Default" );
outputLocaleDataFormats(date, true, true, DateFormat.SHORT, "Short" );
outputLocaleDataFormats(date, true, true, DateFormat.MEDIUM, "Medium" );
outputLocaleDataFormats(date, true, true, DateFormat.LONG, "Long" );
outputLocaleDataFormats(date, true, true, DateFormat.FULL, "Full" );
outputLocaleDataFormats(date, false, true, DateFormat.DEFAULT, "Default" );
outputLocaleDataFormats(date, false, true, DateFormat.SHORT, "Short" );
outputLocaleDataFormats(date, false, true, DateFormat.MEDIUM, "Medium" );
outputLocaleDataFormats(date, false, true, DateFormat.LONG, "Long" );
outputLocaleDataFormats(date, false, true, DateFormat.FULL, "Full" );
}
}