Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Date parsing issue with Arabic and regular date in Java

Tags:

I have a date converter function like:

public static LocalDate getLocalDateFromString(String dateString) {
    DecimalStyle defaultDecimalStyle = DateTimeFormatter.ISO_LOCAL_DATE.getDecimalStyle();
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE.withDecimalStyle(defaultDecimalStyle.withZeroDigit('\u0660'));
    LocalDate date = LocalDate.parse(dateString, dateTimeFormatter);
    return date;
}

It works fine for Arabic dates like ٢٠١٩-٠٤-١٥, but when I pass a normal date like 2019-07-31, it throws an exception because the formatter is of a different type:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2019-07-31' could not be parsed at index 0

I don't have control over the date passed, as it is passed by the user.

How can I use the same function to parse both dates?

like image 461
robin Avatar asked Mar 06 '19 07:03

robin


People also ask

How to write Date in Java?

Creating A Simple Date FormatString pattern = "yyyy-MM-dd" ; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); The specified parameter “pattern” is the pattern used for formatting and parsing dates.


1 Answers

Know your string

DateTimeFormatter doesn’t make this very easy for you. I am speculating that there may be a purpose behind this choice: it’s better if you can bring yourself into a situation where you know beforehand what kind of digits is used in the string you are going to parse. You may give this a thought: could you persuade the source of your string to pass this information to you?

Take a taste and act accordingly

If not, of course there is a way through. The following is low-level but should be general.

public static LocalDate getLocalDateFromString(String dateString) {
    DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE;
    // Take a digit from dateString to determine which digits are used
    char sampleDigit = dateString.charAt(0);
    if (Character.isDigit(sampleDigit)) {
        // Subtract the numeric value of the digit to find the zero digit in the same digit block
        char zeroDigit = (char) (sampleDigit - Character.getNumericValue(sampleDigit));
        assert Character.isDigit(zeroDigit) : zeroDigit;
        assert Character.getNumericValue(zeroDigit) == 0 : zeroDigit;
        DecimalStyle defaultDecimalStyle = dateFormatter.getDecimalStyle();
        dateFormatter = dateFormatter
                .withDecimalStyle(defaultDecimalStyle.withZeroDigit(zeroDigit));
    }
    // If the examined char wasn’t a digit, the following parsing will fail;
    // but in that case the best we can give the caller is the exception from that failed parsing.
    LocalDate date = LocalDate.parse(dateString, dateFormatter);
    return date;
}

Let’s try it out:

    System.out.println("Parsing Arabic date string to  "
            + getLocalDateFromString("٢٠١٩-٠٤-١٥"));
    System.out.println("Parsing Western date string to "
            + getLocalDateFromString("2019-07-31"));

Output from this snippet is:

Parsing Arabic date string to  2019-04-15
Parsing Western date string to 2019-07-31
like image 151
Ole V.V. Avatar answered Nov 15 '22 05:11

Ole V.V.