PersianMaterialDateTimePicker
PersianMaterialDateTimePicker copied to clipboard
PersianCalendar Lags
Hi there,
There's an issue in the PersianCalendar class. it lags a day behind. you can check it out by setting your device date to say 1/6/1394 00:10 AM. What you get is 31/5/1394. I'm looking forward to fix it. God willingly I'll post the result :-)
Here is the corrected code, hope it helps :)
/**
* Persian Calendar see: http://code.google.com/p/persian-calendar/
Copyright (C) 2012 [email protected]
PersianCalendar.java
Persian Calendar is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mohamadamin.persianmaterialdatetimepicker.utils;
/**
* Modified By Ahmad Siavashi: [email protected] / Summer 2015
* The Original PersianCalendar class had problem @ Times like : yyyy-MM-dd 00:15 AM
* Amir Mehdizadeh's JalaliCalendar @ https://github.com/amirmehdizadeh/JalaliCalendar got used to correct it.
* If you found any other problem, please let me know about it.
* Regards,
*/
/**
* Persian Calendar see: http://code.google.com/p/persian-calendar/
Copyright (C) 2012 [email protected]
PersianCalendar.java
Persian Calendar is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Persian Calendar see: http://code.google.com/p/persian-calendar/
Copyright (C) 2012 [email protected]
PersianCalendar.java
Persian Calendar is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
/**
*
* <strong> Persian(Shamsi) calendar </strong>
* <p>
* </p>
* <p>
* The calendar consists of 12 months, the first six of which are 31 days, the
* next five 30 days, and the final month 29 days in a normal year and 30 days
* in a leap year.
* </p>
* <p>
* As one of the few calendars designed in the era of accurate positional
* astronomy, the Persian calendar uses a very complex leap year structure which
* makes it the most accurate solar calendar in use today. Years are grouped
* into cycles which begin with four normal years after which every fourth
* subsequent year in the cycle is a leap year. Cycles are grouped into grand
* cycles of either 128 years (composed of cycles of 29, 33, 33, and 33 years)
* or 132 years, containing cycles of of 29, 33, 33, and 37 years. A great grand
* cycle is composed of 21 consecutive 128 year grand cycles and a final 132
* grand cycle, for a total of 2820 years. The pattern of normal and leap years
* which began in 1925 will not repeat until the year 4745!
* </p>
* </p> Each 2820 year great grand cycle contains 2137 normal years of 365 days
* and 683 leap years of 366 days, with the average year length over the great
* grand cycle of 365.24219852. So close is this to the actual solar tropical
* year of 365.24219878 days that the Persian calendar accumulates an error of
* one day only every 3.8 million years. As a purely solar calendar, months are
* not synchronized with the phases of the Moon. </p>
* <p>
* </p>
*
* <p>
* <strong>PersianCalendar</strong> by extending Default GregorianCalendar
* provides capabilities such as:
* </p>
* <p>
* </p>
*
* <li>you can set the date in Persian by setPersianDate(persianYear,
* persianMonth, persianDay) and get the Gregorian date or vice versa</li>
* <p>
* </p>
* <li>determine is the current date is Leap year in persian calendar or not by
* IsPersianLeapYear()</li>
* <p>
* </p>
* <li>getPersian short and long Date String getPersianShortDate() and
* getPersianLongDate you also can set delimiter to assign delimiter of returned
* dateString</li>
* <p>
* </p>
* <li>Parse string based on assigned delimiter</li>
* <p>
* </p>
* <p>
* </p>
* <p>
* </p>
* <p>
* <strong> Example </strong>
* </p>
* <p>
* </p>
*
* <pre>
* {@code
* PersianCalendar persianCal = new PersianCalendar();
* System.out.println(persianCal.getPersianShortDate());
*
* persianCal.set(1982, Calendar.MAY, 22);
* System.out.println(persianCal.getPersianShortDate());
*
* persianCal.setDelimiter(" , ");
* persianCal.parse("1361 , 03 , 01");
* System.out.println(persianCal.getPersianShortDate());
*
* persianCal.setPersianDate(1361, 3, 1);
* System.out.println(persianCal.getPersianLongDate());
* System.out.println(persianCal.getTime());
*
* persianCal.addPersianDate(Calendar.MONTH, 33);
* persianCal.addPersianDate(Calendar.YEAR, 5);
* persianCal.addPersianDate(Calendar.DATE, 50);
*
* }
*
* <pre>
* @author Morteza contact: <a href="mailto:[email protected]">[email protected]</a>
* @version 1.1
*/
public class PersianCalendar extends GregorianCalendar {
private static final long serialVersionUID = 5541422440580682494L;
private int persianYear;
private int persianMonth;
private int persianDay;
// use to seperate PersianDate's field and also Parse the DateString based
// on this delimiter
private String delimiter = "/";
private long convertToMilis(long julianDate) {
return PersianCalendarConstants.MILLIS_JULIAN_EPOCH
+ julianDate
* PersianCalendarConstants.MILLIS_OF_A_DAY
+ PersianCalendarUtils.ceil(getTimeInMillis()
- PersianCalendarConstants.MILLIS_JULIAN_EPOCH,
PersianCalendarConstants.MILLIS_OF_A_DAY);
}
/**
* default constructor
*
* most of the time we don't care about TimeZone when we persisting Date or
* doing some calculation on date. <strong> Default TimeZone was set to
* "GMT" </strong> in order to make developer to work more convenient with
* the library; however you can change the TimeZone as you do in
* GregorianCalendar by calling setTimeZone()
*/
public PersianCalendar() {
// setTimeZone(TimeZone.getTimeZone("GMT"));
super(TimeZone.getDefault(), Locale.getDefault());
}
/**
* Calculate persian date from current Date and populates the corresponding
* fields(persianYear, persianMonth, persianDay)
*/
protected void calculatePersianDate() {
// long julianDate = ((long) Math.floor((getTimeInMillis() - PersianCalendarConstants.MILLIS_JULIAN_EPOCH ))/
// PersianCalendarConstants.MILLIS_OF_A_DAY);
// long PersianRowDate = PersianCalendarUtils.julianToPersian(julianDate);
// long year = PersianRowDate >> 16;
// int month = (int) (PersianRowDate & 0xff00) >> 8;
// int day = (int) (PersianRowDate & 0xff);
// this.persianYear = (int) (year > 0 ? year : year - 1);
// this.persianMonth = month;
// this.persianDay = day;
YearMonthDay persianYearMonthDay = PersianCalendar.gregorianToJalali(new YearMonthDay(this.get(PersianCalendar.YEAR), this.get(PersianCalendar.MONTH), this.get(PersianCalendar.DAY_OF_MONTH)));
this.persianYear = persianYearMonthDay.year;
this.persianMonth = persianYearMonthDay.month;
this.persianDay = persianYearMonthDay.day;
}
/**
*
* Determines if the given year is a leap year in persian calendar. Returns
* true if the given year is a leap year.
*
* @return boolean
*/
public boolean isPersianLeapYear() {
// calculatePersianDate();
return PersianCalendarUtils.isPersianLeapYear(this.persianYear);
}
/**
* set the persian date it converts PersianDate to the Julian and assigned
* equivalent milliseconds to the instance
*
* @param persianYear
* @param persianMonth
* @param persianDay
*/
public void setPersianDate(int persianYear, int persianMonth, int persianDay) {
persianMonth += 1; // TODO
this.persianYear = persianYear;
this.persianMonth = persianMonth;
this.persianDay = persianDay;
// setTimeInMillis(convertToMilis(PersianCalendarUtils.persianToJulian(
// this.persianYear > 0 ? this.persianYear : this.persianYear + 1,
// this.persianMonth - 1, this.persianDay)));
YearMonthDay gregorianYearMonthDay = jalaliToGregorian(new YearMonthDay(persianYear, this.persianMonth - 1, persianDay));
this.set(gregorianYearMonthDay.year, gregorianYearMonthDay.month, gregorianYearMonthDay.day);
}
public int getPersianYear() {
// calculatePersianDate();
return this.persianYear;
}
/**
*
* @return int persian month number
*/
public int getPersianMonth() {
// calculatePersianDate();
return this.persianMonth;
}
/**
*
* @return String persian month name
*/
public String getPersianMonthName() {
// calculatePersianDate();
return PersianCalendarConstants.persianMonthNames[this.persianMonth];
}
/**
*
* @return int Persian day in month
*/
public int getPersianDay() {
// calculatePersianDate();
return this.persianDay;
}
/**
*
* @return String Name of the day in week
*/
public String getPersianWeekDayName() {
switch (get(DAY_OF_WEEK)) {
case SATURDAY:
return PersianCalendarConstants.persianWeekDays[0];
case SUNDAY:
return PersianCalendarConstants.persianWeekDays[1];
case MONDAY:
return PersianCalendarConstants.persianWeekDays[2];
case TUESDAY:
return PersianCalendarConstants.persianWeekDays[3];
case WEDNESDAY:
return PersianCalendarConstants.persianWeekDays[4];
case THURSDAY:
return PersianCalendarConstants.persianWeekDays[5];
default:
return PersianCalendarConstants.persianWeekDays[6];
}
}
/**
*
* @return String of Persian Date ex: شنبه 01 خرداد 1361
*/
public String getPersianLongDate() {
return getPersianWeekDayName() + " "
+ formatToMilitary(this.persianDay) + " "
+ getPersianMonthName() + " " + this.persianYear;
}
/**
*
* @return String of persian date formatted by
* 'YYYY[delimiter]mm[delimiter]dd' default delimiter is '/'
*/
public String getPersianShortDate() {
// calculatePersianDate();
return "" + formatToMilitary(this.persianYear) + delimiter
+ formatToMilitary(getPersianMonth()) + delimiter
+ formatToMilitary(this.persianDay);
}
private String formatToMilitary(int i) {
return (i < 9) ? "0" + i : String.valueOf(i);
}
/**
* add specific amout of fields to the current date for now doesnt handle
* before 1 farvardin hejri (before epoch)
*
* @param field
* @param amount
* <pre>
* Usage:
* {@code
* addPersianDate(Calendar.YEAR, 2);
* addPersianDate(Calendar.MONTH, 3);
* }
* </pre>
*
* u can also use Calendar.HOUR_OF_DAY,Calendar.MINUTE,
* Calendar.SECOND, Calendar.MILLISECOND etc
*/
//
public void addPersianDate(int field, int amount) {
if (amount == 0) {
return; // Do nothing!
}
if (field < 0 || field >= ZONE_OFFSET) {
throw new IllegalArgumentException();
}
if (field == YEAR) {
setPersianDate(this.persianYear + amount, getPersianMonth(),
this.persianDay);
return;
} else if (field == MONTH) {
setPersianDate(this.persianYear
+ ((getPersianMonth() + amount) / 12),
(getPersianMonth() + amount) % 12, this.persianDay);
return;
}
add(field, amount);
calculatePersianDate();
}
/**
* <pre>
* use <code>{@link PersianDateParser}</code> to parse string
* and get the Persian Date.
* </pre>
*
* @see PersianDateParser
* @param dateString
*/
public void parse(String dateString) {
PersianCalendar p = new PersianDateParser(dateString, delimiter)
.getPersianDate();
setPersianDate(p.getPersianYear(), p.getPersianMonth(),
p.getPersianDay());
}
public String getDelimiter() {
return delimiter;
}
/**
* assign delimiter to use as a separator of date fields.
*
* @param delimiter
*/
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
@Override
public String toString() {
String str = super.toString();
return str.substring(0, str.length() - 1) + ",PersianDate="
+ getPersianShortDate() + "]";
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public void set(int field, int value) {
super.set(field, value);
calculatePersianDate();
}
@Override
public void setTimeInMillis(long millis) {
super.setTimeInMillis(millis);
calculatePersianDate();
}
@Override
public void setTimeZone(TimeZone zone) {
super.setTimeZone(zone);
calculatePersianDate();
}
// Helper Functions
public static int gregorianDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31 };
public static int jalaliDaysInMonth[] = { 31, 31, 31, 31, 31, 31, 30, 30,
30, 30, 30, 29 };
public static YearMonthDay gregorianToJalali(YearMonthDay gregorian) {
if (gregorian.getMonth() > 11 || gregorian.getMonth() < -11) {
throw new IllegalArgumentException();
}
int jalaliYear;
int jalaliMonth;
int jalaliDay;
int gregorianDayNo, jalaliDayNo;
int jalaliNP;
int i;
gregorian.setYear(gregorian.getYear() - 1600);
gregorian.setDay(gregorian.getDay() - 1);
gregorianDayNo = 365 * gregorian.getYear() + (int) Math.floor((gregorian.getYear() + 3) / 4)
- (int) Math.floor((gregorian.getYear() + 99) / 100)
+ (int) Math.floor((gregorian.getYear() + 399) / 400);
for (i = 0; i < gregorian.getMonth(); ++i) {
gregorianDayNo += gregorianDaysInMonth[i];
}
if (gregorian.getMonth() > 1 && ((gregorian.getYear() % 4 == 0 && gregorian.getYear() % 100 != 0)
|| (gregorian.getYear() % 400 == 0))) {
++gregorianDayNo;
}
gregorianDayNo += gregorian.getDay();
jalaliDayNo = gregorianDayNo - 79;
jalaliNP = (int) Math.floor(jalaliDayNo / 12053);
jalaliDayNo = jalaliDayNo % 12053;
jalaliYear = 979 + 33 * jalaliNP + 4 * (int) (jalaliDayNo / 1461);
jalaliDayNo = jalaliDayNo % 1461;
if (jalaliDayNo >= 366) {
jalaliYear += (int) Math.floor((jalaliDayNo - 1) / 365);
jalaliDayNo = (jalaliDayNo - 1) % 365;
}
for (i = 0; i < 11 && jalaliDayNo >= jalaliDaysInMonth[i]; ++i) {
jalaliDayNo -= jalaliDaysInMonth[i];
}
jalaliMonth = i;
jalaliDay = jalaliDayNo + 1;
return new YearMonthDay(jalaliYear, jalaliMonth, jalaliDay);
}
public static YearMonthDay jalaliToGregorian(YearMonthDay jalali) {
if (jalali.getMonth() > 11 || jalali.getMonth() < -11) {
throw new IllegalArgumentException();
}
int gregorianYear;
int gregorianMonth;
int gregorianDay;
int gregorianDayNo, jalaliDayNo;
int leap;
int i;
jalali.setYear(jalali.getYear() - 979);
jalali.setDay(jalali.getDay() - 1);
jalaliDayNo = 365 * jalali.getYear() + (int) (jalali.getYear() / 33) * 8
+ (int) Math.floor(((jalali.getYear() % 33) + 3) / 4);
for (i = 0; i < jalali.getMonth(); ++i) {
jalaliDayNo += jalaliDaysInMonth[i];
}
jalaliDayNo += jalali.getDay();
gregorianDayNo = jalaliDayNo + 79;
gregorianYear = 1600 + 400 * (int) Math.floor(gregorianDayNo / 146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
gregorianDayNo = gregorianDayNo % 146097;
leap = 1;
if (gregorianDayNo >= 36525) /* 36525 = 365*100 + 100/4 */ {
gregorianDayNo--;
gregorianYear += 100 * (int) Math.floor(gregorianDayNo / 36524); /* 36524 = 365*100 + 100/4 - 100/100 */
gregorianDayNo = gregorianDayNo % 36524;
if (gregorianDayNo >= 365) {
gregorianDayNo++;
} else {
leap = 0;
}
}
gregorianYear += 4 * (int) Math.floor(gregorianDayNo / 1461); /* 1461 = 365*4 + 4/4 */
gregorianDayNo = gregorianDayNo % 1461;
if (gregorianDayNo >= 366) {
leap = 0;
gregorianDayNo--;
gregorianYear += (int) Math.floor(gregorianDayNo / 365);
gregorianDayNo = gregorianDayNo % 365;
}
for (i = 0; gregorianDayNo >= gregorianDaysInMonth[i] + ((i == 1 && leap == 1) ? i : 0); i++) {
gregorianDayNo -= gregorianDaysInMonth[i] + ((i == 1 && leap == 1) ? i : 0);
}
gregorianMonth = i;
gregorianDay = gregorianDayNo + 1;
return new YearMonthDay(gregorianYear, gregorianMonth, gregorianDay);
}
static class YearMonthDay {
public YearMonthDay(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
private int year;
private int month;
private int day;
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int date) {
this.day = date;
}
public String toString() {
return getYear() + "/" + getMonth() + "/" + getDay();
}
}
}
Thanks. This will be fixed this in the next version and your code will (probably) be used. The next version is coming out this Friday.
سلام جناب محمد امین لایبرری چطور میشه به پروژه اضافه کرد. ببخشید فایل دانلودیش کجاست. ممنونم.
@MansoorJafari سلام از این صفحه استفاده کنید:
https://github.com/mohamad-amin/PersianMaterialDateTimePicker/wiki/Importing-to-Android-Studio
Hi, Use this page: https://github.com/mohamad-amin/PersianMaterialDateTimePicker/wiki/Importing-to-Android-Studio
خیلی ممنونم جناب محمد عزیز مشکل حل شد. فقط قابلیت تغییر فونت داره؟؟ ممنونم.
نه متاسفانه
سلام مجدد چطور میشه تاریخ رو با فرمت زیر دریافت کرد. 1390/09/10
یعنی کاملا همه دو رقمی باشند. YYYY/MM/DD ممنونم.یاعلی
سلام مشکل من timeZone هستش persianCalendar.get(PersianCalendar.HOUR_OF_DAY) ساعت رو 3 ساعت عقب تر نشون میده واسه همین اگه ساعت بین 00:00 تا 3:30 باشه یک روز عقب تر نشون میده چیکارش کنم
متاسفانه منم همین مشکلی که دوستمون گفتن رو دارم یعنی نصف شب تاریخ به مدت چند ساعت به روز قبل برمیگرده
دقیقا ، من هم با مشکل تایم زون مواجه هستم که ۳.۳۰ دقیقه عقب هست . کسی راهکاری نداره ؟
من هم همین مشکل رو دارم این سه ساعت و نیم که میفرمایید مربوط میشه به تایم زون