package org.smartly.commons.util; import java.math.BigDecimal; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; public class FormatUtils { public static interface FormatHandler{ Object handle(final String placeholder); } public static final int STYLE_SHORT = DateFormat.SHORT; public static final int STYLE_MEDIUM = DateFormat.MEDIUM; public static final int STYLE_LONG = DateFormat.LONG; public static final String DEFAULT_DATEFORMAT = "yyyyMMdd"; public static final String DEFAULT_TIMEFORMAT = "HH:mm:ss"; //--------------------------------------------------------------------- // String //--------------------------------------------------------------------- /** * Extends String.format behaviour.<br> If "text" contains more format * specifiers than passed arguments, excided format specifiers are replaced * with an empty string. * * @param text * @param args * @return A formatted string. */ public static String format(final String text, Object... args) { Object[] array = CollectionUtils.toArray(args); final int length = null != array ? array.length : 0; if (StringUtils.hasText(text) && length > 0) { //-- string type ("hello {0}" or "hello %s") --// if (text.indexOf("{0}") > -1) { // "hello {0}" final Map<String, Object> context = toContext(args); return formatTemplate(text, "{", "}", context); } else { // "hello %s" // check if format specifiers are same number of passed arguments. final int count = StringUtils.countOccurrencesOf(text, "%"); if (count > length) { int diff = count - length; List<Object> largs = new ArrayList<Object>(Arrays.asList(array)); for (int i = 0; i < diff; i++) { largs.add(""); } array = largs.toArray(new Object[]{largs.size()}); } return String.format(text, array); } } return text; } public static String formatText(final String prefix, final String suffix, final String text, final Object... args) { final Map<String, Object> context = toContext(args); if (StringUtils.hasText(text) && !context.isEmpty()) { return formatTemplate(text, prefix, suffix, context); } return text; } public static Map<String, Object> toContext(final Object... args) { final Object[] array = CollectionUtils.toArray(args); final Map<String, Object> context = new HashMap<String, Object>(); for (int i = 0; i < array.length; i++) { final Object arg = array[i]; context.put(i + "", arg); } return context; } public static String format(final String text, final Map<String, ? extends Object> context) { if (StringUtils.hasText(text) && null != context && !context.isEmpty()) { // "hello {name}" return formatTemplate(text, "{", "}", context); } return text; } /** * Resolve encoding placeholders (i.e. @) in the given text, replacing * them with corresponding characters (i.e. @). * * @param text the String to resolve * @return the resolved String */ public static String resolveEncodingPlaceHolders(final String text) { return resolveEncodingPlaceHolders(text, "&#", ";"); } /** * Resolve encoding placeholders (i.e. @) in the given text, replacing * them with corresponding characters (i.e. @). * * @param text the String to resolve * @param prefix The placeholder's prefix (i.e. '&#') * @param suffix The placeholder's suffix (i.e. ';') * @return the resolved String */ public static String resolveEncodingPlaceHolders(final String text, final String prefix, final String suffix) { if (null == text) { return null; } final StringBuffer buf = new StringBuffer(text); int startIndex = text.indexOf(prefix); while (startIndex != -1) { final int endIndex = buf.toString().indexOf(suffix, startIndex + prefix.length()); if (endIndex != -1) { Character propVal = null; try { final String placeholder = buf.substring(startIndex + prefix.length(), endIndex); propVal = (char) Integer.parseInt(placeholder); } catch (Throwable t) { } if (propVal != null) { buf.replace(startIndex, endIndex + suffix.length(), propVal.toString()); startIndex = buf.toString().indexOf(prefix, startIndex + propVal.toString().length()); } else { // Could not resolve placeholder startIndex = buf.toString().indexOf(prefix, endIndex + suffix.length()); } } else { startIndex = -1; } } return buf.toString(); } /** * Resolve placeholders in the given text, replacing them with corresponding * contextData values. * * @param text the String to resolve * @param prefix The placeholder's prefix (i.e. '{') * @param suffix The placeholder's suffix (i.e. '}') * @param contextData Data containig values. Context Data map keys to * values. Keys are String and Values are Objects * @return the resolved String */ public static String formatTemplate(final String text, final String prefix, final String suffix, final Map<String, ?> contextData) { if (null == text) { return null; } final StringBuilder buf = new StringBuilder(text); int startIndex = text.indexOf(prefix); while (startIndex != -1) { final int endIndex = buf.toString().indexOf(suffix, startIndex + prefix.length()); if (endIndex != -1) { final String placeholder = buf.toString().substring(startIndex + prefix.length(), endIndex); Object propVal; if (contextData.containsKey(placeholder)) { if (placeholder.indexOf(".") == -1) { // simple property propVal = contextData.get(placeholder); } else { // navigate object propVal = BeanUtils.getValueIfAny(contextData, placeholder); } if (null == propVal) { propVal = ""; } } else { propVal = null; } if (propVal != null) { buf.replace(startIndex, endIndex + suffix.length(), propVal.toString()); startIndex = buf.toString().indexOf(prefix, startIndex + propVal.toString().length()); } else { // Could not resolve placeholder startIndex = buf.toString().indexOf(prefix, endIndex + suffix.length()); } } else { startIndex = -1; } } return buf.toString(); } public static String formatTemplate(final String text, final String prefix, final String suffix, final FormatHandler handler) { if (null == text || null==handler) { return null; } final StringBuilder buf = new StringBuilder(text); int startIndex = text.indexOf(prefix); while (startIndex != -1) { final int endIndex = buf.toString().indexOf(suffix, startIndex + prefix.length()); if (endIndex != -1) { final String placeholder = buf.toString().substring(startIndex + prefix.length(), endIndex); final Object propVal = handler.handle(placeholder); if (propVal != null) { buf.replace(startIndex, endIndex + suffix.length(), propVal.toString()); startIndex = buf.toString().indexOf(prefix, startIndex + propVal.toString().length()); } else { // Could not resolve placeholder startIndex = buf.toString().indexOf(prefix, endIndex + suffix.length()); } } else { startIndex = -1; } } return buf.toString(); } /** * Resolve placeholders in the given text, replacing them with corresponding * contextData values. * * @param text the String to resolve * @param prefix The placeholder's prefix (i.e. ':') * @param contextData Data containig values. Context Data map keys to * values. Keys are String and Values are Objects * @return the resolved String */ public static String formatTemplate(final String text, final String prefix, Map<String, Object> contextData) { if (null == text) { return null; } String result = text; for (Map.Entry<String, Object> entry : contextData.entrySet()) { if (null != entry.getValue()) { result = result.replace(prefix.concat(entry.getKey()), entry.getValue().toString()); } } return result; } // ------------------------------------------------------------------------- // D A T E // ------------------------------------------------------------------------- /** * Format an input date using passed Locale settings and a standard mask (yyyyMMdd).<br> * Ex: for a date "19680121", if locale is 'US' * return value: <br> * "01-21-1968" * * @param sDate String date to format. Ex: '21-01-1968' * @param locale Locale * @return Formatted date using Locale settings and "yyyyMMdd" mask. */ public static String formatDate(String sDate, Locale locale) { String result = null; try { String inputMask = DEFAULT_DATEFORMAT; result = formatDate(sDate, inputMask, locale); } catch (Exception ex) { result = ""; } return result; } /** * Format an input date using passed Locale settings.<br> * Ex: for a date "21-01-1968", with mask "dd-MM-yyyy", if locale is 'US' * return value: <br> * "01-21-1968" * * @param sDate String date to format. Ex: '21-01-1968' * @param inputMask Format of input date. Ex: 'dd-MM-yyyy' * @param locale Locale * @return Formatted date using Locale settings */ public static String formatDate(String sDate, String inputMask, Locale locale) { String result = null; DateWrapper date = null; try { date = new DateWrapper(sDate, inputMask); result = date.toString(DateFormat.MEDIUM, locale); } catch (Exception ex) { result = ex.getMessage(); } return result; } /** * Format an input date using output mask.<br> * Ex: for a date "21-01-1968", with input mask "dd-MM-yyyy", if outpurMask * is "yyyyMMdd" return value: <br> * "19680121" * * @param sDate String date to format. Ex: '21-01-1968' * @param inputMask Format of input date. Ex: 'dd-MM-yyyy' * @param outputMask Format of output mask (desired output date format).<br> * Ex: 'yyyyMMdd' * @return Formatted date. Ex: "19680121" */ public static String formatDate(String sDate, String inputMask, String outputMask) { String result = null; DateWrapper date = null; try { date = new DateWrapper(sDate, inputMask); result = date.toString(outputMask); } catch (Exception ex) { result = ex.getMessage(); } return result; } /** * Format a date using MEDIUM format. * * @param dateToFormat Date to format * @param locale Locale * @return String formatted date. */ public static String formatDate(final Date dateToFormat, final Locale locale) { return formatDate(dateToFormat, DateFormat.MEDIUM, locale); } public static String formatDate(final long dateToFormat, final Locale locale) { final Date date = new Date(dateToFormat); return formatDate(date, locale); } public static String formatDate(final long dateToFormat, final String template) { final Date date = new Date(dateToFormat); return formatDate(date, template); } public static String formatDate(final long dateToFormat, int style, Locale locale) { return formatDate(new Date(dateToFormat), style, locale, false); } public static String formatDate(final Date dateToFormat, final Locale locale, final boolean includetime) { return formatDate(dateToFormat, DateFormat.MEDIUM, locale, includetime); } /** * Format a date using passed style.<br> * Styles:<br> * - FULL = 0<br> * - LONG = 1<br> * - MEDIUM = 2<br> * - SHORT = 3 * * @param dateToFormat Date to format * @param style Date format style: FULL = 0, LONG = 1, MEDIUM = 2, SHORT = 3. * @param locale Locale * @return String formatted date. */ public static String formatDate(final Date dateToFormat, final int style, final Locale locale) { return formatDate(dateToFormat, style, locale, false); } /** * Format a date using passed style.<br> * Styles:<br> * - FULL = 0<br> * - LONG = 1<br> * - MEDIUM = 2<br> * - SHORT = 3 * * @param dateToFormat Date to format * @param style Date format style: FULL = 0, LONG = 1, MEDIUM = 2, SHORT = 3. * @param locale Locale * @param includetime If true also time in format "hh:mm:ss" is included in output * @return formatted date. */ public static String formatDate(final Date dateToFormat, final int style, final Locale locale, final boolean includetime) { String result = null; try { final DateWrapper date = new DateWrapper(dateToFormat); result = date.toString(style, locale); if (includetime) { result = result + " " + date.toString(DEFAULT_TIMEFORMAT); } } catch (Exception ex) { result = ""; } return result; } public static String formatDate(final Date dateToFormat) { return formatDate(dateToFormat, DEFAULT_DATEFORMAT); } /** * Format a date using passed outputFormat as mask.<br> * i.e. : if outputFormat is "yyyyMMdd" this date "21-jan-1968" will be formatted "19680121" * * @param dateToFormat Date to format * @param outputFormat Date format * @return String formatted date. */ public static String formatDate(final Date dateToFormat, final String outputFormat) { String result = null; try { final DateWrapper date = new DateWrapper(dateToFormat); result = date.toString(outputFormat); } catch (Exception ex) { result = ""; } return result; } public static String formatDateRange(final Date fromDate, final Date toDate, final Locale locale) { final DateWrapper date1 = new DateWrapper(fromDate); final int day1 = date1.getDay(); final int month1 = date1.getMonth(); final int year1 = date1.getYear(); final DateWrapper date2 = new DateWrapper(toDate); final int day2 = date2.getDay(); final int month2 = date2.getMonth(); final int year2 = date2.getYear(); if (year1 == year2) { if (month1 == month2) { //-- same month --// if (day1 == day2) { return FormatUtils.formatDate(fromDate, 2, locale); } else { return day1 + "-" + day2 + " " + DateUtils.getMonthAsString(month1, locale) + " " + year1; } } else { //-- not same month --// return day1 + " " + DateUtils.getShortMonthAsString(month1, locale) + " - " + day2 + " " + DateUtils.getShortMonthAsString(month2, locale) + " " + year1; } } return FormatUtils.formatDate(fromDate, 2, locale) + " " + FormatUtils.formatDate(toDate, 2, locale); } public static String getNow() { return FormatUtils.formatDate(DateUtils.now()); } /** * Return the pattern of a certain date style using current locale. * * @param style Date format style. i.e. DateFormat.SHORT * @return Patter of passed style and locale. i.e "M/d/yy" */ public static String getDateFormatLocalizedPattern(int style) { return getDateFormatLocalizedPattern(style, LocaleUtils.getCurrent()); } /** * Return the pattern of a certain date style. * * @param style Date format style. i.e. DateFormat.SHORT * @param locale Locale * @return Patter of passed style and locale. i.e "M/d/yy" */ public static String getDateFormatLocalizedPattern(int style, Locale locale) { final SimpleDateFormat df = (SimpleDateFormat) SimpleDateFormat.getDateInstance(style, locale); return df.toLocalizedPattern(); } /** * Return the pattern of a certain date style using current locale. * * @param style Date format style. i.e. DateFormat.SHORT * @return Patter of passed style and locale. i.e "M/d/yy" */ public static String getDateFormatPattern(int style) { return getDateFormatPattern(style, LocaleUtils.getCurrent()); } /** * Return the pattern of a certain date style. * * @param style Date format style. i.e. DateFormat.SHORT * @param locale Locale * @return Patter of passed style and locale. i.e "M/d/yy" */ public static String getDateFormatPattern(int style, Locale locale) { final SimpleDateFormat df = (SimpleDateFormat) SimpleDateFormat.getDateInstance(style, locale); return df.toPattern(); } // ------------------------------------------------------------------------- // D O U B L E // ------------------------------------------------------------------------- /** * Format a Double number using Locale settings * * @param value Double number to format * @param locale Locale * @return Formatted number. Ex: '1.256,78' */ public static String formatDouble(Double value, Locale locale) { return formatDouble(new BigDecimal(value), locale); } /** * Format a Double number using Locale settings * * @param value BigDecimal number to format * @param locale Locale * @return Formatted number. Ex: '1.256,78' */ public static String formatDouble(final BigDecimal value, final Locale locale) { String result = null; try { final NumberWrapper number = new NumberWrapper(value); result = number.toString(locale); } catch (Exception ex) { result = "0.0"; } return result; } /** * Format a Double number using Locale settings or current user * * @param value Double number (as String) to format * @param locale Locale * @return Formatted number. Ex: '1.256,78' */ public static String formatDouble(String value, final Locale locale) { value = value.replace(",", "\\."); final BigDecimal bd = new BigDecimal(value); final NumberWrapper number = new NumberWrapper(bd); final String result = number.toString(locale); return result; } public static String formatInteger(final Integer value, final Locale locale) { final String pattern = "#,##0;(#,##0)"; return formatNumber(value, pattern, locale); } public static String formatNumber(final Object value, final Locale locale) { final String pattern = "#,##0.0###;(#,##0.0###)"; return formatNumber(value, pattern, locale); } public static String formatNumber(final Object value, final Locale locale, final int minDecimals) { final String pattern = getPattern(minDecimals); return formatNumber(value, pattern, locale); } public static String formatNumber(final Object value, final String pattern, final Locale locale) { String result = null; try { if (null != value) { final NumberWrapper decodedNumber = new NumberWrapper(); decodedNumber.setLocale(locale); decodedNumber.setPattern(getPattern(pattern)); decodedNumber.setValue(value); result = decodedNumber.toString(); } else { throw new Exception("Number and Pattern cannot be null."); } } catch (Exception ex) { result = "Error: [" + ex.getMessage() + "]"; } return result; } // ------------------------------------------------------------------------- // p r i v a t e // ------------------------------------------------------------------------- private static String getPattern(final String pattern) { // pattern "n,nn0.nn;(n,nn0.nn)" become "#,##0.##;(#,##0.##)" return pattern.replace('n', '#'); } private static String getPattern(final int minDecimals) { final int pos = 4 - (minDecimals > 4 ? 4 : minDecimals); String d = StringUtils.fillString("", "#", pos); d = StringUtils.fillString(d, "0", 4); return "#,##0.".concat(d).concat(";(#,##0.").concat(d).concat(")"); } }