com.squarespace.cldrengine.api.PersianDate Maven / Gradle / Ivy
The newest version!
package com.squarespace.cldrengine.api;
import com.squarespace.cldrengine.internal.MathFix;
import com.squarespace.cldrengine.utils.MathUtil;
/**
* Construct a date using the rules of the Persian calendar.
*
* type: persian
*/
public class PersianDate extends CalendarDate {
public PersianDate(int firstDay, int minDays) {
super(CalendarType.PERSIAN, firstDay, minDays);
}
@Override
public long relatedYear() {
return this.fields[DateField.EXTENDED_YEAR] + 622;
}
@Override
public CalendarDate add(TimePeriod fields) {
Pair result = this._add(fields);
PersianDate d = new PersianDate(this.firstDay, this.minDays);
d._initFromJD(result._1, Math.round(result._2), this.timeZoneId());
return d;
}
@Override
public CalendarDate subtract(TimePeriod fields) {
return this.add(invertPeriod(fields));
}
@Override
public CalendarDate withZone(String zoneId) {
PersianDate d = new PersianDate(this.firstDay, this.minDays);
d._initFromUnixEpoch(this.unixEpoch(), zoneId);
return d;
}
@Override
protected int daysInMonth(long year, int month) {
return MONTH_COUNT[month][leapPersian(year) ? 1 : 0];
}
@Override
protected int daysInYear(long year) {
return leapPersian(year) ? 366 : 365;
}
@Override
protected int monthCount() {
return 12;
}
@Override
public String toString() {
return _toString("Persian");
}
public static PersianDate fromUnixEpoch(long epoch, String zoneId, int firstDay, int minDays) {
return new PersianDate(firstDay, minDays)._initFromUnixEpoch(epoch, zoneId);
}
protected PersianDate _initFromUnixEpoch(long epoch, String zoneId) {
super.initFromUnixEpoch(epoch, zoneId);
this.initFields(this.fields);
return this;
}
protected PersianDate _initFromJD(long jd, long msDay, String zoneId) {
super.initFromJD(jd, msDay, zoneId);
this.initFields(this.fields);
return this;
}
@Override
protected void initFields(long[] f) {
this.computePersianFields(f);
}
@Override
protected long monthStart(long eyear, double month, boolean useMonth) {
long jd = CalendarConstants.JD_PERSIAN_EPOCH - 1 + 365 * (eyear - 1) +
(long)Math.floor((8 * eyear + 21) / 33);
if (month != 0) {
int m = (int)Math.floor(month);
double d = month - m;
jd += MONTH_COUNT[m][2];
// Check if there is a fractional month part, and if so add the number
// of the days in the next month multiplied by the fraction
if (d != 0) {
// number of days in Esfand determined by:
// "number of days between two vernal equinoxes"
boolean isLeap = leapPersian(eyear - 1);
// note: the 'month' parameter must always be <= # months in the calendar
// year, so <= 12 in this case.
jd += d * MONTH_COUNT[m + 1][isLeap ? 1 : 0];
}
}
return jd;
}
private void computePersianFields(long[] f) {
long jd = f[DateField.JULIAN_DAY];
long days = jd - CalendarConstants.JD_PERSIAN_EPOCH;
long year = 1 + (long)MathFix.floorDiv((33 * days + 3), 12053);
long favardin1 = 365 * (year - 1) + (long)MathFix.floorDiv((8 * year + 21), 33);
long doy = days - favardin1;
int month = (int)(doy < 216 ? MathFix.floorDiv(doy, 31) : MathFix.floorDiv(doy - 6, 30));
long dom = doy - MONTH_COUNT[month][2] + 1;
f[DateField.ERA] = 0;
f[DateField.YEAR] = year;
f[DateField.EXTENDED_YEAR] = year;
f[DateField.MONTH] = month + 1;
f[DateField.DAY_OF_MONTH] = dom;
f[DateField.DAY_OF_YEAR] = doy + 1;
f[DateField.IS_LEAP] = leapPersian(year) ? 1 : 0;
}
private boolean leapPersian(long year) {
long[] rem = new long[] { 0 };
MathUtil.floorDiv(25 * year + 11, 33, rem);
return rem[0] < 8;
}
private static final int[][] MONTH_COUNT = new int[][] {
new int[] { 31, 31, 0 }, // Farvardin
new int[] { 31, 31, 31 }, // Ordibehesht
new int[] { 31, 31, 62 }, // Khordad
new int[] { 31, 31, 93 }, // Tir
new int[] { 31, 31, 124 }, // Mordad
new int[] { 31, 31, 155 }, // Shahrivar
new int[] { 30, 30, 186 }, // Mehr
new int[] { 30, 30, 216 }, // Aban
new int[] { 30, 30, 246 }, // Azar
new int[] { 30, 30, 276 }, // Dey
new int[] { 30, 30, 306 }, // Bahman
new int[] { 29, 30, 336 } // Esfand
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy