Android中是不是有波斯(Shamsi或Jalali)日历的库或算法? [关闭]
Posted
技术标签:
【中文标题】Android中是不是有波斯(Shamsi或Jalali)日历的库或算法? [关闭]【英文标题】:Is there any library or algorithm for Persian (Shamsi or Jalali) calendar in Android? [closed]Android中是否有波斯(Shamsi或Jalali)日历的库或算法? [关闭] 【发布时间】:2012-05-09 20:41:44 【问题描述】:对于所有版本的 android,我想将 Gregorian(西方)日期转换为 波斯(Shamsi)日期,反之亦然。
有没有完整可靠的库或算法?
【问题讨论】:
A good date converter for Jalali Calendar in Java?的可能重复 【参考方案1】:我多年来一直使用这个算法,它在 1901 年到 2099 年之间非常准确。
使用它并享受! :)
public class Utilities
private class SolarCalendar
public String strWeekDay = "";
public String strMonth = "";
int date;
int month;
int year;
public SolarCalendar()
Date MiladiDate = new Date();
calcSolarCalendar(MiladiDate);
public SolarCalendar(Date MiladiDate)
calcSolarCalendar(MiladiDate);
private void calcSolarCalendar(Date MiladiDate)
int ld;
int miladiYear = MiladiDate.getYear() + 1900;
int miladiMonth = MiladiDate.getMonth() + 1;
int miladiDate = MiladiDate.getDate();
int WeekDay = MiladiDate.getDay();
int[] buf1 = new int[12];
int[] buf2 = new int[12];
buf1[0] = 0;
buf1[1] = 31;
buf1[2] = 59;
buf1[3] = 90;
buf1[4] = 120;
buf1[5] = 151;
buf1[6] = 181;
buf1[7] = 212;
buf1[8] = 243;
buf1[9] = 273;
buf1[10] = 304;
buf1[11] = 334;
buf2[0] = 0;
buf2[1] = 31;
buf2[2] = 60;
buf2[3] = 91;
buf2[4] = 121;
buf2[5] = 152;
buf2[6] = 182;
buf2[7] = 213;
buf2[8] = 244;
buf2[9] = 274;
buf2[10] = 305;
buf2[11] = 335;
if ((miladiYear % 4) != 0)
date = buf1[miladiMonth - 1] + miladiDate;
if (date > 79)
date = date - 79;
if (date <= 186)
switch (date % 31)
case 0:
month = date / 31;
date = 31;
break;
default:
month = (date / 31) + 1;
date = (date % 31);
break;
year = miladiYear - 621;
else
date = date - 186;
switch (date % 30)
case 0:
month = (date / 30) + 6;
date = 30;
break;
default:
month = (date / 30) + 7;
date = (date % 30);
break;
year = miladiYear - 621;
else
if ((miladiYear > 1996) && (miladiYear % 4) == 1)
ld = 11;
else
ld = 10;
date = date + ld;
switch (date % 30)
case 0:
month = (date / 30) + 9;
date = 30;
break;
default:
month = (date / 30) + 10;
date = (date % 30);
break;
year = miladiYear - 622;
else
date = buf2[miladiMonth - 1] + miladiDate;
if (miladiYear >= 1996)
ld = 79;
else
ld = 80;
if (date > ld)
date = date - ld;
if (date <= 186)
switch (date % 31)
case 0:
month = (date / 31);
date = 31;
break;
default:
month = (date / 31) + 1;
date = (date % 31);
break;
year = miladiYear - 621;
else
date = date - 186;
switch (date % 30)
case 0:
month = (date / 30) + 6;
date = 30;
break;
default:
month = (date / 30) + 7;
date = (date % 30);
break;
year = miladiYear - 621;
else
date = date + 10;
switch (date % 30)
case 0:
month = (date / 30) + 9;
date = 30;
break;
default:
month = (date / 30) + 10;
date = (date % 30);
break;
year = miladiYear - 622;
switch (month)
case 1:
strMonth = "فروردين";
break;
case 2:
strMonth = "ارديبهشت";
break;
case 3:
strMonth = "خرداد";
break;
case 4:
strMonth = "تير";
break;
case 5:
strMonth = "مرداد";
break;
case 6:
strMonth = "شهريور";
break;
case 7:
strMonth = "مهر";
break;
case 8:
strMonth = "آبان";
break;
case 9:
strMonth = "آذر";
break;
case 10:
strMonth = "دي";
break;
case 11:
strMonth = "بهمن";
break;
case 12:
strMonth = "اسفند";
break;
switch (WeekDay)
case 0:
strWeekDay = "يکشنبه";
break;
case 1:
strWeekDay = "دوشنبه";
break;
case 2:
strWeekDay = "سه شنبه";
break;
case 3:
strWeekDay = "چهارشنبه";
break;
case 4:
strWeekDay = "پنج شنبه";
break;
case 5:
strWeekDay = "جمعه";
break;
case 6:
strWeekDay = "شنبه";
break;
public static String getCurrentShamsidate()
Locale loc = new Locale("en_US");
Utilities util = new Utilities();
SolarCalendar sc = util.new SolarCalendar();
return String.valueOf(sc.year) + "/" + String.format(loc, "%02d",
sc.month) + "/" + String.format(loc, "%02d", sc.date);
【讨论】:
并非所有年份(即 4 的倍数)都是闰年。那些是 100 的倍数,但不是 400 的倍数的例外。见:wikipedia 您遇到问题的日期是什么? 我在我的应用程序中使用了这个算法 6 年。 你应该使用它 100 年才能看到问题:) 也许您可以编辑答案的第一句话,使其显示“......它在 1901 年和 2099 年之间非常准确”。这对于许多应用程序来说可能已经足够了;但是一些开发者可能对这个范围之外的日期感兴趣,最好警告他们这个算法不够好。【参考方案2】:我认为这个java类更容易使用,更可靠。 我在Iranian forum 找到它,伊朗人使用 Jalali 日历并将其称为“Shamsi”,意思是阳历。这是 Java 类:
package MyUtil;
import java.util.Calendar;
import java.util.GregorianCalendar;
/**
* Title: Calender Conversion class
* Description: Convert Iranian (Jalali), Julian, and Gregorian dates to
* each other
* Public Methods Summary:
* -----------------------
* JavaSource_Calendar();
* JavaSource_Calendar(int year, int month, int day);
* int getIranianYear();
* int getIranianMonth();
* int getIranianDay();
* int getGregorianYear();
* int getGregorianMonth();
* int getGregorianDay();
* int getJulianYear();
* int getJulianMonth();
* int getJulianDay();
* String getIranianDate();
* String getGregorianDate();
* String getJulianDate();
* String getWeekDayStr();
* String toString();
* int getDayOfWeek();
* void nextDay();
* void nextDay(int days);
* void previousDay();
* void previousDay(int days);
* void setIranianDate(int year, int month, int day);
* void setGregorianDate(int year, int month, int day);
* void setJulianDate(int year, int month, int day);
*/
public class CalendarTool
/**
* JavaSource_Calendar:
* The default constructor uses the current Gregorian date to initialize the
* other private memebers of the class (Iranian and Julian dates).
*/
public CalendarTool()
Calendar calendar = new GregorianCalendar();
setGregorianDate(calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH)+1,
calendar.get(Calendar.DAY_OF_MONTH));
/**
* JavaSource_Calendar:
* This constructor receives a Gregorian date and initializes the other private
* members of the class accordingly.
* @param year int
* @param month int
* @param day int
*/
public CalendarTool(int year, int month, int day)
setGregorianDate(year,month,day);
/**
* getIranianYear:
* Returns the 'year' part of the Iranian date.
* @return int
*/
public int getIranianYear()
return irYear;
/**
* getIranianMonth:
* Returns the 'month' part of the Iranian date.
* @return int
*/
public int getIranianMonth()
return irMonth;
/**
* getIranianDay:
* Returns the 'day' part of the Iranian date.
* @return int
*/
public int getIranianDay()
return irDay;
/**
* getGregorianYear:
* Returns the 'year' part of the Gregorian date.
* @return int
*/
public int getGregorianYear()
return gYear;
/**
* getGregorianMonth:
* Returns the 'month' part of the Gregorian date.
* @return int
*/
public int getGregorianMonth()
return gMonth;
/**
* getGregorianDay:
* Returns the 'day' part of the Gregorian date.
* @return int
*/
public int getGregorianDay()
return gDay;
/**
* getJulianYear:
* Returns the 'year' part of the Julian date.
* @return int
*/
public int getJulianYear()
return juYear;
/**
* getJulianMonth:
* Returns the 'month' part of the Julian date.
* @return int
*/
public int getJulianMonth()
return juMonth;
/**
* getJulianDay()
* Returns the 'day' part of the Julian date.
* @return int
*/
public int getJulianDay()
return juDay;
/**
* getIranianDate:
* Returns a string version of Iranian date
* @return String
*/
public String getIranianDate()
return (irYear+"/"+irMonth+"/"+irDay);
/**
* getGregorianDate:
* Returns a string version of Gregorian date
* @return String
*/
public String getGregorianDate()
return (gYear+"/"+gMonth+"/"+gDay);
/**
* getJulianDate:
* Returns a string version of Julian date
* @return String
*/
public String getJulianDate()
return (juYear+"/"+juMonth+"/"+juDay);
/**
* getWeekDayStr:
* Returns the week day name.
* @return String
*/
public String getWeekDayStr()
String weekDayStr[]=
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday";
return (weekDayStr[getDayOfWeek()]);
/**
* toString:
* Overrides the default toString() method to return all dates.
* @return String
*/
public String toString()
return (getWeekDayStr()+
", Gregorian:["+getGregorianDate()+
"], Julian:["+getJulianDate()+
"], Iranian:["+getIranianDate()+"]");
/**
* getDayOfWeek:
* Returns the week day number. Monday=0..Sunday=6;
* @return int
*/
public int getDayOfWeek()
return (JDN % 7);
/**
* nextDay:
* Go to next julian day number (JDN) and adjusts the other dates.
*/
public void nextDay()
JDN++;
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* nextDay:
* Overload the nextDay() method to accept the number of days to go ahead and
* adjusts the other dates accordingly.
* @param days int
*/
public void nextDay(int days)
JDN+=days;
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* previousDay:
* Go to previous julian day number (JDN) and adjusts the otehr dates.
*/
public void previousDay()
JDN--;
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* previousDay:
* Overload the previousDay() method to accept the number of days to go backward
* and adjusts the other dates accordingly.
* @param days int
*/
public void previousDay(int days)
JDN-=days;
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* setIranianDate:
* Sets the date according to the Iranian calendar and adjusts the other dates.
* @param year int
* @param month int
* @param day int
*/
public void setIranianDate(int year, int month, int day)
irYear =year;
irMonth = month;
irDay = day;
JDN = IranianDateToJDN();
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* setGregorianDate:
* Sets the date according to the Gregorian calendar and adjusts the other dates.
* @param year int
* @param month int
* @param day int
*/
public void setGregorianDate(int year, int month, int day)
gYear = year;
gMonth = month;
gDay = day;
JDN = gregorianDateToJDN(year,month,day);
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* setJulianDate:
* Sets the date according to the Julian calendar and adjusts the other dates.
* @param year int
* @param month int
* @param day int
*/
public void setJulianDate(int year, int month, int day)
juYear = year;
juMonth = month;
juDay = day;
JDN = julianDateToJDN(year,month,day);
JDNToIranian();
JDNToJulian();
JDNToGregorian();
/**
* IranianCalendar:
* This method determines if the Iranian (Jalali) year is leap (366-day long)
* or is the common year (365 days), and finds the day in March (Gregorian
* Calendar)of the first day of the Iranian year ('irYear').Iranian year (irYear)
* ranges from (-61 to 3177).This method will set the following private data
* members as follows:
* leap: Number of years since the last leap year (0 to 4)
* Gy: Gregorian year of the begining of Iranian year
* march: The March day of Farvardin the 1st (first day of jaYear)
*/
private void IranianCalendar()
// Iranian years starting the 33-year rule
int Breaks[]=
-61, 9, 38, 199, 426, 686, 756, 818,1111,1181,
1210,1635,2060,2097,2192,2262,2324,2394,2456,3178 ;
int jm,N,leapJ,leapG,jp,j,jump;
gYear = irYear + 621;
leapJ = -14;
jp = Breaks[0];
// Find the limiting years for the Iranian year 'irYear'
j=1;
do
jm=Breaks[j];
jump = jm-jp;
if (irYear >= jm)
leapJ += (jump / 33 * 8 + (jump % 33) / 4);
jp = jm;
j++;
while ((j<20) && (irYear >= jm));
N = irYear - jp;
// Find the number of leap years from AD 621 to the begining of the current
// Iranian year in the Iranian (Jalali) calendar
leapJ += (N/33 * 8 + ((N % 33) +3)/4);
if ( ((jump % 33) == 4 ) && ((jump-N)==4))
leapJ++;
// And the same in the Gregorian date of Farvardin the first
leapG = gYear/4 - ((gYear /100 + 1) * 3 / 4) - 150;
march = 20 + leapJ - leapG;
// Find how many years have passed since the last leap year
if ( (jump - N) < 6 )
N = N - jump + ((jump + 4)/33 * 33);
leap = (((N+1) % 33)-1) % 4;
if (leap == -1)
leap = 4;
/**
* IsLeap:
* This method determines if the Iranian (Jalali) year is leap (366-day long)
* or is the common year (365 days), and finds the day in March (Gregorian
* Calendar)of the first day of the Iranian year ('irYear').Iranian year (irYear)
* ranges from (-61 to 3177).This method will set the following private data
* members as follows:
* leap: Number of years since the last leap year (0 to 4)
* Gy: Gregorian year of the begining of Iranian year
* march: The March day of Farvardin the 1st (first day of jaYear)
*/
public boolean IsLeap(int irYear1)
// Iranian years starting the 33-year rule
int Breaks[]=
-61, 9, 38, 199, 426, 686, 756, 818,1111,1181,
1210,1635,2060,2097,2192,2262,2324,2394,2456,3178 ;
int jm,N,leapJ,leapG,jp,j,jump;
gYear = irYear1 + 621;
leapJ = -14;
jp = Breaks[0];
// Find the limiting years for the Iranian year 'irYear'
j=1;
do
jm=Breaks[j];
jump = jm-jp;
if (irYear1 >= jm)
leapJ += (jump / 33 * 8 + (jump % 33) / 4);
jp = jm;
j++;
while ((j<20) && (irYear1 >= jm));
N = irYear1 - jp;
// Find the number of leap years from AD 621 to the begining of the current
// Iranian year in the Iranian (Jalali) calendar
leapJ += (N/33 * 8 + ((N % 33) +3)/4);
if ( ((jump % 33) == 4 ) && ((jump-N)==4))
leapJ++;
// And the same in the Gregorian date of Farvardin the first
leapG = gYear/4 - ((gYear /100 + 1) * 3 / 4) - 150;
march = 20 + leapJ - leapG;
// Find how many years have passed since the last leap year
if ( (jump - N) < 6 )
N = N - jump + ((jump + 4)/33 * 33);
leap = (((N+1) % 33)-1) % 4;
if (leap == -1)
leap = 4;
if (leap==4 || leap==0)
return true;
else
return false;
/**
* IranianDateToJDN:
* Converts a date of the Iranian calendar to the Julian Day Number. It first
* invokes the 'IranianCalender' private method to convert the Iranian date to
* Gregorian date and then returns the Julian Day Number based on the Gregorian
* date. The Iranian date is obtained from 'irYear'(1-3100),'irMonth'(1-12) and
* 'irDay'(1-29/31).
* @return long (Julian Day Number)
*/
private int IranianDateToJDN()
IranianCalendar();
return (gregorianDateToJDN(gYear,3,march)+ (irMonth-1) * 31 - irMonth/7 * (irMonth-7) + irDay -1);
/**
* JDNToIranian:
* Converts the current value of 'JDN' Julian Day Number to a date in the
* Iranian calendar. The caller should make sure that the current value of
* 'JDN' is set correctly. This method first converts the JDN to Gregorian
* calendar and then to Iranian calendar.
*/
private void JDNToIranian()
JDNToGregorian();
irYear = gYear - 621;
IranianCalendar(); // This invocation will update 'leap' and 'march'
int JDN1F = gregorianDateToJDN(gYear,3,march);
int k = JDN - JDN1F;
if (k >= 0)
if (k <= 185)
irMonth = 1 + k/31;
irDay = (k % 31) + 1;
return;
else
k -= 186;
else
irYear--;
k += 179;
if (leap == 1)
k++;
irMonth = 7 + k/30;
irDay = (k % 30) + 1;
/**
* julianDateToJDN:
* Calculates the julian day number (JDN) from Julian calendar dates. This
* integer number corresponds to the noon of the date (i.e. 12 hours of
* Universal Time). This method was tested to be good (valid) since 1 March,
* -100100 (of both calendars) up to a few millions (10^6) years into the
* future. The algorithm is based on D.A.Hatcher, Q.Jl.R.Astron.Soc. 25(1984),
* 53-55 slightly modified by K.M. Borkowski, Post.Astron. 25(1987), 275-279.
* @param year int
* @param month int
* @param day int
* @return int
*/
private int julianDateToJDN(int year, int month, int day)
return (year + (month - 8) / 6 + 100100) * 1461/4 + (153 * ((month+9) % 12) + 2)/5 + day - 34840408;
/**
* JDNToJulian:
* Calculates Julian calendar dates from the julian day number (JDN) for the
* period since JDN=-34839655 (i.e. the year -100100 of both calendars) to
* some millions (10^6) years ahead of the present. The algorithm is based on
* D.A. Hatcher, Q.Jl.R.Astron.Soc. 25(1984), 53-55 slightly modified by K.M.
* Borkowski, Post.Astron. 25(1987), 275-279).
*/
private void JDNToJulian()
int j= 4 * JDN + 139361631;
int i= ((j % 1461)/4) * 5 + 308;
juDay = (i % 153) / 5 + 1;
juMonth = ((i/153) % 12) + 1;
juYear = j/1461 - 100100 + (8-juMonth)/6;
/**
* gergorianDateToJDN:
* Calculates the julian day number (JDN) from Gregorian calendar dates. This
* integer number corresponds to the noon of the date (i.e. 12 hours of
* Universal Time). This method was tested to be good (valid) since 1 March,
* -100100 (of both calendars) up to a few millions (10^6) years into the
* future. The algorithm is based on D.A.Hatcher, Q.Jl.R.Astron.Soc. 25(1984),
* 53-55 slightly modified by K.M. Borkowski, Post.Astron. 25(1987), 275-279.
* @param year int
* @param month int
* @param day int
* @return int
*/
private int gregorianDateToJDN(int year, int month, int day)
int jdn = (year + (month - 8) / 6 + 100100) * 1461/4 + (153 * ((month+9) % 12) + 2)/5 + day - 34840408;
jdn = jdn - (year + 100100+(month-8)/6)/100*3/4+752;
return (jdn);
/**
* JDNToGregorian:
* Calculates Gregorian calendar dates from the julian day number (JDN) for
* the period since JDN=-34839655 (i.e. the year -100100 of both calendars) to
* some millions (10^6) years ahead of the present. The algorithm is based on
* D.A. Hatcher, Q.Jl.R.Astron.Soc. 25(1984), 53-55 slightly modified by K.M.
* Borkowski, Post.Astron. 25(1987), 275-279).
*/
private void JDNToGregorian()
int j= 4 * JDN + 139361631;
j = j + (((((4* JDN +183187720)/146097)*3)/4)*4-3908);
int i= ((j % 1461)/4) * 5 + 308;
gDay = (i % 153) / 5 + 1;
gMonth = ((i/153) % 12) + 1;
gYear = j/1461 - 100100 + (8-gMonth)/6;
private int irYear; // Year part of a Iranian date
private int irMonth; // Month part of a Iranian date
private int irDay; // Day part of a Iranian date
private int gYear; // Year part of a Gregorian date
private int gMonth; // Month part of a Gregorian date
private int gDay; // Day part of a Gregorian date
private int juYear; // Year part of a Julian date
private int juMonth; // Month part of a Julian date
private int juDay; // Day part of a Julian date
private int leap; // Number of years since the last leap year (0 to 4)
private int JDN; // Julian Day Number
private int march; // The march day of Farvardin the first (First day of jaYear)
// End of Class 'JavaSource_Calendar
您可以轻松设置公历日、月和年,然后调用“getIranianDate()”方法获取字符串格式的日期,如下面的示例代码:
MyUtil.CalendarTool ct = new CalendarTool(2012,10,10);
System.out.println(ct.getIranianDate());
希望对你有帮助。
【讨论】:
我认为有一个错误!当您转换今天的日期(我发布此评论的日期)时,它将是 '1396/01/20' 但它是 '1395/12/20' 它给出了错误的答案。 你可以帮我编辑它并解决错误。 代码在 2017 年 4 月 10 日和 18 年 4 月 14 日都可以正常工作 我认为一个问题是月份的天数没有界限,例如四月是 30 天,但是 Apr31 的代码答案与 May1 相同【参考方案3】:使用 IBM 的 Unicode 国际组件 (icu4j)。它是Unicode Consortium 的一部分,非常可靠,可用于任何Java 项目(Java EE、Java SE、Android 等)。将其与 Gradle、Maven 或仅通过 downloading 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);
用法:
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);
输出:
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
更详细:
Java 7 及之前版本:
除了其他一些功能之外,您还可以期待 java.util.Calendar
的所有功能:
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
警告:请注意,基于 Java 日历的月份字段为零,因此 calendar.set(1395, 3, 10)
日历将表示 1395 年的第 4 个月,而不是第 3 个月!
如果您需要波斯语文本输出:
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()));
输出:
ه.ش. ۱۳۹۵ تیر ۱۰, پنجشنبه
۱۳۹۵
تیر
پنجشنبه
۹۵/۰۴/۱۰
如果您需要输出为英文,请将new ULocale("fa_IR@calendar=persian")
更改为new ULocale("en@calendar=persian")
。
输出:
AP 1395 Tir 10, Thu
1395
Tir
Thu
95/04/10
其他好东西:
// 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
其他功能见icu4j demos,特别是:
demo of various calendar fields 当年的list of Tuesdays and Thursdays demo of converting number to text representation(使用fa_IR
表示区域设置)
另请参阅 Calendar 和 PersianCalendar API。
Java 8 以后:
为了使用 java.time
类,如 ZonedDateTime
或 LocalDateTime
,您可以简单地使用以下方法将波斯日期转换为首选类:
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"));
关于罐子大小的备注
如果您担心 icu4j 的 jar 大小,那么您可以重建它并使用 Calendar 模块 (2,176KB)。更多信息:ver. 57 or earlier,ver. 58 or later 使用 ICU Data Build Tool。
【讨论】:
@deadManN 我更新了我的答案。我希望它会有所帮助。 @deadManN 如果 daysInMonth 是指某个月份的最大天数,则可以通过调用getActualMaximum(Calendar.DAY_OF_MONTH)
来实现您要查找的内容。我更新了我的答案以展示如何使用它。
我认为是你犯了错误,因为我检查了getActualMaximum(Calendar.DAY_OF_MONTH)
之前、当前和明年的所有月份,结果是正确的。您是否知道基于 Java 日历的月份为零?如果你在月份字段中输入 5,它实际上意味着第 6 个月而不是第 5 个月! 11(第 12 个月)也是如此。如果不是这样,您能否提供导致错误行为的确切日期?
据我所知,唯一“非常规”的事情是几个月是从零开始的,没什么好担心的。 (实际上,这并不是非常规的,因为月份在某种程度上是一个枚举!)
最佳答案! 因为您指出:“它是 Unicode Consortium 的一部分,非常可靠,可用于任何 Java 项目”。另请考虑从 Android 7.0(API 级别 24)开始,Android 公开了 ICU4J API 的子集,供应用开发者在 android.icu
包下使用。查看详情here。【参考方案4】:
这个方法很精确,也支持闰年
解释:
第 1 步: 今天的时间包含当前时间
第 2 步: 为 gregorian 和 jalali 日创建两个数组(g_days_in_month&j_days_in_month)
第 3 步: 为日历之间的保留时间差创建变量 (gy,gm,gd) 和变量 g_day_no 数年的天数。
第 4 步: 插入月份中的日期并按天收集。
第 5 步: 将年的天数转换为 jalili 年 (jy)
最后: 从天数设置 jalali 月份, 从 jalali 月份数组中设置 jalali 日。
祝你好运。
Time today = new Time(Time.getCurrentTimezone());
today.setToNow();
int Day = (today.monthDay); // Day of the month (0-31)
int Month = (today.month); // Month (0-11)
int Year = (today.year); // Year
String persianDate = GregorianToJalali(Year, Month+1, Day);
private String GregorianToJalali(int g_y, int g_m, int g_d)
int[] g_days_in_month = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;
int[] j_days_in_month = 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29;
int gy = g_y-1600;
int gm = g_m-1;
int gd = g_d-1;
int g_day_no = 365*gy+div(gy+3,4)-div(gy+99,100)+div(gy+399,400);
for (int i=0; i < gm; ++i)
g_day_no += g_days_in_month[i];
if (gm>1 && ((gy%4==0 && gy%100!=0) || (gy%400==0)))
// leap and after Feb
g_day_no++;
g_day_no += gd;
int j_day_no = g_day_no-79;
int j_np = div(j_day_no, 12053); //12053 = 365*33 + 32/4
j_day_no = j_day_no % 12053;
int jy = 979+33*j_np+4*div(j_day_no,1461); // 1461 = 365*4 + 4/4
j_day_no %= 1461;
if (j_day_no >= 366)
jy += div(j_day_no-1, 365);
j_day_no = (j_day_no-1)%365;
int j;
for (j=0; j < 11 && j_day_no >= j_days_in_month[j]; ++j)
j_day_no -= j_days_in_month[j];
int jm = j+1;
int jd = j_day_no+1;
String Result= jy+"/"+jm+"/"+jd;
return (Result);
private int div(float a, float b)
return (int)(a/b);
【讨论】:
你应该尝试解释你的答案,而不是仅仅发布一段代码。【参考方案5】:我的库Time4A(Time4J 的 Android 版本)的最新版本 v3.10-2015g 包含对 Jalali 日历的支持。该库部署了Borkowski 的算法(有效期至公历 2129 年)。实际上,波斯语月份和纪元支持大约 25 种语言(包括波斯语和普什图语,基于 CLDR-28)。
使用示例:
// current date
PersianCalendar jalali = SystemClock.inLocalView().now(PersianCalendar.axis());
System.out.println(jalali); // AP-1394-08-04
// tomorrow
jalali = jalali.plus(CalendarDays.ONE);
System.out.println(jalali); // AP-1394-08-05
// localized format of tomorrow (English and Farsi)
ChronoFormatter<PersianCalendar> f =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.ENGLISH, PersianCalendar.axis());
Locale farsi = new Locale("fa");
System.out.println(f.format(jalali)); // Tuesday, Aban 5, 1394 AP
System.out.println(f.with(farsi).format(jalali)); // سهشنبه, آبان 5, 1394 ه.ش.
// shift back to month Farvardin and format the result
jalali = jalali.with(PersianCalendar.MONTH_OF_YEAR, PersianMonth.FARVARDIN);
System.out.println(f.format(jalali)); // Wednesday, Farvardin 5, 1394 AP
System.out.println(f.with(farsi).format(jalali)); // چهارشنبه, فروردین 5, 1394 ه.ش.
// conversion to gregorian date
System.out.println(jalali); // AP-1394-01-05
System.out.println(jalali.transform(PlainDate.class)); // 2015-03-25
// create new year in persian calendar and show gregorian counter part
jalali = PersianCalendar.of(1394, PersianMonth.FARVARDIN, 1);
System.out.println(jalali.transform(PlainDate.class)); // 2015-03-21
// create new year in gregorian calendar and show persian counter part
PlainDate gregorianDate = PlainDate.of(2015, Month.JANUARY, 1);
System.out.println(gregorianDate.transform(PersianCalendar.class)); // AP-1393-10-11
// delta between gregorian new year and persian new year
System.out.println(CalendarDays.between(gregorianDate, jalali).getAmount()); // 79
与 Android 上的 java.util.Date 的互操作性
由于 Time4A 管理自己的一组不可变类型并且不基于 Android 的主要时间类型,因此我展示了以下桥:
// Time4A => Android
PlainDate gdate = jalali.transform(PlainDate.class);
Moment m1 = gdate.atStartOfDay().inTimezone(ASIA.TEHRAN);
java.util.Date jud = TemporalType.JAVA_UTIL_DATE.from(m1);
// Android => Time4A
java.util.Date input = new java.util.Date();
Moment m2 = TemporalType.JAVA_UTIL_DATE.translate(input);
jalali = m2.toZonalTimestamp(ASIA.TEHRAN).toDate().transform(PersianCalendar.class);
【讨论】:
+1 以使用Borkowski 方法获得最大准确性。我写了Persian Chronology(s) for Joda Time。 Jalali 基于在经度上观察春分时间,Omar Khayyam(由 Borkowski 扩展)从约 450 年的春分预测中推导出了一个快速公式。警告; Khayyam 使用德黑兰经度而不是现在使用的 IRST,因此 1 或 2 闰年可能在接下来的 3k 中关闭。 Meno,请在项目页面上添加一个添加计时到 Time4A 的教程。 @ZubinKavarana 感谢您的评论。作为 JUnit 测试,我确实已经明确验证了我对 Borkowski 的改编在给定的年份范围(约 450 年)内与 Khayyam 完全一致。关于教程:好主意,但有一个问题:“添加计时”是什么意思?我想通过一个关于使用各种日历的页面来扩展我现有的tutorial。您还可以在那里找到online-javadoc。 @ZubinKavarana 如果您想通过“添加计时器”来说明“如何添加新日历”,那么我可以通过在上面提到的教程中添加一个额外的页面来做到这一点。您对添加另一个日历有什么想法、建议或计划吗?您也可以在 time4j-github-issue-tracker 上打开一个问题以继续讨论。 我刚刚实现了你的例子,我得到了这两行错误:在 net.time4j.base.ResourceLoader.getInstance(Unknown Source), at net.time4j.SystemClock.ApplicationStarter.initialize(this, ...);
正确初始化了您的应用程序?另请参阅Time4A - 使用部分的代码初始化示例。您的堆栈跟踪表明了该原因。【参考方案6】:
试试这个
import java.util.Calendar;
import java.util.Date;
public class PersianCalendar
String[] weekDayNames =
"شنبه","یکشنبه","دوشنبه",
"سه شنبه", "چهارشنبه",
"پنج شنبه", "جمعه"
;
String[] monthNames =
"فروردین","اردیبهشت","خرداد","تیر", "مرداد","شهریور",
"مهر", "آبان", "آذر","دی", "بهمن","اسفند"
;
String strWeekDay = "";
String strMonth = "";
int day;
int month;
int year;
int ld;
Calendar calendar = Calendar.getInstance();
int gregorianYear =calendar.get(Calendar.YEAR);
int gregorianMonth = calendar.get(Calendar.MONTH)+1;
int gregorianDate = calendar.get(Calendar.DATE);
int WeekDay = calendar.get(Calendar.DAY_OF_WEEK);
int[] buf1 = 0,31,59,90,120,151,181,212,243,273,304,334;
int[] buf2 = 0,31,60, 91,121,152,182, 213, 244, 274,305,335;
public PersianCalendar()
Date gregorianDate = new Date();
calendar.setTime(gregorianDate);
toPersian(gregorianDate);
public PersianCalendar(Date gregorianDate)
calendar.setTime(gregorianDate);
toPersian(gregorianDate);
private void toPersian(Date gregorianDate)
if ((gregorianYear % 4) != 0)
func1();
else
func2();
strMonth = monthNames[month-1];
strWeekDay = weekDayNames[WeekDay];
private void func1()
day = buf1[gregorianMonth - 1] + gregorianDate;
if (day > 79)
day = day - 79;
if (day <= 186)
int day2 = day;
month = (day2 / 31) + 1;
day = (day2 % 31);
if(day2 % 31 == 0)
month--;
day = 31;
year = gregorianYear - 621;
else
int day2 = day - 186;
month = (day2 / 30) + 7;
day = (day2 % 30);
if(day2 % 30 == 0)
month = (day2 / 30) + 6;
day = 30;
year = gregorianYear - 621;
else
ld = gregorianYear > 1996 && gregorianYear % 4 == 1 ? 11 : 10 ;
int day2 = day + ld;
month = (day2 / 30) + 10;
day = (day2 % 30);
if(day2 % 30 == 0)
month--;
day = 30;
year = gregorianYear - 622;
private void func2()
day = buf2[gregorianMonth - 1] + gregorianDate;
ld = gregorianYear >= 1996 ? 79 : 80 ;
if (day > ld)
day = day - ld;
if (day <= 186)
int day2 = day;
month = (day2 / 31) + 1;
day = (day2 % 31);
if(day2 % 31 == 0)
month--;
day = 31;
year = gregorianYear - 621;
else
int day2 = day - 186;
month = (day2 / 30) + 7;
day = (day2 % 30);
if(day2 % 30 == 0 )
month--;
day = 30;
year = gregorianYear - 621;
else
int day2 = day + 10;
month = (day2 / 30) + 10;
day = (day2 % 30);
if(day2 % 30==0)
month--;
day = 30;
year = gregorianYear - 622;
创建实例
PersianCalendar sc = new PersianCalendar();
String s= sc.strWeekDay + " " +sc.day + " " +
sc.strMonth + " " + sc.year;
System.out.print(s);
//setTitle(s);
【讨论】:
【参考方案7】:有一个 persianutils 项目,其中包括一个双向 DateConverter;公历 波斯语 (Jalali)。它是用 Scala 编写的,所以我想在 Java 项目中使用它会很容易。
所使用的算法适用于最高 ~3790 年的公历年和最高 ~3170 年的波斯年。
免责声明:我是 PersianUtils 的作者
【讨论】:
【参考方案8】:您可以将这个稳定且经过测试的库与格式化程序类 Roozh for Java 一起使用。它没有被弃用,并且总是会更新波斯日期时间所需的酷炫功能。
【讨论】:
【参考方案9】:我已经开发了带有回历 - gerogian- shamsi 事件视图的 Android Shamsi datepicker 小部件: https://github.com/irshst/ir.shes.calendar
【讨论】:
【参考方案10】:像这样创建calculateJalaliDate函数; 然后以字符串形式返回 Jalali 日期
public String calculateJalaliDate()
Calendar c = Calendar.getInstance();
String jalaliDate,JalaliMonth;
int jalaliYear,jalaliMonth,calculateMonth,jalaliDay=0,allDays=0;
int day=c.get(Calendar.DAY_OF_MONTH);
int month=c.get(Calendar.MONTH)+1;
int year=c.get(Calendar.YEAR);
switch (month)
case 1: allDays=year*365+31+day;break;
case 2: allDays=year*365+(31+28)+day;break;
case 3: allDays=year*365+(31+28+31)+day;break;
case 4: allDays=year*365+(31+28+31+30)+day;break;
case 5: allDays=year*365+(31+28+31+30+31)+day;break;
case 6: allDays=year*365+(31+28+31+30+31+30)+day;break;
case 7: allDays=year*365+(31+28+31+30+31+30+31)+day;break;
case 8: allDays=year*365+(31+28+31+30+31+30+31+31)+day;break;
case 9: allDays=year*365+(31+28+31+30+31+30+31+31+30)+day;break;
case 10: allDays=year*365+(31+28+31+30+31+30+31+31+30+31)+day;break;
case 11: allDays=year*365+(31+28+31+30+31+30+31+31+30+31+30)+day;break;
case 12: allDays=year*365+(31+28+31+30+31+30+31+31+30+31+30+31)+day;break;
//226899
jalaliYear=( allDays - 227139 )/365+1;
calculateMonth=( allDays - 227139 )%365;
if(calculateMonth<32)jalaliMonth=1;
else if((calculateMonth-31)<32)jalaliMonth=2;jalaliDay=calculateMonth-31;
else if((calculateMonth-62)<32)jalaliMonth=3;jalaliDay=calculateMonth-62;
else if((calculateMonth-93)<32)jalaliMonth=4;jalaliDay=calculateMonth-93;
else if((calculateMonth-124)<32)jalaliMonth=5;jalaliDay=calculateMonth-124;
else if((calculateMonth-155)<32)jalaliMonth=6;jalaliDay=calculateMonth-155;
else if((calculateMonth-186)<31)jalaliMonth=7;jalaliDay=calculateMonth-186;
else if((calculateMonth-216)<31)jalaliMonth=8;jalaliDay=calculateMonth-216;
else if((calculateMonth-246)<31)jalaliMonth=9;jalaliDay=calculateMonth-246;
else if((calculateMonth-276)<31)jalaliMonth=10;jalaliDay=calculateMonth-276;
else if((calculateMonth-306)<31)jalaliMonth=11;jalaliDay=calculateMonth-306;
else
jalaliMonth=12;
if((jalaliYear%4)==0)jalaliDay=calculateMonth-336;
else jalaliDay=calculateMonth-335;
/*switch (jalaliMonth)
case 1:JalaliMonth="فروردین"; break;
case 2:JalaliMonth="اردیبهشت"; break;
case 3:JalaliMonth="خرداد"; break;
case 4:JalaliMonth="تیر"; break;
case 5:JalaliMonth="مرداد"; break;
case 6:JalaliMonth="شهریور"; break;
case 7:JalaliMonth="مهر"; break;
case 8:JalaliMonth="آبان"; break;
case 9:JalaliMonth="آذر"; break;
case 10:JalaliMonth="دی"; break;
case 11:JalaliMonth="بهمن"; break;
case 12:JalaliMonth="اسفند"; break;
*/
jalaliDate=String.valueOf(jalaliYear)+"/"+String.valueOf(jalaliMonth)+"/"+String.valueOf(jalaliDay);
return jalaliDate;
【讨论】:
【参考方案11】:除了Time4A、icu4j这些太重的库之外,我写了一个类来准确处理波斯历,你可以在这里找到它: https://github.com/hadilq/java-persian-calendar/blob/master/persian/src/main/java/ir/hadilq/PersianCalendar.java
正如您在其测试中发现的那样,此类支持从回历之前的 3000 年到回历之后的 3000 年。
【讨论】:
谢谢。对于不想在项目中放置第三方重型库的开发人员来说,这是最好的解决方案。以上是关于Android中是不是有波斯(Shamsi或Jalali)日历的库或算法? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
问号显示像“????”而是来自 php 或 mysql 的波斯字符......! [复制]