PDA

View Full Version : Persian DatePicker (Jalali Date)



navaro_81
27 Sep 2009, 5:23 AM
Dear Persian Users,

I Overrided DatePicker And Date to adding persian calendar to them. but it has some bug/:). please use it, Debug and share it.

Tnx
Ali



/*
* Ext JS Library 3.0 Pre-alpha
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license

* Author: Alireza Javid Tajrishi
* Email : navaro_81@yahoo.com
* TEL : +98-912-3894863

*/

Date.SolarMonthNames=['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور','مهر','آبان','آذر','دي','بهمن','اسفند'];
Date.SolarShortMonthNames=['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور','مهر','آبان','آذر','دي','بهمن','اسفند'];

Ext.override(Date, {
calculateSolarDate: function() {
g_y=this.getFullYear();
g_m=this.getMonth()+1;
g_d=this.getDate();
var g_days_in_month = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var j_days_in_month = new Array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var j_np;

var i;
gy = g_y-1600;
gm = g_m-1;
gd = g_d-1;

g_day_no = 365*gy+Math.floor((gy+3)/4)-Math.floor((gy+99)/100)+Math.floor((gy+399)/400);
for (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;

j_day_no = g_day_no-79;

j_np = Math.floor(j_day_no / 12053);
j_day_no %= 12053;

jy = 979+33*j_np+4*Math.floor((j_day_no/1461));
j_day_no %= 1461;

if (j_day_no >= 366) {
jy += Math.floor((j_day_no-1)/365);
j_day_no = (j_day_no-1)%365;
}

for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {
j_day_no -= j_days_in_month[i];
}
jm = i;
jd = j_day_no;

this.solarYear=jy;
this.solarMonth=jm;
this.solarDay=jd+1;
},
getSolarDaysInMonth: function (){
this.calculateSolarDate();
if (this.solarMonth<6)
return 31;
if (this.solarMonth<11)
return 30;
if (this.isLeapYear())
return 30;
else
return 29;
},
getSolarDate: function (){
this.calculateSolarDate();
return this.solarDay;
},
getSolarMonth: function (){
this.calculateSolarDate();
return this.solarMonth;
},
getSolarFullYear: function (){
this.calculateSolarDate();
return this.solarYear;
},
getSolarFirstDateOfMonth: function (){
this.calculateSolarDate();
return new Date(this.getFullYear(), this.getMonth(), this.getDate() - this.solarDay + 1);
}
});
Ext.override(Ext.DatePicker, {
calendarType:'G',
startDay:6,
onRender : function(container, position){
var m = [
'<table cellspacing="0">',
'<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',
'<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
var dn = this.dayNames;

for(var i = 0; i < 7; i++){
var d = this.startDay+i;
if(d > 6){
d = d-7;
}
m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
}
m[m.length] = "</tr></thead><tbody><tr>";
for(var i = 0; i < 42; i++) {
if(i % 7 == 0 && i != 0){
m[m.length] = "</tr><tr>";
}
m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
}
m.push('</tr></tbody></table></td></tr>',
this.showToday ? '<tr><td colspan="3" class="x-date-bottom" align="center"></td></tr>' : '',
'</table><div class="x-date-mp"></div>');

var el = document.createElement("div");
el.className = "x-date-picker";
el.innerHTML = m.join("");

container.dom.insertBefore(el, position);

this.el = Ext.get(el);
this.eventEl = Ext.get(el.firstChild);

new Ext.util.ClickRepeater(this.el.child("td.x-date-left a"), {
handler: this.showPrevMonth,
scope: this,
preventDefault:true,
stopDefault:true
});

new Ext.util.ClickRepeater(this.el.child("td.x-date-right a"), {
handler: this.showNextMonth,
scope: this,
preventDefault:true,
stopDefault:true
});

this.mon(this.eventEl, "mousewheel", this.handleMouseWheel, this);

this.monthPicker = this.el.down('div.x-date-mp');
this.monthPicker.enableDisplayMode('block');

var kn = new Ext.KeyNav(this.eventEl, {
"left" : function(e){
e.ctrlKey ?
this.showPrevMonth() :
this.update(this.activeDate.add("d", -1));
},

"right" : function(e){
e.ctrlKey ?
this.showNextMonth() :
this.update(this.activeDate.add("d", 1));
},

"up" : function(e){
e.ctrlKey ?
this.showNextYear() :
this.update(this.activeDate.add("d", -7));
},

"down" : function(e){
e.ctrlKey ?
this.showPrevYear() :
this.update(this.activeDate.add("d", 7));
},

"pageUp" : function(e){
this.showNextMonth();
},

"pageDown" : function(e){
this.showPrevMonth();
},

"enter" : function(e){
e.stopPropagation();
return true;
},

scope : this
});

this.mon(this.eventEl, "click", this.handleDateClick, this, {delegate: "a.x-date-date"});

this.el.unselectable();

this.cells = this.el.select("table.x-date-inner tbody td");
this.textNodes = this.el.query("table.x-date-inner tbody span");

this.mbtn = new Ext.Button({
text: "&#160;",
tooltip: this.monthYearText,
renderTo: this.el.child("td.x-date-middle", true)
});

this.mon(this.mbtn, 'click', this.showMonthPicker, this);
this.mbtn.el.child('em').addClass("x-btn-arrow");

if(this.showToday){
this.todayKeyListener = this.eventEl.addKeyListener(Ext.EventObject.SPACE, this.selectToday, this);
var today = (new Date()).dateFormat(this.format);
this.todayBtn = new Ext.Button({
renderTo: this.el.child("td.x-date-bottom", true),
text: String.format(this.todayText, today),
tooltip: String.format(this.todayTip, today),
handler: this.selectToday,
scope: this
});
}
new Ext.Button({
renderTo: this.el.child("td.x-date-bottom", true),
text: 'CH',
handler: this.changeCalendar,
scope: this
});

if(Ext.isIE){
this.el.repaint();
}
this.update(this.value);
},
updateMPYear : function(y){
this.mpyear = y;
var ys = this.mpYears.elements;
for(var i = 1; i <= 10; i++){
var td = ys[i-1], y2;
if((i%2) == 0){
y2 = y + Math.round(i * .5);
td.firstChild.innerHTML = y2 - (this.calendarType=='G'?0:622);
td.xyear = y2;
}else{
y2 = y - (5-Math.round(i * .5));
td.firstChild.innerHTML = y2 - (this.calendarType=='G'?0:622);
td.xyear = y2;
}
this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
}
},
changeCalendar: function(){
this.calendarType=(this.calendarType=='G')?'J':'G';
this.update(this.value, true);
this.updateMPYear(this.value.getFullYear())

},
update : function(date, forceRefresh){
this.monthNames=(this.calendarType=='G')?Date.monthNames:Date.SolarMonthNames;

var vd = this.activeDate;
this.activeDate = date;
if(!forceRefresh && vd && this.el){
var t = date.getTime();
if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
this.cells.removeClass("x-date-selected");
this.cells.each(function(c){
if(c.dom.firstChild.dateValue == t){
c.addClass("x-date-selected");
setTimeout(function(){
try{c.dom.firstChild.focus();}catch(e){}
}, 50);
return false;
}
});
return;
}
}

var days = date.getDaysInMonth();
var firstOfMonth = (this.calendarType=='G')?
date.getFirstDateOfMonth():
date.getSolarFirstDateOfMonth();

var startingPos = firstOfMonth.getDay()-this.startDay;

if(startingPos <= this.startDay)
startingPos += 7;


var pm =date.add("mo", -1);
var prevStart = ((this.calendarType=='G')?
pm.getDaysInMonth():
pm.getSolarDaysInMonth());

var cells = this.cells.elements;
var textEls = this.textNodes;
days += startingPos;


/////////////////////////////////////////////////////////////////////////////////////////////////////////
// convert everything to numbers so it's fast
var day = 86400000;
var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
var today = new Date().clearTime().getTime();
var sel = date.clearTime().getTime();
var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
var ddMatch = this.disabledDatesRE;
var ddText = this.disabledDatesText;
var ddays = this.disabledDays ? this.disabledDays.join("") : false;
var ddaysText = this.disabledDaysText;
var format = this.format;

if(this.showToday){
var td = new Date().clearTime();
var disable = (td < min || td > max ||
(ddMatch && format && ddMatch.test(td.dateFormat(format))) ||
(ddays && ddays.indexOf(td.getDay()) != -1));

this.todayBtn.setDisabled(disable);
this.todayKeyListener[disable ? 'disable' : 'enable']();
}

var setCellClass = function(cal, cell){
cell.title = "";
var t = d.getTime() - day;
cell.firstChild.dateValue = t;
if(t == today-day){
cell.className += " x-date-today";
cell.title = cal.todayText;
}
if(t == sel-day){
cell.className += " x-date-selected";
setTimeout(function(){
try{cell.firstChild.focus();}catch(e){}
}, 50);
}
// disabling
if(t < min) {
cell.className = " x-date-disabled";
cell.title = cal.minText;
return;
}
if(t > max) {
cell.className = " x-date-disabled";
cell.title = cal.maxText;
return;
}
if(ddays){
if(ddays.indexOf(d.getDay()) != -1){
cell.title = ddaysText;
cell.className = " x-date-disabled";
}
}
if(ddMatch && format){
var fvalue = d.dateFormat(format);
if(ddMatch.test(fvalue)){
cell.title = ddText.replace("%0", fvalue);
cell.className = " x-date-disabled";
}
}
};


if (this.calendarType=='G')
d.setDate(d.getDate()-d.getDay()+d.getFirstDateOfMonth().getDate()-startingPos);
else
d.setDate(d.getDate()-d.getDay()+d.getSolarFirstDateOfMonth().getDate()-startingPos);


i=0;
for(; i < startingPos; i++) {

textEls[i].innerHTML = (++prevStart);
d.setDate(d.getDate()+1);
cells[i].className = "x-date-prevday";
setCellClass(this, cells[i]);
}
for(; i < days; i++){
var intDay = i - startingPos + 1;
textEls[i].innerHTML = (intDay);// + '<br>' + ((d.getMonth()+1) + '/' +d.getDate()) + '<BR><small>' + (d.getSolarMonth()+1) + '/' +d.getSolarDate() + '</SMALL>';
d.setDate(d.getDate()+1);
cells[i].className = "x-date-active";
setCellClass(this, cells[i]);
}
var extraDays = 0;
for(; i < 42; i++) {
textEls[i].innerHTML = (++extraDays);
d.setDate(d.getDate()+1);
cells[i].className = "x-date-nextday";
setCellClass(this, cells[i]);
}

this.mbtn.setText(((this.calendarType=='G')?
this.monthNames[date.getMonth()]:
Date.SolarMonthNames[date.getSolarMonth()]) + " " +
((this.calendarType=='G')?
date.getFullYear():
date.getSolarFullYear()));

if(!this.internalRender){
var main = this.el.dom.firstChild;
var w = main.offsetWidth;
this.el.setWidth(w + this.el.getBorderWidth("lr"));
Ext.fly(main).setWidth(w);
this.internalRender = true;
if(Ext.isOpera && !this.secondPass){
main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
this.secondPass = true;
this.update.defer(10, this, [date]);
}
}
}
});

vahid4134
29 Sep 2009, 11:41 PM
very thanks Ali
I apologize for bad English
For Leap Year for Persian date must use another algoritm


Ext.override(Date, {
calculateSolarDate: function() {
g_y=this.getFullYear();
g_m=this.getMonth()+1;
g_d=this.getDate();
var g_days_in_month = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
var j_days_in_month = new Array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var j_np;

var i;
gy = g_y-1600;
gm = g_m-1;
gd = g_d-1;

g_day_no = 365*gy+Math.floor((gy+3)/4)-Math.floor((gy+99)/100)+Math.floor((gy+399)/400);
for (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;

j_day_no = g_day_no-79;

j_np = Math.floor(j_day_no / 12053);
j_day_no %= 12053;

jy = 979+33*j_np+4*Math.floor((j_day_no/1461));
j_day_no %= 1461;

if (j_day_no >= 366) {
jy += Math.floor((j_day_no-1)/365);
j_day_no = (j_day_no-1)%365;
}

for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {
j_day_no -= j_days_in_month[i];
}
jm = i;
jd = j_day_no;

this.solarYear=jy;
this.solarMonth=jm;
this.solarDay=jd+1;
},
getSolarDaysInMonth: function (){
this.calculateSolarDate();
if (this.solarMonth<6)
return 31;
if (this.solarMonth<11)
return 30;
//use Leap method for Persian date
if (this.isKabiseYear())
return 30;
else
return 29;
},
isKabiseYear: function(){
var mod=this.solarYear%33;
if(mod==1 || mod==5 || mod==9 || mod==13 || mod==17 || mod==22 || mod==26 || mod==30)return true;
return false;
},
getSolarDate: function (){
this.calculateSolarDate();
return this.solarDay;
},
getSolarMonth: function (){
this.calculateSolarDate();
return this.solarMonth;
},
getSolarFullYear: function (){
this.calculateSolarDate();
return this.solarYear;
},
getSolarFirstDateOfMonth: function (){
this.calculateSolarDate();
return new Date(this.getFullYear(), this.getMonth(), this.getDate() - this.solarDay + 1);
}
});



اگر شد بیا با هم به صورت خصوصی این قسمت رو کامل کنیم. خیلی خوشحال شدم از شما.
مدیرت سایت iranphp.org هستم و ازتون دعوت می کنم به سایت بیایید تا بتونیم این قسمت رو اونجا کامل کنیم و در اینجا قرار بدیم
از کدت واقعا ممنونم

Animal
29 Sep 2009, 11:57 PM
Very interesting. I find the date calculation arithmetic devised by various cultures fascinating. I've read about the evolution of the Julian and Gregorian calendars. What's a good site to learn about the development of the Persian calendar?

vahid4134
30 Sep 2009, 1:12 AM
Hi Animal
I write pdate (persian date) for php
for get php function download here
http://iranphp.org/pdate.php.tar.gz
More information about the Persian calendar : http://en.wikipedia.org/wiki/Iranian_calendar

mystix
30 Sep 2009, 8:52 PM
Very interesting. I find the date calculation arithmetic devised by various cultures fascinating. I've read about the evolution of the Julian and Gregorian calendars. What's a good site to learn about the development of the Persian calendar?

+1 :D

unfortunately i'm swamped with work for 2 weeks and counting... :s

Foggy
6 Oct 2009, 1:19 AM
Btw: http://iranphp.org/ is a really nice site, i like their layout ;)
Unfortunately i don't understand any word :)
I tried to translate with google, but without success. Isn't this hebrew?

Edit: forget my question, of course it's persian :)

vahid4134
7 Oct 2009, 6:00 AM
Thanks Foggy
I try ro complete this extension.
Extjs should go to the versatility. such persian date and RTL (Right To Left)

ardavan
19 Nov 2009, 2:05 PM
سلام
این که درست کار نمی کنه اصلا

jovaini_m
7 Feb 2012, 9:16 PM
// Mehdi Jovaini <jovaini.m@nepaco.ir> (http://nepaco.ir)
jQuery(function($){
$.datepicker.regional['fa'] = {
calendar: JalaliDate,
closeText: 'قبول',
prevText: 'قبل',
nextText: 'بعد',
currentText: 'امروز',
monthNames: ['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'],
monthNamesShort: ['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'],
dayNames: ['یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],
dayNamesShort: ['یک', 'دو', 'سه', 'چهار', 'پنج', 'جمعه', 'شنبه'],
dayNamesMin: ['ی','د','س','چ','پ','ج','ش'],
dateFormat: 'dd MM yy',
firstDay: 5,
isRTL: true};
$.datepicker.setDefaults($.datepicker.regional['fa']);
});


// JalaliDate: a Date-like object wrapper for jalali.js functions
// Mehdi Jovaini <jovaini.m@nepaco.ir> (http://nepaco.ir)
function JalaliDate(p0, p1, p2) {
var georgianDate;
var jalaliDate;
var isJalali = true;

if (!p0) {
setFullDate();
} else if (typeof (p0) == 'boolean') {
isJalali = p0;
setFullDate();
} else if (typeof (p0 == 'number')) {
var y = parseInt(p0, 10);
var m = parseInt(p1, 10);
var d = parseInt(p2, 10);
y += div(m, 12);
m = remainder(m, 12);
var g = jalali_to_gregorian([y, m, d]);
setFullDate(new Date(g[0], g[1], g[2]));
} else if (p0 instanceof Array) {
throw new "JalaliDate(Array) is not implemented yet!";
} else {
setFullDate(p0);
}

function setFullDate(date) {
if (date instanceof JalaliDate) {
date = date.getGeorgianDate();
}
georgianDate = new Date(date);
if (!georgianDate || georgianDate == 'Invalid Date' || isNaN(georgianDate || !georgianDate.getDate())) {
georgianDate = new Date();
}
jalaliDate = gregorian_to_jalali([
georgianDate.getFullYear(),
georgianDate.getMonth(),
georgianDate.getDate()]);
return this;
}
this.getGeorgianDate = function() { return georgianDate; }

this.setFullDate = setFullDate;

this.setDate = function(e) {
jalaliDate[2] = e;
var g = jalali_to_gregorian(jalaliDate);
georgianDate = new Date(g[0], g[1], g[2]);
jalaliDate = gregorian_to_jalali([g[0], g[1], g[2]]);
};

this.getFullYear = function() { return jalaliDate[0]; };
this.getMonth = function() { return jalaliDate[1]; };
this.getDate = function() { return jalaliDate[2]; };
this.toString = function() { return jalaliDate.join(',').toString(); };
this.getDay = function() { return georgianDate.getDay(); };
this.getHours = function() { return georgianDate.getHours(); };
this.getMinutes = function() { return georgianDate.getMinutes(); };
this.getSeconds = function() { return georgianDate.getSeconds(); };
this.getTime = function() { return georgianDate.getTime(); };
this.getTimeZoneOffset = function() { return georgianDate.getTimeZoneOffset(); };
this.getYear = function() { return JalaliDate[0] % 100; };

this.setHours = function(e) { georgianDate.setHours(e) };
this.setMinutes = function(e) { georgianDate.setMinutes(e) };
this.setSeconds = function(e) { georgianDate.setSeconds(e) };
this.setMilliseconds = function(e) { georgianDate.setMilliseconds(e) };
}


g_days_in_month = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
j_days_in_month = new Array(31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29);

function div(a,b) {
return Math.floor(a/b);
}

function remainder(a,b) {
return a - div(a,b)*b;
}

function gregorian_to_jalali(g /* array containing year, month, day*/ )
{
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var j_np;

var i;

gy = g[0]-1600;
//gm = g[1]-1;
gm = g[1];
gd = g[2]-1;

g_day_no = 365*gy+div((gy+3),4)-div((gy+99),100)+div((gy+399),400);
for (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;

j_day_no = g_day_no-79;

j_np = div(j_day_no, 12053);
j_day_no = remainder (j_day_no, 12053);

jy = 979+33*j_np+4*div(j_day_no,1461);
j_day_no = remainder (j_day_no, 1461);

if (j_day_no >= 366) {
jy += div((j_day_no-1),365);
j_day_no = remainder ((j_day_no-1), 365);
}

for (i = 0; i < 11 && j_day_no >= j_days_in_month[i]; ++i) {
j_day_no -= j_days_in_month[i];
}
//jm = i+1;
jm = i;
jd = j_day_no+1;

return new Array(jy, jm, jd);
}

function jalali_to_gregorian(j /* array containing year, month, day*/ )
{
var gy, gm, gd;
var jy, jm, jd;
var g_day_no, j_day_no;
var leap;

var i;

jy = j[0]-979;
//jm = j[1]-1;
jm = j[1];
jd = j[2] - 1;

j_day_no = 365*jy + div(jy,33)*8 + div((remainder (jy, 33)+3),4);
for (i=0; i < jm; ++i)
j_day_no += j_days_in_month[i];

j_day_no += jd;

g_day_no = j_day_no+79;

gy = 1600 + 400*div(g_day_no,146097); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
g_day_no = remainder (g_day_no, 146097);

leap = 1;
if (g_day_no >= 36525) /* 36525 = 365*100 + 100/4 */
{
g_day_no--;
gy += 100*div(g_day_no,36524); /* 36524 = 365*100 + 100/4 - 100/100 */
g_day_no = remainder (g_day_no, 36524);

if (g_day_no >= 365)
g_day_no++;
else
leap = 0;
}

gy += 4*div(g_day_no,1461); /* 1461 = 365*4 + 4/4 */
g_day_no = remainder (g_day_no, 1461);

if (g_day_no >= 366) {
leap = 0;

g_day_no--;
gy += div(g_day_no, 365);
g_day_no = remainder (g_day_no, 365);
}

for (i = 0; g_day_no >= g_days_in_month[i] + (i == 1 && leap); i++)
g_day_no -= g_days_in_month[i] + (i == 1 && leap);
//gm = i+1;
gm = i;
gd = g_day_no + 1;

return new Array(gy, gm, gd);
}

function jalali_today() {
Today = new Date();
j = gregorian_to_jalali(new Array(
Today.getFullYear(),
Today.getMonth()+1,
Today.getDate()
));
return j[2]+"/"+j[1]+"/"+j[0];
}