Class DateTimeFormatterXSD


  • public class DateTimeFormatterXSD
    extends Object
    Formatter-Parsers for XML Schema types xs:date, xs:dateTime and xs:time.

    Predefined Formatter-Parsers for these value types are not included in the JDK.

    It it not uncommon that XML documents (or JSON documents) use a format for date and time values which is aligned with ISO-8601, but do not (strictly) conform to the XML Schema Specification. The former allows much more freedom than the latter. Freedom in the case of data interchange between two parties is a really bad idea. This is why the XML Schema Specification in this respect is superior to the ISO-8601 specification.

    While it is sad that the XML Schema Specification is sometimes not strictly followed in XML and JSON documents it is nevertheless a reality. For this reason, this class has predefined parsers which are lenient and therefore strictly speaking do not conform to the XML Schema Specification. However, only unambiguous deviations are accepted while parsing.

    The closest JDK equivalent to xs:dateTime, xs:date and xs:time are OffsetDateTime and OffsetTime. However, the XML Schema data types do not mandate the presence of the timezone offset and therefore they have no direct equivalent in the JDK.

    Predefined Formatters-Parsers overview

    Predefined Formatters
    Formatter Usage Description Examples
    XSD_DATETIME_PARSER Parsing For xs:dateTime lenient parsing '2018-12-03T10:15:30+01:00'
    '2018-12-03 10:15:30+01:00'
    '2018-12-03T10:15:30+01'
    '2018-12-03t10:15:30+01'
    '2018-12-03T10:15:30Z'
    '2018-12-03T10:15:30z'
    XSD_DATETIME Parsing
    Formatting
    For xs:dateTime formatting or strict parsing '2018-12-03T10:15:30+01:00'
    '2018-12-03T10:15:30Z'
    XSD_DATE_PARSER Parsing For xs:date lenient parsing '2018-12-03+01:00'
    '2018-12-03+01'
    '2018-12-03Z'
    '2018-12-03z'
    XSD_DATE Parsing
    Formatting
    For xs:date formatting or strict parsing '2018-12-03+01:00'
    '2018-12-03Z'
    XSD_TIME_PARSER Parsing For xs:time lenient parsing '10:15:30+01:00'
    '10:15:30+01'
    '10:15:30Z'
    '10:15:30z'
    XSD_TIME Parsing
    Formatting
    For xs:time formatting or strict parsing '10:15:30+01:00'
    '10:15:30Z'

    Parsing

    This class also provides convenience methods for parsing XML Schema date/time string values into their best match JDK class.
    See Also:
    XML Schema Specification.
    • Field Detail

      • XSD_DATETIME_PARSER

        public static final DateTimeFormatter XSD_DATETIME_PARSER
        For lenient parsing values of type xs:dateTime.

        This Formatter-Parser is suitable only for parsing, not for formatting. When used for formatting it may produce values which are not compliant with the specification for xs:dateTime. Instead XSD_DATETIME should be used for formatting.

        Lenient parsing is performed, meaning that certain non-compliant formats are accepted. These formats should not be encouraged but are accepted by this parser as a pragmatic compromise. Compared to the formal definition of xs:dateTime the following is accepted while parsing:

        • In the time value the seconds field may be omitted. Hence "2019-03-12T14:45Z" is an acceptable value. The formal specification mandates that the seconds field is present, even if zero.
        • The delimiter between the date and the time value may be a 'T' or a ' ' (space). The formal definition only allows a 'T'.
        • Literals in the string, i.e. 'T' and 'Z', are accepted regardless of upper/lower-case. The formal specification mandates that these are in upper-case.
        • If a time zone offset is specified it doesn't have to include minutes, meaning that "+05" is an acceptable value for an offset. The formal definition mandates that the minutes must be specified, i.e. "+05:00".
        • Trailing zeroes in the fractional second is acceptable, meaning that a value such as "2019-03-12T14:45:28.340Z" will be accepted. The formal specification says "the fractional second string, if present, must not end in '0'".

        Parsing
        There are two methods for parsing a string into an OffsetDateTime depending on your scenario:

        1. Use the static parse() method on this class. This method gracefully handles the situation where there are more then 9 digits on the seconds fractional value.
        2. Creating a new DateTimeFormatter based on this one, but with a default ZoneId which is used during parsing if none is provided in the input.
                     // This only need to be created once and can be re-used
                     // (DateTimeFormatters are immutable and thread-safe)
                     DateTimeFormatter dtf = DateTimeFormatterXSD.XSD_DATETIME_PARSER.withZone(ZoneId.of("America/New_York"));
                     // Parse the string value. Since no offset is given in the input, the New York TZ is assumed.
                     OffsetDateTime value = dtf.parse("2018-03-19:22:35:58", OffsetDateTime::from);
                  

        Compliance

        • Formatting: Should not be used for formatting.
        • Parsing: Compliant with the formal definition for xs:dateTme, except for:
          • A number of formally incorrect forms are accepted as explained above.
          • The seconds fraction field may contain no more than 9 digits. In the formal definition, the seconds fractional field has "arbitrary level of precision". This implementation will throw DateTimeParseException if the input has more than 9 fractional digits. If this is a problem then parseIntoOffsetDateTime() can be used.
        See Also:
        https://www.w3.org/TR/xmlschema-2/#dateTime
      • XSD_DATETIME

        public static final DateTimeFormatter XSD_DATETIME
        For parsing and formatting of xs:dateTime values as defined in XML Schema..

        This Formatter-Parser is suitable for both parsing and formatting. When used as a formatter it produces output compliant with the specification for xs:dateTime. When used as a parser it mandates strict compliance with the specification for xs:dateTime. In most scenarios, XSD_DATETIME_PARSER is probably a better fit for parsing as it is more forgiving.

        Compliance

        • Formatting: Produces output fully compliant with formal definition for xs:dateTime assuming that a OffsetDateTime or LocalDateTime is used as input.
        • Parsing: Compliant with the formal definition for xs:dateTime, except for:
          • The seconds fraction field may contain no more than 9 digits. In the formal definition, the seconds fractional field has "arbitrary level of precision". This implementation will throw DateTimeParseException if the input has more than 9 fractional digits.
          • Trailing zeroes in the fractional second is acceptable, meaning that a value such as "2019-03-12T14:45:28.340Z" will be accepted. The formal specification says "the fractional second string, if present, must not end in '0'".
        See Also:
        https://www.w3.org/TR/xmlschema-2/#dateTime
      • XSD_DATE_PARSER

        public static final DateTimeFormatter XSD_DATE_PARSER
        For lenient parsing values of type xs:date.

        This Formatter-Parser is suitable only for parsing, not for formatting. Instead XSD_DATE should be used for formatting.

        Lenient parsing is performed, meaning that certain non-compliant formats are accepted. These formats should not be encouraged but are accepted by this parser as a pragmatic compromise. Compared to the formal definition of xs:date the following is accepted while parsing:

        • The literal 'Z' in a timezone offset is accepted both in upper- and lower-case.
        • If a time zone offset is specified it doesn't have to include minutes, meaning that '+05' is an acceptable value. The formal definition mandates that the minutes must be specified, i.e. '+05:00'.

        Parsing
        There are two methods for parsing a date string into an OffsetDate/OffsetDateTime depending on your scenario:

        1. Use either of the static methods: on this class.
        2. Creating a new DateTimeFormatter based on this one, but with a default ZoneId which is used during parsing if none is provided in the input.
                     // This only need to be created once and can be re-used
                     // (DateTimeFormatters are immutable and thread-safe)
                     DateTimeFormatter dtf = DateTimeFormatterXSD.XSD_DATE_PARSER.withZone(ZoneId.of("America/New_York"));
                     // Parse the string value. Since no offset is given in the input, the New York TZ is assumed.
                     OffsetDate value = dtf.parse("2018-03-19", OffsetDate::from);
                  

        Compliance

        • Formatting: Should not be used for formatting.
        • Parsing: Compliant with the formal definition for xs:date, except for the forms accepted during parsing as listed above.
        See Also:
        https://www.w3.org/TR/xmlschema-2/#date
      • XSD_DATE

        public static final DateTimeFormatter XSD_DATE
        For parsing and formatting of xs:date values as defined in XML Schema.

        This Formatter-Parser is suitable for both parsing and formatting. When used as a formatter it produces output compliant with the specification for xs:date. When used as a parser it mandates strict compliance with the specification for xs:date. In most scenarios, XSD_DATE_PARSER is probably a better fit for parsing as it is more forgiving.

        Compliance

        • Formatting: Produces output fully compliant with the formal definition for xs:date assuming that a OffsetDateTime or LocalDate is used as input.
        • Parsing: Compliant with the formal definition for xs:date.
        See Also:
        https://www.w3.org/TR/xmlschema-2/#date
      • XSD_TIME_PARSER

        public static final DateTimeFormatter XSD_TIME_PARSER
        For lenient parsing values of type xs:time.

        This Formatter-Parser is suitable only for parsing, not for formatting. Instead XSD_TIME should be used for formatting.

        Lenient parsing is performed, meaning that certain non-compliant formats are accepted. These formats should not be encouraged but are accepted by this parser as a pragmatic compromise. Compared to the formal definition of xs:time the following is accepted while parsing:

        • In the time value the seconds field may be omitted. Hence "14:45Z" is an acceptable value. The formal specification mandates that the seconds field is present, even if zero.
        • The literal 'Z' in a timezone offset is accepted both in upper- and lower-case.
        • If a time zone offset is specified it doesn't have to include minutes, meaning that '+05' is an acceptable value. The formal definition mandates that the minutes must be specified, i.e. '+05:00'.
        • Trailing zeroes in the fractional second is acceptable, meaning that a value such as "2019-03-12T14:45:28.340Z" will be accepted. The formal specification says "the fractional second string, if present, must not end in '0'".

        Parsing
        There are two methods for parsing a string into an OffsetTime depending on your scenario:

        1. Use the static parse() on this class. This method gracefully handles the situation where there are more then 9 digits on the seconds fractional value.
        2. Creating a new DateTimeFormatter based on this one, but with a default ZoneId which is used during parsing if none is provided in the input.
                     // This only need to be created once and can be re-used
                     // (DateTimeFormatters are immutable and thread-safe)
                     DateTimeFormatter dtf = DateTimeFormatterXSD.XSD_TIME_PARSER.withZone(ZoneId.of("America/New_York"));
                     // Parse the string value. Since no offset is given in the input, the New York TZ is assumed.
                     OffsetTime value = dtf.parse("22:33:58", OffsetTime::from);
                  

        Compliance

        • Formatting: Should not be used for formatting.
        • Parsing: Compliant with the formal definition for xs:time, except for:
          • A number of formally incorrect forms are accepted as explained above.
          • The seconds fraction field may contain no more than 9 digits. In the formal definition, the seconds fractional field has "arbitrary level of precision". This implementation will throw DateTimeParseException if the input has more than 9 fractional digits. If this is a problem then parseIntoOffsetTime() can be used.
        See Also:
        https://www.w3.org/TR/xmlschema-2/#time
      • XSD_TIME

        public static final DateTimeFormatter XSD_TIME
        For parsing and formatting of xs:time values as defined in XML Schema.

        This Formatter-Parser is suitable for both parsing and formatting. When used as a formatter it produces output compliant with the specification for xs:time. When used as a parser it mandates strict compliance with the specification for xsdtime. In most scenarios, XSD_TIME_PARSER is probably a better fit for parsing as it is more forgiving.

        Compliance

        • Formatting: Produces output fully compliant with formal definition for xs:time assuming that a OffsetTime or LocalTime is used as input.
        • Parsing: Compliant with the formal definition for xs:time, except for:
          • The seconds fraction field may contain no more than 9 digits. In the formal definition, the seconds fractional field has "arbitrary level of precision". This implementation will throw DateTimeParseException if the input has more than 9 fractional digits.
          • Trailing zeroes in the fractional second is acceptable, meaning that a value such as "2019-03-12T14:45:28.340Z" will be accepted. The formal specification says "the fractional second string, if present, must not end in '0'".
        See Also:
        https://www.w3.org/TR/xmlschema-2/#time
    • Method Detail

      • parseIntoOffsetDateTime

        public static OffsetDateTime parseIntoOffsetDateTime​(String str,
                                                             Function<LocalDateTime,​ZoneOffset> zoneOffsetProvider)
        Parses a xs:dateTime string into an OffsetDateTime. For example a string on the form "2018-12-03T10:15:30+01:00" (value with offset) or "2018-12-03T10:15:30" (value without offset).

        The string is parsed using XSD_DATETIME_PARSER which is forgiving and accepts minor deviations from the official specification.

        Furthermore, parsing is attempted in a two-step procedure: If first parsing attempt fails the method will evaluate if the problem is something which can likely be fixed and if so it will "fix" the input value, str, and perform a new parsing attempt.

        Parameters:
        str - the string to parse
        zoneOffsetProvider - a function which will be called if no zone offset is present in the temporal.
        Returns:
        parsed value
        Throws:
        DateTimeParseException - if unable to parse the string
      • parseIntoOffsetDate

        public static OffsetDate parseIntoOffsetDate​(String str,
                                                     Function<LocalDate,​ZoneOffset> zoneOffsetProvider)
        Parses a xs:date string into an OffsetDate. For example a string on the form "2018-12-03+01:00" (value with offset) or "2018-12-03" (value without offset).

        The string is parsed using XSD_DATE_PARSER which is forgiving and accepts minor deviations from the official specification.

        Parameters:
        str - the string to parse
        zoneOffsetProvider - a function which will be called if no zone offset is present in the input string.
        Returns:
        parsed value
        Throws:
        DateTimeParseException - if unable to parse the string
      • parseIntoOffsetDateTimeNoTime

        public static OffsetDateTime parseIntoOffsetDateTimeNoTime​(String str,
                                                                   Function<LocalDate,​ZoneOffset> zoneOffsetProvider)
        Parses a xs:date string into an OffsetDateTime. For example a string on the form "2018-12-03+01:00" (value with offset) or "2018-12-03" (value without offset).

        The string is parsed using XSD_DATE_PARSER which is forgiving and accepts minor deviations from the official specification.

        Parameters:
        str - the string to parse
        zoneOffsetProvider - a function which will be called if no zone offset is present in the input string.
        Returns:
        parsed value (with "no" time value, meaning time value is set to midnight)
        Throws:
        DateTimeParseException - if unable to parse the string
      • parseIntoOffsetTime

        public static OffsetTime parseIntoOffsetTime​(String str,
                                                     Function<LocalTime,​ZoneOffset> zoneOffsetProvider)
        Parses a xs:time string into an OffsetTime. For example a string on the form "10:15:30+01:00" (value with offset) or "10:15:30" (value without offset).

        The string is parsed using XSD_TIME_PARSER which is forgiving and accepts minor deviations from the official specification.

        Furthermore, parsing is attempted in a two-step procedure: If first parsing attempt fails the method will evaluate if the problem is something which can likely be fixed and if so it will "fix" the input value, str, and perform a new parsing attempt.

        Parameters:
        str - the string to parse
        zoneOffsetProvider - a function which will be called if no zone offset is present in the input string.
        Returns:
        parsed value
        Throws:
        DateTimeParseException - if unable to parse the string