# Class RangeFormat

Object
Format
RangeFormat

All Implemented Interfaces:
  `Serializable`, `Cloneable`, `Localized`

public class RangeFormat extends Format implements Localized
Parses and formats `Range` instances according the given locale. This class complies to the format described in the ISO 31-11 standard, except that the minimal and maximal values are separated by the "`…`" character instead of coma. More specifically, the format is defined as below:

- If the range is empty, then the range is represented by "`{}`".
- Otherwise if the minimal value is equal to the maximal value, then that single value is formatted inside braces as in "`{value}`".
- Otherwise the minimal and maximal values are formatted inside bracket or parenthesis, depending on whether each endpoint is inclusive or exclusive:
  - "`[min … max]`" if both endpoints are inclusive (closed interval);
  - "`(min … max)`" if both endpoints are exclusive (open interval);
  - or a mix of both styles if an endpoint is inclusive while the other is exclusive.
  The "`∞`" symbol is used in place of `min` or `max` for unbounded ranges.

If the range to format is an instance of `MeasurementRange`, then the unit of measurement is appended except for empty ranges.

## Lenient parsing

At parsing time, the above formatting rules are relaxed as below:

- Empty ranges can be represented by "`[]`"or "`()`" in addition to the standard "`{}`".
- The braces are optional for singleton values, i.e. "`value`" is accepted as well as "`{value}`".

## Range type and type of range elements

The kind of ranges created by the `parse(…)` methods is determined by the type of range elements:

- If the elements type is assignable to `Date`, then the `parse(…)` methods will create `Range<Date>` objects.
- If the elements type is assignable to `Number`, then:
  - If the text to parse contains a unit of measurement, then the `parse(…)` methods will create `MeasurementRange` objects.
  - Otherwise the `parse(…)` methods will create `NumberRange` objects.

Since:
  0.3
See Also:
  - `Range​.toString()`
  - Wikipedia: ISO 31-11
  - Serialized Form

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `static final class`
  `RangeFormat​.Field`
  Constants that are used as attribute keys in the iterator returned from `formatToCharacterIterator(Object)`.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final Format`
  `elementFormat`
  The format to use for parsing and formatting the range components.
  `protected final Class<?>`
  `elementType`
  The type of the range components.
  `protected final UnitFormat`
  `unitFormat`
  The format for unit of measurement, or `null` if none.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `RangeFormat()`
  Creates a new format for parsing and formatting number ranges using the default locale.
  `RangeFormat(Locale locale)`
  Creates a new format for parsing and formatting number ranges using the given locale.
  `RangeFormat(Locale locale, Class<?> elementType)`
  Creates a new format for parsing and formatting ranges of the given element type using the given locale.
  `RangeFormat(Locale locale, TimeZone timezone)`
  Creates a new format for parsing and formatting `Range<Date>` using the given locale and timezone.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `RangeFormat`
  `clone()`
  Returns a clone of this range format.
  `StringBuffer`
  `format(Object range, StringBuffer toAppendTo, FieldPosition pos)`
  Formats a `Range` and appends the resulting text to a given string buffer.
  `AttributedCharacterIterator`
  `formatToCharacterIterator(Object range)`
  Formats a range as an attributed character iterator.
  `String`
  `getElementPattern(boolean localized)`
  Returns the pattern used by `elementFormat` for formatting the minimum and maximum values.
  `Locale`
  `getLocale()`
  Returns this formatter locale.
  `static boolean`
  `hasDateFields(Class<?> date)`
  Returns `true` if objects of the given class have day, month and hour fields.
  `static boolean`
  `hasTimeFields(Class<?> date)`
  Returns `true` if objects of the given class have time fields.
  `boolean`
  `isAlternateForm()`
  Returns `true` if this `RangeFormat` shall use the alternate form at formatting time.
  `Range<?>`
  `parse(String source)`
  Parses text from the given string to produce a range.
  `Range<?>`
  `parse(String source, ParsePosition pos)`
  Parses text from a string to produce a range.
  `Object`
  `parseObject(String source)`
  Parses text from a string to produce a range.
  `Object`
  `parseObject(String source, ParsePosition pos)`
  Parses text from a string to produce a range.
  `void`
  `setAlternateForm(boolean alternateForm)`
  Sets whether this `RangeFormat` shall use the alternate form at formatting time.
  `void`
  `setElementPattern(String pattern, boolean localized)`
  Sets the pattern to be used by `elementFormat` for formatting the minimum and maximum values.

  ### Methods inherited from class Format

  `format`

  ### Methods inherited from class Object

  `equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### elementType

    protected final Class<?> elementType
    The type of the range components. Valid types are `Number`, `Angle`, `Date` or a subclass of those types. This value determines the kind of range to be created by the parse method:
    - `NumberRange<?>` if the element type is assignable to `Number` or `Angle`.
    - `Range<Date>` if the element type is assignable to `Date`.
    See Also:
      - `Range​.getElementType()`

  - ### elementFormat

    protected final Format elementFormat
    The format to use for parsing and formatting the range components. The format is determined from the element type:
    - `AngleFormat` if the element type is assignable to `Angle`.
    - `NumberFormat` if the element type is assignable to `Number`.
    - `DateFormat` if the element type is assignable to `Date`.

  - ### unitFormat

    protected final UnitFormat unitFormat
    The format for unit of measurement, or `null` if none. This is non-null if and only if `elementType` is assignable to `Number` but not to `Angle`.

- ## Constructor Details

  - ### RangeFormat

    public RangeFormat()
    Creates a new format for parsing and formatting number ranges using the default locale.

  - ### RangeFormat

    public RangeFormat(Locale locale)
    Creates a new format for parsing and formatting number ranges using the given locale.
    Parameters:
      `locale` - the locale for parsing and formatting range components.

  - ### RangeFormat

    public RangeFormat(Locale locale, TimeZone timezone)
    Creates a new format for parsing and formatting `Range<Date>` using the given locale and timezone.
    Parameters:
      `locale` - the locale for parsing and formatting range components.
      `timezone` - the timezone for the dates to be formatted.

  - ### RangeFormat

    public RangeFormat(Locale locale, Class<?> elementType) throws IllegalArgumentException
    Creates a new format for parsing and formatting ranges of the given element type using the given locale. The element type is typically `Date​.class` or some subclass of `Number​.class`.
    Parameters:
      `locale` - the locale for parsing and formatting range components.
      `elementType` - the type of range components.
    Throws:
      `IllegalArgumentException` - if the given type is not recognized by this constructor.

- ## Method Details

  - ### hasDateFields

    public static boolean hasDateFields(Class<?> date)
    Returns `true` if objects of the given class have day, month and hour fields. This method is defined here for having a single class where to concentrate such heuristic rules. Note that `Instant` does not have date fields.
    Parameters:
      `date` - class of object to test (may be `null`).
    Returns:
      whether the given class is `LocalDate` or one of the classes with date + time. This list may be expanded in future versions.

  - ### hasTimeFields

    public static boolean hasTimeFields(Class<?> date)
    Returns `true` if objects of the given class have time fields. This method is defined here for having a single class where to concentrate such heuristic rules. Note that `Instant` does not have hour fields.
    Parameters:
      `date` - class of object to test (may be `null`).
    Returns:
      whether the given class is `LocalTime`, `OffsetTime` or one of the classes with date + time. This list may be expanded in future versions.

  - ### getLocale

    public Locale getLocale()
    Returns this formatter locale. This is the locale specified at construction time if any, or the default locale at construction time otherwise.
    Specified by:
      `getLocale` in interface `Localized`
    Returns:
      this formatter locale (never `null`).
    Since:
      1.0

  - ### getElementPattern

    public String getElementPattern(boolean localized)
    Returns the pattern used by `elementFormat` for formatting the minimum and maximum values. If the element format does not use pattern, returns `null`.
    Parameters:
      `localized` - `true` for returning the localized pattern, or `false` for the unlocalized one.
    Returns:
      the pattern, or `null` if the `elementFormat` doesn't use pattern.
    See Also:
      - `DecimalFormat​.toPattern()`
      - `SimpleDateFormat​.toPattern()`
      - `AngleFormat​.toPattern()`

  - ### setElementPattern

    public void setElementPattern(String pattern, boolean localized)
    Sets the pattern to be used by `elementFormat` for formatting the minimum and maximum values.
    Parameters:
      `pattern` - the new pattern.
      `localized` - `true` if the given pattern is localized.
    Throws:
      `IllegalStateException` - if the `elementFormat` does not use pattern.
    See Also:
      - `DecimalFormat​.applyPattern(String)`
      - `SimpleDateFormat​.applyPattern(String)`
      - `AngleFormat​.applyPattern(String)`

  - ### isAlternateForm

    public boolean isAlternateForm()
    Returns `true` if this `RangeFormat` shall use the alternate form at formatting time. The alternate form expresses open intervals like `]a…b[` instead of `(a…b)`.

    This flag has no effect on parsing, since the parser accepts both forms.

    Returns:
      `true` for using the alternate format instead of the default format.

  - ### setAlternateForm

    public void setAlternateForm(boolean alternateForm)
    Sets whether this `RangeFormat` shall use the alternate form at formatting time. The alternate form expresses open intervals like `]a…b[` instead of `(a…b)`.
    Parameters:
      `alternateForm` - `true` for using the alternate format, or `false` for using the default format.

  - ### format

    public StringBuffer format(Object range, StringBuffer toAppendTo, FieldPosition pos)
    Formats a `Range` and appends the resulting text to a given string buffer. See the class javadoc for a description of the format.
    Specified by:
      `format` in class `Format`
    Parameters:
      `range` - the `Range` object to format.
      `toAppendTo` - where the text is to be appended.
      `pos` - identifies a field in the formatted text, or `null` if none.
    Returns:
      the string buffer passed in as `toAppendTo`, with formatted text appended.
    Throws:
      `IllegalArgumentException` - if this formatter cannot format the given object.

  - ### formatToCharacterIterator

    public AttributedCharacterIterator formatToCharacterIterator(Object range)
    Formats a range as an attributed character iterator. Callers can iterate and queries the attribute values as in the following example:

        AttributedCharacterIterator it = rangeFormat.formatToCharacterIterator(myRange);
        for (char c=it.first(); c!=AttributedCharacterIterator.DONE; c=c.next()) {
            // 'c' is a character from the formatted string.
            if (it.getAttribute(RangeFormat.Field.MIN_VALUE) != null) {
                // If we enter this block, then the character 'c' is part of the minimal value,
                // This field extends from it.getRunStart(MIN_VALUE) to it.getRunLimit(MIN_VALUE).
            }
        }

    Alternatively, if the current iterator index is before the start of the minimum value field, then the starting position of that field can be obtained directly by `it​.getRunLimit(MIN_VALUE)`. If the current iterator index is inside the minimum value field, then the above method call will rather returns the end of that field. The same strategy works for other all fields too.

    The returned character iterator contains all `NumberFormat​.Field`, `DateFormat​.Field` or `AngleFormat​.Field` attributes in addition to the `RangeFormat​.Field` ones. Consequently, the same character may have more than one attribute.

    In Apache SIS implementation, the returned character iterator also implements the `CharSequence` interface for convenience.

    Overrides:
      `formatToCharacterIterator` in class `Format`
    Parameters:
      `range` - the `Range` object to format.
    Returns:
      a character iterator together with the attributes describing the formatted value.
    Throws:
      `IllegalArgumentException` - if `value` if not an instance of `Range`.

  - ### parseObject

    public Object parseObject(String source) throws ParseException
    Parses text from a string to produce a range. The default implementation delegates to `parse(String)` with no additional work.
    Overrides:
      `parseObject` in class `Format`
    Parameters:
      `source` - the text, part of which should be parsed.
    Returns:
      a range parsed from the string.
    Throws:
      `ParseException` - if the given string cannot be fully parsed.

  - ### parseObject

    public Object parseObject(String source, ParsePosition pos)
    Parses text from a string to produce a range. The default implementation delegates to `parse(String, ParsePosition)` with no additional work.
    Specified by:
      `parseObject` in class `Format`
    Parameters:
      `source` - the text, part of which should be parsed.
      `pos` - index and error index information as described above.
    Returns:
      a range parsed from the string, or `null` in case of error.

  - ### parse

    public Range<?> parse(String source) throws ParseException
    Parses text from the given string to produce a range. This method use the full string. If there is some unparsed characters after the parsed range, then this method thrown an exception.
    Parameters:
      `source` - the text to parse.
    Returns:
      the parsed range (never `null`).
    Throws:
      `ParseException` - if the given string cannot be fully parsed.

  - ### parse

    public Range<?> parse(String source, ParsePosition pos)
    Parses text from a string to produce a range. The method attempts to parse text starting at the index given by `pos`. If parsing succeeds, then the index of `pos` is updated to the index after the last character used, and the parsed range is returned. If an error occurs, then the index of `pos` is not changed, the error index of `pos` is set to the index of the character where the error occurred, and `null` is returned.
    Parameters:
      `source` - the text, part of which should be parsed.
      `pos` - index and error index information as described above.
    Returns:
      a range parsed from the string, or `null` in case of error.

  - ### clone

    public RangeFormat clone()
    Returns a clone of this range format.
    Overrides:
      `clone` in class `Format`
    Returns:
      a clone of this range format.