All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joda.time.format.PeriodFormat Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright 2001-2014 Stephen Colebourne
 *
 *  Licensed 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.joda.time.format;

import java.io.IOException;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.joda.time.ReadWritablePeriod;
import org.joda.time.ReadablePeriod;

/**
 * Factory that creates instances of PeriodFormatter.
 * 

* Period formatting is performed by the {@link PeriodFormatter} class. * Three classes provide factory methods to create formatters, and this is one. * The others are {@link ISOPeriodFormat} and {@link PeriodFormatterBuilder}. *

* PeriodFormat is thread-safe and immutable, and the formatters it returns * are as well. * * @author Brian S O'Neill * @since 1.0 * @see ISOPeriodFormat * @see PeriodFormatterBuilder */ public class PeriodFormat { /** * The resource bundle name. */ private static final String BUNDLE_NAME = "org.joda.time.format.messages"; /** * The created formatters. */ private static final ConcurrentMap FORMATTERS = new ConcurrentHashMap(); /** * Constructor. * * @since 1.1 (previously private) */ protected PeriodFormat() { super(); } //----------------------------------------------------------------------- /** * Gets the default formatter that outputs words in English. *

* This calls {@link #wordBased(Locale)} using a locale of {@code ENGLISH}. * * @return the formatter, not null */ public static PeriodFormatter getDefault() { return wordBased(Locale.ENGLISH); } /** * Returns a word based formatter for the JDK default locale. *

* This calls {@link #wordBased(Locale)} using the {@link Locale#getDefault() default locale}. * * @return the formatter, not null * @since 2.0 */ public static PeriodFormatter wordBased() { return wordBased(Locale.getDefault()); } /** * Returns a word based formatter for the specified locale. *

* The words are configured in a resource bundle text file - * {@code org.joda.time.format.messages}. * This can be added to via the normal classpath resource bundle mechanisms. *

* You can add your own translation by creating messages_.properties file * and adding it to the {@code org.joda.time.format.messages} path. *

* Simple example (1 -> singular suffix, not 1 -> plural suffix): * *

     * PeriodFormat.space=\ 
     * PeriodFormat.comma=,
     * PeriodFormat.commandand=,and 
     * PeriodFormat.commaspaceand=, and 
     * PeriodFormat.commaspace=, 
     * PeriodFormat.spaceandspace=\ and 
     * PeriodFormat.year=\ year
     * PeriodFormat.years=\ years
     * PeriodFormat.month=\ month
     * PeriodFormat.months=\ months
     * PeriodFormat.week=\ week
     * PeriodFormat.weeks=\ weeks
     * PeriodFormat.day=\ day
     * PeriodFormat.days=\ days
     * PeriodFormat.hour=\ hour
     * PeriodFormat.hours=\ hours
     * PeriodFormat.minute=\ minute
     * PeriodFormat.minutes=\ minutes
     * PeriodFormat.second=\ second
     * PeriodFormat.seconds=\ seconds
     * PeriodFormat.millisecond=\ millisecond
     * PeriodFormat.milliseconds=\ milliseconds
     * 
* *

* Some languages contain more than two suffixes. You can use regular expressions * for them. Here's an example using regular expression for English: * *

     * PeriodFormat.space=\ 
     * PeriodFormat.comma=,
     * PeriodFormat.commandand=,and 
     * PeriodFormat.commaspaceand=, and 
     * PeriodFormat.commaspace=, 
     * PeriodFormat.spaceandspace=\ and 
     * PeriodFormat.regex.separator=%
     * PeriodFormat.years.regex=1$%.*
     * PeriodFormat.years.list=\ year%\ years
     * PeriodFormat.months.regex=1$%.*
     * PeriodFormat.months.list=\ month%\ months
     * PeriodFormat.weeks.regex=1$%.*
     * PeriodFormat.weeks.list=\ week%\ weeks
     * PeriodFormat.days.regex=1$%.*
     * PeriodFormat.days.list=\ day%\ days
     * PeriodFormat.hours.regex=1$%.*
     * PeriodFormat.hours.list=\ hour%\ hours
     * PeriodFormat.minutes.regex=1$%.*
     * PeriodFormat.minutes.list=\ minute%\ minutes
     * PeriodFormat.seconds.regex=1$%.*
     * PeriodFormat.seconds.list=\ second%\ seconds
     * PeriodFormat.milliseconds.regex=1$%.*
     * PeriodFormat.milliseconds.list=\ millisecond%\ milliseconds
     * 
* *

* You can mix both approaches. Here's example for Polish ( * "1 year, 2 years, 5 years, 12 years, 15 years, 21 years, 22 years, 25 years" * translates to * "1 rok, 2 lata, 5 lat, 12 lat, 15 lat, 21 lat, 22 lata, 25 lat"). Notice that * PeriodFormat.day and PeriodFormat.days is used for day suffixes as there is no * need for regular expressions: * *

     * PeriodFormat.space=\ 
     * PeriodFormat.comma=,
     * PeriodFormat.commandand=,i 
     * PeriodFormat.commaspaceand=, i 
     * PeriodFormat.commaspace=, 
     * PeriodFormat.spaceandspace=\ i 
     * PeriodFormat.regex.separator=%
     * PeriodFormat.years.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.years.list=\ rok%\ lata%\ lat
     * PeriodFormat.months.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.months.list=\ miesi\u0105c%\ miesi\u0105ce%\ miesi\u0119cy
     * PeriodFormat.weeks.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.weeks.list=\ tydzie\u0144%\ tygodnie%\ tygodni
     * PeriodFormat.day=\ dzie\u0144
     * PeriodFormat.days=\ dni
     * PeriodFormat.hours.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.hours.list=\ godzina%\ godziny%\ godzin
     * PeriodFormat.minutes.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.minutes.list=\ minuta%\ minuty%\ minut
     * PeriodFormat.seconds.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.seconds.list=\ sekunda%\ sekundy%\ sekund
     * PeriodFormat.milliseconds.regex=^1$%[0-9]*(?<!1)[2-4]$%[0-9]*
     * PeriodFormat.milliseconds.list=\ milisekunda%\ milisekundy%\ milisekund
     * 
* *

* Each PeriodFormat.<duration_field_type>.regex property stands for an array of * regular expressions and is followed by a property * PeriodFormat.<duration_field_type>.list holding an array of suffixes. * PeriodFormat.regex.separator is used for splitting. See * {@link PeriodFormatterBuilder#appendSuffix(String[], String[])} for details. *

* Available languages are English, Danish, Dutch, French, German, Japanese, * Polish, Portuguese and Spanish. * * @return the formatter, not null * @since 2.0, regex since 2.5 */ public static PeriodFormatter wordBased(Locale locale) { PeriodFormatter pf = FORMATTERS.get(locale); if (pf == null) { DynamicWordBased dynamic = new DynamicWordBased(buildWordBased(locale)); pf = new PeriodFormatter(dynamic, dynamic, locale, null); PeriodFormatter existing = FORMATTERS.putIfAbsent(locale, pf); if (existing != null) { pf = existing; } } return pf; } //----------------------------------------------------------------------- private static PeriodFormatter buildWordBased(Locale locale) { ResourceBundle b = ResourceBundle.getBundle(BUNDLE_NAME, locale); if (containsKey(b, "PeriodFormat.regex.separator")) { return buildRegExFormatter(b, locale); } else { return buildNonRegExFormatter(b, locale); } } private static PeriodFormatter buildRegExFormatter(ResourceBundle b, Locale locale) { String[] variants = retrieveVariants(b); String regExSeparator = b.getString("PeriodFormat.regex.separator"); PeriodFormatterBuilder builder = new PeriodFormatterBuilder(); builder.appendYears(); if (containsKey(b, "PeriodFormat.years.regex")) { builder.appendSuffix( b.getString("PeriodFormat.years.regex").split(regExSeparator), b.getString("PeriodFormat.years.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.year"), b.getString("PeriodFormat.years")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendMonths(); if (containsKey(b, "PeriodFormat.months.regex")) { builder.appendSuffix( b.getString("PeriodFormat.months.regex").split(regExSeparator), b.getString("PeriodFormat.months.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.month"), b.getString("PeriodFormat.months")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendWeeks(); if (containsKey(b, "PeriodFormat.weeks.regex")) { builder.appendSuffix( b.getString("PeriodFormat.weeks.regex").split(regExSeparator), b.getString("PeriodFormat.weeks.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.week"), b.getString("PeriodFormat.weeks")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendDays(); if (containsKey(b, "PeriodFormat.days.regex")) { builder.appendSuffix( b.getString("PeriodFormat.days.regex").split(regExSeparator), b.getString("PeriodFormat.days.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.day"), b.getString("PeriodFormat.days")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendHours(); if (containsKey(b, "PeriodFormat.hours.regex")) { builder.appendSuffix( b.getString("PeriodFormat.hours.regex").split(regExSeparator), b.getString("PeriodFormat.hours.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.hour"), b.getString("PeriodFormat.hours")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendMinutes(); if (containsKey(b, "PeriodFormat.minutes.regex")) { builder.appendSuffix( b.getString("PeriodFormat.minutes.regex").split(regExSeparator), b.getString("PeriodFormat.minutes.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.minute"), b.getString("PeriodFormat.minutes")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendSeconds(); if (containsKey(b, "PeriodFormat.seconds.regex")) { builder.appendSuffix( b.getString("PeriodFormat.seconds.regex").split(regExSeparator), b.getString("PeriodFormat.seconds.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.second"), b.getString("PeriodFormat.seconds")); } builder.appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants); builder.appendMillis(); if (containsKey(b, "PeriodFormat.milliseconds.regex")) { builder.appendSuffix( b.getString("PeriodFormat.milliseconds.regex").split(regExSeparator), b.getString("PeriodFormat.milliseconds.list").split(regExSeparator)); } else { builder.appendSuffix(b.getString("PeriodFormat.millisecond"), b.getString("PeriodFormat.milliseconds")); } return builder.toFormatter().withLocale(locale); } private static PeriodFormatter buildNonRegExFormatter(ResourceBundle b, Locale locale) { String[] variants = retrieveVariants(b); return new PeriodFormatterBuilder() .appendYears() .appendSuffix(b.getString("PeriodFormat.year"), b.getString("PeriodFormat.years")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendMonths() .appendSuffix(b.getString("PeriodFormat.month"), b.getString("PeriodFormat.months")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendWeeks() .appendSuffix(b.getString("PeriodFormat.week"), b.getString("PeriodFormat.weeks")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendDays() .appendSuffix(b.getString("PeriodFormat.day"), b.getString("PeriodFormat.days")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendHours() .appendSuffix(b.getString("PeriodFormat.hour"), b.getString("PeriodFormat.hours")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendMinutes() .appendSuffix(b.getString("PeriodFormat.minute"), b.getString("PeriodFormat.minutes")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendSeconds() .appendSuffix(b.getString("PeriodFormat.second"), b.getString("PeriodFormat.seconds")) .appendSeparator(b.getString("PeriodFormat.commaspace"), b.getString("PeriodFormat.spaceandspace"), variants) .appendMillis() .appendSuffix(b.getString("PeriodFormat.millisecond"), b.getString("PeriodFormat.milliseconds")) .toFormatter().withLocale(locale); } private static String[] retrieveVariants(ResourceBundle b) { return new String[] { b.getString("PeriodFormat.space"), b.getString("PeriodFormat.comma"), b.getString("PeriodFormat.commandand"), b.getString("PeriodFormat.commaspaceand") }; } // simulate ResourceBundle.containsKey() private static boolean containsKey(ResourceBundle bundle, String key) { for (Enumeration en = bundle.getKeys(); en.hasMoreElements(); ) { if (en.nextElement().equals(key)) { return true; } } return false; } //----------------------------------------------------------------------- /** * Printer/parser that reacts to the locale and changes the word-based * pattern if necessary. */ static class DynamicWordBased implements PeriodPrinter, PeriodParser { /** The formatter with the locale selected at construction time. */ private final PeriodFormatter iFormatter; DynamicWordBased(PeriodFormatter formatter) { iFormatter = formatter; } public int countFieldsToPrint(ReadablePeriod period, int stopAt, Locale locale) { return getPrinter(locale).countFieldsToPrint(period, stopAt, locale); } public int calculatePrintedLength(ReadablePeriod period, Locale locale) { return getPrinter(locale).calculatePrintedLength(period, locale); } public void printTo(StringBuffer buf, ReadablePeriod period, Locale locale) { getPrinter(locale).printTo(buf, period, locale); } public void printTo(Writer out, ReadablePeriod period, Locale locale) throws IOException { getPrinter(locale).printTo(out, period, locale); } private PeriodPrinter getPrinter(Locale locale) { if (locale != null && !locale.equals(iFormatter.getLocale())) { return wordBased(locale).getPrinter(); } return iFormatter.getPrinter(); } public int parseInto( ReadWritablePeriod period, String periodStr, int position, Locale locale) { return getParser(locale).parseInto(period, periodStr, position, locale); } private PeriodParser getParser(Locale locale) { if (locale != null && !locale.equals(iFormatter.getLocale())) { return wordBased(locale).getParser(); } return iFormatter.getParser(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy