org.joda.time.format.PeriodFormatter Maven / Gradle / Ivy
Show all versions of virtdata-lib-realer Show documentation
/*
* Copyright 2001-2005 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.Locale;
import org.joda.time.MutablePeriod;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.ReadWritablePeriod;
import org.joda.time.ReadablePeriod;
/**
* Controls the printing and parsing of a time period to and from a string.
*
* This class is the main API for printing and parsing used by most applications.
* Instances of this class are created via one of three factory classes:
*
* - {@link PeriodFormat} - formats by pattern and style
* - {@link ISOPeriodFormat} - ISO8601 formats
* - {@link PeriodFormatterBuilder} - complex formats created via method calls
*
*
* An instance of this class holds a reference internally to one printer and
* one parser. It is possible that one of these may be null, in which case the
* formatter cannot print/parse. This can be checked via the {@link #isPrinter()}
* and {@link #isParser()} methods.
*
* The underlying printer/parser can be altered to behave exactly as required
* by using a decorator modifier:
*
* - {@link #withLocale(Locale)} - returns a new formatter that uses the specified locale
*
* This returns a new formatter (instances of this class are immutable).
*
* The main methods of the class are the printXxx
and
* parseXxx
methods. These are used as follows:
*
* // print using the default locale
* String periodStr = formatter.print(period);
* // print using the French locale
* String periodStr = formatter.withLocale(Locale.FRENCH).print(period);
*
* // parse using the French locale
* Period date = formatter.withLocale(Locale.FRENCH).parsePeriod(str);
*
*
* @author Brian S O'Neill
* @author Stephen Colebourne
* @since 1.0
*/
public class PeriodFormatter {
/** The internal printer used to output the datetime. */
private final PeriodPrinter iPrinter;
/** The internal parser used to output the datetime. */
private final PeriodParser iParser;
/** The locale to use for printing and parsing. */
private final Locale iLocale;
/** The period type used in parsing. */
private final PeriodType iParseType;
/**
* Creates a new formatter, however you will normally use the factory
* or the builder.
*
* @param printer the internal printer, null if cannot print
* @param parser the internal parser, null if cannot parse
*/
public PeriodFormatter(
PeriodPrinter printer, PeriodParser parser) {
super();
iPrinter = printer;
iParser = parser;
iLocale = null;
iParseType = null;
}
/**
* Constructor.
*
* @param printer the internal printer, null if cannot print
* @param parser the internal parser, null if cannot parse
* @param locale the locale to use
* @param type the parse period type
*/
PeriodFormatter(
PeriodPrinter printer, PeriodParser parser,
Locale locale, PeriodType type) {
super();
iPrinter = printer;
iParser = parser;
iLocale = locale;
iParseType = type;
}
//-----------------------------------------------------------------------
/**
* Is this formatter capable of printing.
*
* @return true if this is a printer
*/
public boolean isPrinter() {
return (iPrinter != null);
}
/**
* Gets the internal printer object that performs the real printing work.
*
* @return the internal printer
*/
public PeriodPrinter getPrinter() {
return iPrinter;
}
/**
* Is this formatter capable of parsing.
*
* @return true if this is a parser
*/
public boolean isParser() {
return (iParser != null);
}
/**
* Gets the internal parser object that performs the real parsing work.
*
* @return the internal parser
*/
public PeriodParser getParser() {
return iParser;
}
//-----------------------------------------------------------------------
/**
* Returns a new formatter with a different locale that will be used
* for printing and parsing.
*
* A PeriodFormatter is immutable, so a new instance is returned,
* and the original is unaltered and still usable.
*
* A null locale indicates that no specific locale override is in use.
*
* @param locale the locale to use
* @return the new formatter
*/
public PeriodFormatter withLocale(Locale locale) {
if (locale == getLocale() || (locale != null && locale.equals(getLocale()))) {
return this;
}
return new PeriodFormatter(iPrinter, iParser, locale, iParseType);
}
/**
* Gets the locale that will be used for printing and parsing.
*
* A null locale indicates that no specific locale override is in use.
*
* @return the locale to use
*/
public Locale getLocale() {
return iLocale;
}
//-----------------------------------------------------------------------
/**
* Returns a new formatter with a different PeriodType for parsing.
*
* A PeriodFormatter is immutable, so a new instance is returned,
* and the original is unaltered and still usable.
*
* @param type the type to use in parsing
* @return the new formatter
*/
public PeriodFormatter withParseType(PeriodType type) {
if (type == iParseType) {
return this;
}
return new PeriodFormatter(iPrinter, iParser, iLocale, type);
}
/**
* Gets the PeriodType that will be used for parsing.
*
* @return the parse type to use
*/
public PeriodType getParseType() {
return iParseType;
}
//-----------------------------------------------------------------------
/**
* Prints a ReadablePeriod to a StringBuffer.
*
* @param buf the formatted period is appended to this buffer
* @param period the period to format, not null
*/
public void printTo(StringBuffer buf, ReadablePeriod period) {
checkPrinter();
checkPeriod(period);
getPrinter().printTo(buf, period, iLocale);
}
/**
* Prints a ReadablePeriod to a Writer.
*
* @param out the formatted period is written out
* @param period the period to format, not null
*/
public void printTo(Writer out, ReadablePeriod period) throws IOException {
checkPrinter();
checkPeriod(period);
getPrinter().printTo(out, period, iLocale);
}
/**
* Prints a ReadablePeriod to a new String.
*
* @param period the period to format, not null
* @return the printed result
*/
public String print(ReadablePeriod period) {
checkPrinter();
checkPeriod(period);
PeriodPrinter printer = getPrinter();
StringBuffer buf = new StringBuffer(printer.calculatePrintedLength(period, iLocale));
printer.printTo(buf, period, iLocale);
return buf.toString();
}
/**
* Checks whether printing is supported.
*
* @throws UnsupportedOperationException if printing is not supported
*/
private void checkPrinter() {
if (iPrinter == null) {
throw new UnsupportedOperationException("Printing not supported");
}
}
/**
* Checks whether the period is non-null.
*
* @throws IllegalArgumentException if the period is null
*/
private void checkPeriod(ReadablePeriod period) {
if (period == null) {
throw new IllegalArgumentException("Period must not be null");
}
}
//-----------------------------------------------------------------------
/**
* Parses a period from the given text, at the given position, saving the
* result into the fields of the given ReadWritablePeriod. If the parse
* succeeds, the return value is the new text position. Note that the parse
* may succeed without fully reading the text.
*
* The parse type of the formatter is not used by this method.
*
* If it fails, the return value is negative, but the period may still be
* modified. To determine the position where the parse failed, apply the
* one's complement operator (~) on the return value.
*
* @param period a period that will be modified
* @param text text to parse
* @param position position to start parsing from
* @return new position, if negative, parse failed. Apply complement
* operator (~) to get position of failure
* @throws IllegalArgumentException if any field is out of range
*/
public int parseInto(ReadWritablePeriod period, String text, int position) {
checkParser();
checkPeriod(period);
return getParser().parseInto(period, text, position, iLocale);
}
/**
* Parses a period from the given text, returning a new Period.
*
* @param text text to parse
* @return parsed value in a Period object
* @throws IllegalArgumentException if any field is out of range
*/
public Period parsePeriod(String text) {
checkParser();
return parseMutablePeriod(text).toPeriod();
}
/**
* Parses a period from the given text, returning a new MutablePeriod.
*
* @param text text to parse
* @return parsed value in a MutablePeriod object
* @throws IllegalArgumentException if any field is out of range
*/
public MutablePeriod parseMutablePeriod(String text) {
checkParser();
MutablePeriod period = new MutablePeriod(0, iParseType);
int newPos = getParser().parseInto(period, text, 0, iLocale);
if (newPos >= 0) {
if (newPos >= text.length()) {
return period;
}
} else {
newPos = ~newPos;
}
throw new IllegalArgumentException(FormatUtils.createErrorMessage(text, newPos));
}
/**
* Checks whether parsing is supported.
*
* @throws UnsupportedOperationException if parsing is not supported
*/
private void checkParser() {
if (iParser == null) {
throw new UnsupportedOperationException("Parsing not supported");
}
}
}