Use IBM's International Components for Unicode (icu4j). It is part of Unicode Consortium, is extremely reliable and can be used in any java project (Java EE, Java SE, Android, etc). Use it with Gradle, Maven or simply by downloading the jar.
TL;DR
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.ULocale;
public class DateTimeUtils {
public static final ULocale PERSIAN_LOCALE = new ULocale("fa_IR@calendar=persian");
public static final ULocale PERSIAN_EN_LOCALE = new ULocale("en@calendar=persian");
public static final ZoneId IRAN_ZONE_ID = ZoneId.of("Asia/Tehran");
public static Calendar fromDateToPersianCalendar(Date date) {
Calendar persianCalendar = Calendar.getInstance(PERSIAN_LOCALE);
persianCalendar.clear();
persianCalendar.setTime(date);
return persianCalendar;
}
/**
* @param date
* @param field example: Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, etc
*/
public static int fromDateToPersianCalendarField(Date date, int field) {
return fromDateToPersianCalendar(date).get(field);
}
public static String fromDateToPersianString(Date date) {
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, PERSIAN_LOCALE);
return df.format(date);
}
public static String fromDateToPersianString(Date date, String pattern) {
return new SimpleDateFormat(pattern, PERSIAN_LOCALE).format(date);
}
public static String fromDateToPersianString(Date date, String pattern, ULocale locale) {
return new SimpleDateFormat(pattern, locale).format(date);
}
/**
* @param month is zero based. (e.g. Farvardin = 0, Ordibehesht = 1, etc.)
*/
public static Date fromPersianDateToDate(int year, int month, int day, int hour, int minutes, int seconds) {
return new Date(fromPersianDate(year, month, day, hour, minutes, seconds));
}
/**
* @param month is zero based. (e.g. Farvardin = 0, Ordibehesht = 1, etc.)
*/
public static String fromPersianDateToPersianString(int year, int month, int day, int hour, int minutes, int seconds) {
return fromDateToPersianString(fromPersianDateToDate(year, month, day, hour, minutes, seconds));
}
/**
* @param month is zero based. (e.g. Farvardin = 0, Ordibehesht = 1, etc.)
*/
public static LocalDateTime fromPersianDateToLocalDateTime(int year, int month, int day, int hour, int minutes, int seconds) {
return fromPersianDateToZonedDateTime(year, month, day, hour, minutes, seconds).toLocalDateTime();
}
/**
* @param month is zero based. (e.g. Farvardin = 0, Ordibehesht = 1, etc.)
*/
public static ZonedDateTime fromPersianDateToZonedDateTime(int year, int month, int day, int hour, int minutes, int seconds) {
return toZonedDateTime(fromPersianDate(year, month, day, hour, minutes, seconds));
}
/**
* @param month is zero based. (e.g. Farvardin = 0, Ordibehesht = 1, etc.)
*/
public static long fromPersianDate(int year, int month, int day, int hour, int minutes, int seconds) {
Calendar persianCalendar = Calendar.getInstance(PERSIAN_LOCALE);
persianCalendar.clear();
persianCalendar.set(year, month, day, hour, minutes, seconds);
return persianCalendar.getTimeInMillis();
}
public static ZonedDateTime toZonedDateTime(Long epochMilli) {
if(epochMilli == null) return null;
return Instant.ofEpochMilli(epochMilli).atZone(IRAN_ZONE_ID);
}
}
Usage:
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Date;
import com.ibm.icu.util.Calendar;
public class DateTimeUtilsTest {
public static void main(String[] args) {
System.out.println("Java 7 and before:");
Date date = new Date(1467262800000L);
System.out.println("Converting Gregorian date to Persian:");
Calendar persianCalendar = DateTimeUtils.fromDateToPersianCalendar(date);
System.out.println(persianCalendar.get(Calendar.YEAR));
System.out.println(persianCalendar.get(Calendar.MONTH));
System.out.println(persianCalendar.get(Calendar.DAY_OF_MONTH));
System.out.println(DateTimeUtils.fromDateToPersianString(persianCalendar.getTime()));
System.out.println("\nAdding 1 month and 5 days:");
persianCalendar.add(Calendar.MONTH, 1); // add a month
persianCalendar.add(Calendar.DAY_OF_MONTH, 5); // add 5 days
System.out.println(persianCalendar.get(Calendar.YEAR));
System.out.println(persianCalendar.get(Calendar.MONTH));
System.out.println(persianCalendar.get(Calendar.DAY_OF_MONTH));
System.out.println(DateTimeUtils.fromDateToPersianString(persianCalendar.getTime()));
System.out.println("\nConverting Persian date to Gregorian:");
Date gregorianDate = DateTimeUtils.fromPersianDateToDate(1395, 3, 10, 9, 30, 0);
System.out.println(gregorianDate);
System.out.println(DateTimeUtils.fromDateToPersianString(gregorianDate)); // to Persian string
System.out.println(DateTimeUtils.fromDateToPersianString(gregorianDate, "dd/MM/yy - H:mm:dd")); // to Persian string with custom format
System.out.println(DateTimeUtils.fromDateToPersianString(gregorianDate, "dd/MM/yy - H:mm:dd" , DateTimeUtils.PERSIAN_EN_LOCALE)); // to Persian string with custom format and Latin characters
System.out.println("\n"+"Java 8 onward:");
ZonedDateTime gregorianZonedDateTime = DateTimeUtils.fromPersianDateToZonedDateTime(1395, 3, 10, 9, 30, 0);
System.out.println(gregorianZonedDateTime);
LocalDateTime gregorianLocalDateTime = DateTimeUtils.fromPersianDateToLocalDateTime(1395, 3, 10, 9, 30, 0);
System.out.println(gregorianLocalDateTime);
}
}
Output:
Java 7 and before:
Converting Gregorian date to Persian:
1395
3
10
۱۳۹۵ تیر ۱۰, پنجشنبه
Adding 1 month and 5 days:
1395
4
15
۱۳۹۵ مرداد ۱۵, جمعه
Converting Persian date to Gregorian:
Thu Jun 30 09:30:00 IRDT 2016
۱۳۹۵ تیر ۱۰, پنجشنبه
۱۰/۰۴/۹۵ - ۹:۳۰:۱۰
10/04/95 - 9:30:10
Java 8 onward:
2016-06-30T09:30+04:30[Asia/Tehran]
2016-06-30T09:30
More detailed:
Java 7 and before:
You can expect all of functionalities of java.util.Calendar
in addition to some other ones:
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.ULocale;
...
ULocale locale = new ULocale("fa_IR@calendar=persian");
Calendar persianCalendar = Calendar.getInstance(locale);
persianCalendar.clear();
persianCalendar.set(1395, 3, 10); // Tir(4th month) 10th 1395 equivalent to June 30th 2016
java.util.Date gregorianDate = persianCalendar.getTime();
System.out.println(gregorianDate); // Thu Jun 30 00:00:00 IDT 2016
// Gregorian to Persian
java.util.Calendar gregorianCal = java.util.GregorianCalendar.getInstance();
gregorianCal.set(2016, java.util.Calendar.JUNE, 30);
persianCalendar.setTime(gregorianCal.getTime());
System.out.println(persianCalendar.get(Calendar.YEAR)); // 1395
System.out.println(persianCalendar.get(Calendar.MONTH)); // 3
System.out.println(persianCalendar.get(Calendar.DAY_OF_MONTH)); // 10
WARNING: Note that month field is zero based in Java calendar so by calendar.set(1395, 3, 10)
calendar will represent 4th month of 1395, not 3rd!
If you need text outputs in persian:
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
...
// full date output in persian
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, locale);
System.out.println(df.format(persianCalendar.getTime()));
// year output in persian
SimpleDateFormat sdf1 = new SimpleDateFormat(SimpleDateFormat.YEAR, locale);
System.out.println(sdf1.format(persianCalendar.getTime()));
// month name output in persian
SimpleDateFormat sdf2 = new SimpleDateFormat(SimpleDateFormat.MONTH, locale);
System.out.println(sdf2.format(persianCalendar.getTime()));
// weekday name output in persian
SimpleDateFormat sdf3 = new SimpleDateFormat(SimpleDateFormat.WEEKDAY, locale);
System.out.println(sdf3.format(persianCalendar.getTime()));
// full date output in YY/MM/dd form
SimpleDateFormat sdf4 = new SimpleDateFormat("YY/MM/dd", locale);
System.out.println(sdf4.format(persianCalendar.getTime()));
Output:
ه.ش. ۱۳۹۵ تیر ۱۰, پنجشنبه
۱۳۹۵
تیر
پنجشنبه
۹۵/۰۴/۱۰
If you need output to be in english, change new ULocale("fa_IR@calendar=persian")
to new ULocale("en@calendar=persian")
.
Output:
AP 1395 Tir 10, Thu
1395
Tir
Thu
95/04/10
Other nice things:
// Get number of days in month
System.out.println(persianCalendar.getActualMaximum(Calendar.DAY_OF_MONTH)); // 31
// Get first day of week
System.out.println(persianCalendar.getFirstDayOfWeek()); // 7 (Saturday according to docs)
// Add some amount of time
persianCalendar.add(Calendar.MONTH, 2);
System.out.println(persianCalendar.get(Calendar.YEAR)); //1395
System.out.println(persianCalendar.get(Calendar.MONTH)); // 5
System.out.println(persianCalendar.get(Calendar.DAY_OF_MONTH)); // 10
For other functionalities see icu4j demos, specially:
- demo of various calendar fields
- list of Tuesdays and Thursdays of current year
- demo of converting number to text representation (use
fa_IR
for locale)
Also see Calendar and PersianCalendar API.
Java 8 onward:
In order to use java.time
classes like ZonedDateTime
or LocalDateTime
, you could simply use this methods to convert a persian date to preferred classes:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.ULocale;
...
public static LocalDateTime fromPersianDateToLocalDateTime(int year, int month, int day, int hour, int minutes, int seconds) {
return fromPersianDateToZonedDateTime(year, month, day, hour, minutes, seconds).toLocalDateTime();
}
public static ZonedDateTime fromPersianDateToZonedDateTime(int year, int month, int day, int hour, int minutes, int seconds) {
return toZonedDateTime(fromPersianDate(year, month, day, hour, minutes, seconds));
}
public static long fromPersianDate(int year, int month, int day, int hour, int minutes, int seconds) {
Calendar persianCalendar = Calendar.getInstance(new ULocale("fa_IR@calendar=persian"));
persianCalendar.clear();
persianCalendar.set(year, month, day, hour, minutes, seconds);
return persianCalendar.getTimeInMillis();
}
public static ZonedDateTime toZonedDateTime(Long epochMilli) {
if(epochMilli == null) return null;
return Instant.ofEpochMilli(epochMilli).atZone(ZoneId.of("Asia/Tehran"));
}
Remarks About Jar Size
If you're concerned about icu4j's jar size , then you may rebuild it and just use the Calendar module (2,176KB). More Info: ver. 57 or earlier , ver. 58 or later using ICU Data Build Tool.