mfathi91 / persian-date-time

Persian Date Time
MIT License
81 stars 15 forks source link

Formatting with DateTimeFormatter doesn't work as expected #4

Closed mahozad closed 3 years ago

mahozad commented 4 years ago

Formatting PersianDate with java.time.format.DateTimeFormatter has two problems:

1. When using a fa locale, numbers are represented with English digits

This will be fixed in JDK 15 (using .localizedBy(myLocale) will be enough).

Until then, format like this: .localizedBy(myLcoale).withDecimalStyle(DecimalStyle.of(myLocale))

I believe this is a bug in Java. So I filed an issue here and it seems that for some reason (?!) the numbers are formatted in the string without respecting the given locale. To resolve the problem I did this:

if (currentLocale.getLanguage().equals("fa")) {
    Locale localeFa = Locale.forLanguageTag("fa-u-nu-arabext"); // -u-nu-arabext for Persian digits
    PersianDate dateFa = PersianDate.fromGregorian(aDate);
    dateTimeFormatter.localizedBy(localeFa).format(dateFa);
}

So I wanted to know is there any way PersianDate formats the numbers as Persian when the locale is set to fa or fa-IR?

I think this can easily be done with editing the PersianDate class to override the format() method of ChronoLocalDate like this:

Note that this resolves the problem if user formats the date with the format() method of PersianDate and not format() method of DateTimeFormatter.

@Override
String format(DateTimeFormatter formatter) {
    Objects.requireNonNull(formatter, "formatter");
    if (formatter.getLocale().getLanguage().equals("fa")) {
        Locale localeOverride = Locale.forLanguageTag("fa-u-nu-arabext"); // fa with persian digits
        return formatter.localizedBy(localeOverride).format(this);
    } else {
        return formatter.format(this);
    }
}

#

2. The month is formatted with Gregorian name and not Persian name

PersianDate persianDate = PersianDate.fromGregorian(LocalDate.now());
Locale locale = Locale.forLanguageTag("fa-u-nu-arabext");
DateTimeFormatter formatter = ofPattern("MMMM"/*or "LLLL"*/).localizedBy(locale);
System.out.println(persianDate.format(formatter));

The above code prints فوریه instead of اردیبهشت. The workaround could be again to modify the format() method and replace all occurrences of Gregorian month names with the Persian ones.

mfathi91 commented 4 years ago

Thank you for raising the issue!

The problem is that the library has never intended to format the date into Persian transcriptions. Therefore, neither a specific implementation nor unit test is in place for localized formaters, e.g. fa locale.

Regarding supporting the fa locale in the library, I believe it's generally a positive intention. Having that said, the issue (as you pointed out) is that in case the library would support the fa locale as you proposed, there would be inconsistency between PersianDate#format and DateTimeFormatter#format. I would like to refrain from such an inconsistency.

Maybe introducing another class (e.g. PersianDateFormatter) which specifically addresses the fa locale would be a better compromise.