empty'void
empty'void

Reputation: 101

Parse an ISO 8601 date-time with optional fractional second using ICU

I used yyyy-MM-dd'T'HH:mm:ss.SSSXXX format string with icu::SimpleDateFormat.

Though it works for date-time strings with fractional digits. Examples:

2016-03-31T15:04:32.049Z

2016-03-31T15:04:32.05Z

2016-03-31T15:04:32.3Z

It doesn't parse strings without fractional second (e.g. 2016-03-31T15:08:51Z), returning an error code U_ILLEGAL_ARGUMENT_ERROR.

I tried some other format combinations to no avail: some fail with an error code, others ignore milliseconds.

Does ICU even support parsing of an optional fractional second?

Upvotes: 4

Views: 1902

Answers (1)

pe3k
pe3k

Reputation: 794

Going through ICU's documentation, I did not find any way how to input optional part in pattern specification.

However, this problem can be solved in many different ways on the application level. One of such ways (simplified) is using multiple datetime parsers as follows:

#include <iostream>
#include <vector>
#include "unicode/datefmt.h"
#include "unicode/smpdtfmt.h"

int main() {

    UErrorCode err(U_ZERO_ERROR);

    UnicodeString patternWithMilliseconds("yyyy-MM-dd'T'hh:mm:ss.SSSXXX");
    UnicodeString patternPlane("yyyy-MM-dd'T'hh:mm:ssX");

    // init ICU parsers
    std::vector<SimpleDateFormat*> parsers = {
            new SimpleDateFormat(patternWithMilliseconds, err),
            new SimpleDateFormat(patternPlane, err)
    };

    // get dates to convert
    std::vector<UnicodeString> dates = {
            UnicodeString("2016-03-31T15:04:32.049Z"),
            UnicodeString("2017-10-30T15:05:33Z"),
    };

    SimpleDateFormat resultFormatter(patternWithMilliseconds, err);

    for(const auto& date : dates) {

        UDate parsedDate;
        UnicodeString result;
        std::string resultConverted;

        for(const auto& parser : parsers) {
            err = U_ZERO_ERROR;
            parsedDate = parser->parse(date, err);
            if (err <= 0) break;
        }

        resultFormatter.format(parsedDate, result);
        result.toUTF8String(resultConverted);

        std::cout << resultConverted << std::endl;
    }

    for(auto& parser : parsers) {
        delete parser;
    }

    return 0;
}

Upvotes: 1

Related Questions