123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /* ====================================================================
- 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.usermodel;
-
- import java.math.RoundingMode;
- import java.text.DateFormatSymbols;
- import java.text.DecimalFormat;
- import java.text.DecimalFormatSymbols;
- import java.text.FieldPosition;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.Locale;
-
- import org.apache.poi.util.LocaleUtil;
-
- /**
- * A wrapper around a {@link SimpleDateFormat} instance,
- * which handles a few Excel-style extensions that
- * are not supported by {@link SimpleDateFormat}.
- * Currently, the extensions are around the handling
- * of elapsed time, eg rendering 1 day 2 hours
- * as 26 hours.
- */
- public class ExcelStyleDateFormatter extends SimpleDateFormat {
- public static final char MMMMM_START_SYMBOL = '\ue001';
- public static final char MMMMM_TRUNCATE_SYMBOL = '\ue002';
- public static final char H_BRACKET_SYMBOL = '\ue010';
- public static final char HH_BRACKET_SYMBOL = '\ue011';
- public static final char M_BRACKET_SYMBOL = '\ue012';
- public static final char MM_BRACKET_SYMBOL = '\ue013';
- public static final char S_BRACKET_SYMBOL = '\ue014';
- public static final char SS_BRACKET_SYMBOL = '\ue015';
- public static final char L_BRACKET_SYMBOL = '\ue016';
- public static final char LL_BRACKET_SYMBOL = '\ue017';
-
- private static final DecimalFormat format1digit;
- private static final DecimalFormat format2digits;
-
- private static final DecimalFormat format3digit;
- private static final DecimalFormat format4digits;
-
- static {
- DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(Locale.ROOT);
- format1digit = new DecimalFormat("0", dfs);
- format2digits = new DecimalFormat("00", dfs);
- format3digit = new DecimalFormat("0", dfs);
- format4digits = new DecimalFormat("00", dfs);
- DataFormatter.setExcelStyleRoundingMode(format1digit, RoundingMode.DOWN);
- DataFormatter.setExcelStyleRoundingMode(format2digits, RoundingMode.DOWN);
- DataFormatter.setExcelStyleRoundingMode(format3digit);
- DataFormatter.setExcelStyleRoundingMode(format4digits);
- }
-
- {
- setTimeZone(LocaleUtil.getUserTimeZone());
- }
-
- private double dateToBeFormatted;
-
- // no-arg constructor is private because of undefined super call with locale
-
- public ExcelStyleDateFormatter(String pattern) {
- super(processFormatPattern(pattern), LocaleUtil.getUserLocale());
- }
-
- public ExcelStyleDateFormatter(String pattern,
- DateFormatSymbols formatSymbols) {
- super(processFormatPattern(pattern), formatSymbols);
- }
-
- public ExcelStyleDateFormatter(String pattern, Locale locale) {
- super(processFormatPattern(pattern), locale);
- }
-
- /**
- * Takes a format String, and replaces Excel specific bits
- * with our detection sequences
- */
- private static String processFormatPattern(String f) {
- String t = f.replace("MMMMM", MMMMM_START_SYMBOL + "MMM" + MMMMM_TRUNCATE_SYMBOL);
- t = t.replace("[H]", String.valueOf(H_BRACKET_SYMBOL));
- t = t.replace("[HH]", String.valueOf(HH_BRACKET_SYMBOL));
- t = t.replace("[m]", String.valueOf(M_BRACKET_SYMBOL));
- t = t.replace("[mm]", String.valueOf(MM_BRACKET_SYMBOL));
- t = t.replace("[s]", String.valueOf(S_BRACKET_SYMBOL));
- t = t.replace("[ss]", String.valueOf(SS_BRACKET_SYMBOL));
- t = t.replaceAll("s.000", "s.SSS");
- t = t.replaceAll("s.00", "s." + LL_BRACKET_SYMBOL);
- t = t.replaceAll("s.0", "s." + L_BRACKET_SYMBOL);
- return t;
- }
-
- /**
- * Used to let us know what the date being
- * formatted is, in Excel terms, which we
- * may wish to use when handling elapsed
- * times.
- */
- public void setDateToBeFormatted(double date) {
- this.dateToBeFormatted = date;
- }
-
- @Override
- public StringBuffer format(Date date, StringBuffer paramStringBuffer,
- FieldPosition paramFieldPosition) {
- // Do the normal format
- String s = super.format(date, paramStringBuffer, paramFieldPosition).toString();
-
- // Now handle our special cases
- if (s.indexOf(MMMMM_START_SYMBOL) != -1) {
- s = s.replaceAll(
- MMMMM_START_SYMBOL + "(\\p{L}|\\p{P})[\\p{L}\\p{P}]+" + MMMMM_TRUNCATE_SYMBOL,
- "$1"
- );
- }
-
- if (s.indexOf(H_BRACKET_SYMBOL) != -1 ||
- s.indexOf(HH_BRACKET_SYMBOL) != -1) {
- float hours = (float) dateToBeFormatted * 24;
-
- s = s.replaceAll(
- String.valueOf(H_BRACKET_SYMBOL),
- format1digit.format(hours)
- );
- s = s.replaceAll(
- String.valueOf(HH_BRACKET_SYMBOL),
- format2digits.format(hours)
- );
- }
-
- if (s.indexOf(M_BRACKET_SYMBOL) != -1 ||
- s.indexOf(MM_BRACKET_SYMBOL) != -1) {
- float minutes = (float) dateToBeFormatted * 24 * 60;
- s = s.replaceAll(
- String.valueOf(M_BRACKET_SYMBOL),
- format1digit.format(minutes)
- );
- s = s.replaceAll(
- String.valueOf(MM_BRACKET_SYMBOL),
- format2digits.format(minutes)
- );
- }
- if (s.indexOf(S_BRACKET_SYMBOL) != -1 ||
- s.indexOf(SS_BRACKET_SYMBOL) != -1) {
- float seconds = (float) (dateToBeFormatted * 24 * 60 * 60);
- s = s.replaceAll(
- String.valueOf(S_BRACKET_SYMBOL),
- format1digit.format(seconds)
- );
- s = s.replaceAll(
- String.valueOf(SS_BRACKET_SYMBOL),
- format2digits.format(seconds)
- );
- }
-
- if (s.indexOf(L_BRACKET_SYMBOL) != -1 ||
- s.indexOf(LL_BRACKET_SYMBOL) != -1) {
- float millisTemp = (float) ((dateToBeFormatted - Math.floor(dateToBeFormatted)) * 24 * 60 * 60);
- float millis = (millisTemp - (int) millisTemp);
- s = s.replaceAll(
- String.valueOf(L_BRACKET_SYMBOL),
- format3digit.format(millis * 10.0)
- );
- s = s.replaceAll(
- String.valueOf(LL_BRACKET_SYMBOL),
- format4digits.format(millis * 100.0)
- );
- }
-
- return new StringBuffer(s);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof ExcelStyleDateFormatter)) {
- return false;
- }
-
- ExcelStyleDateFormatter other = (ExcelStyleDateFormatter) o;
- return dateToBeFormatted == other.dateToBeFormatted;
- }
-
- @Override
- public int hashCode() {
- return Double.valueOf(dateToBeFormatted).hashCode();
- }
- }
|