Using my library Time4J (or Time4A on Android) enables following short solution out of the box:
String input = "1397/01/14";
PersianCalendar jalali =
ChronoFormatter
.ofPattern("yyyy/MM/dd", PatternType.CLDR, Locale.ROOT, PersianCalendar.axis())
.parse(input);
PlainDate gregorian = jalali.transform(PlainDate.axis());
String iso8601 = Iso8601Format.EXTENDED_DATE.format(gregorian);
System.out.println(iso8601); // 2018-04-03
No need to implement your own calendar chronology (which is generally a complex task). If you want to get the result with slashes instead of ISO-format then just use another formatter by:
String output = ChronoFormatter
.ofPattern("yyyy/MM/dd", PatternType.CLDR, Locale.ROOT, PlainDate.axis())
.format(gregorian);
Update for question in comment:
If the input contains a time part then the whole thing is rather a timestamp and not a calendar date. So users can parse to a moment instead.
TZID tzid = () -> "Asia/Tehran"; // used as default time zone for parsing
ChronoFormatter<Moment> f =
ChronoFormatter.setUpWithOverride(Locale.ENGLISH, PersianCalendar.axis())
.addPattern("yyyy/MM/dd HH:mm[:ss]", PatternType.CLDR) // optional seconds
.build()
.withTimezone(tzid);
Moment expected =
PlainTimestamp.of(2018, 4, 3, 10, 15, 5).inTimezone(tzid);
assertThat(
f.parse("1397/01/14 10:15:05"),
is(expected));
The parsed moment can be converted back to Persian calendar this way:
assertThat(
expected.toGeneralTimestamp(PersianCalendar.axis(), tzid, StartOfDay.MIDNIGHT).toDate(),
is(PersianCalendar.of(1397, 1, 14)));