diff options
| author | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
|---|---|---|
| committer | Tristan Zur <tzur@web.web.ccwn.org> | 2014-03-27 22:27:47 +0100 |
| commit | b62676ca5d3d6f6ba3f019ea3f99722e165a98d8 (patch) | |
| tree | 86722cb80f07d4569f90088eeaea2fc2f6e2ef94 /js/dojo/dojox/date/hebrew | |
Diffstat (limited to 'js/dojo/dojox/date/hebrew')
| -rw-r--r-- | js/dojo/dojox/date/hebrew/Date.js | 721 | ||||
| -rw-r--r-- | js/dojo/dojox/date/hebrew/locale.js | 511 | ||||
| -rw-r--r-- | js/dojo/dojox/date/hebrew/numerals.js | 141 |
3 files changed, 1373 insertions, 0 deletions
diff --git a/js/dojo/dojox/date/hebrew/Date.js b/js/dojo/dojox/date/hebrew/Date.js new file mode 100644 index 0000000..6255eff --- /dev/null +++ b/js/dojo/dojox/date/hebrew/Date.js @@ -0,0 +1,721 @@ +//>>built +define("dojox/date/hebrew/Date", [ + "dojo/_base/kernel", + "dojo/_base/declare", + "./numerals" +], function(dojo, declare, numerals){ + +dojo.getObject("date.hebrew.Date", true, dojox); +dojo.experimental("dojox.date.hebrew.Date"); + +dojo.declare("dojox.date.hebrew.Date", null, { + // summary: A Date-like object which implements the Hebrew calendar + // + // description: + // A Date-like object which implements the Hebrew Calendar. Because this object + // implements many of the same methods as the native JavaScript Date object, which + // implements the Gregorian calendar, it can often be used its place. Note that + // this object does not extend Date or use its prototype. + // + // example: + // | dojo.require("dojox.date.hebrew.Date"); + // | + // | var date = new dojox.date.hebrew.Date(); + // | console.log(date.getFullYear()+'\'+date.getMonth()+'\'+date.getDate()); + + // Hebrew date calculations are performed in terms of days, hours, and + // "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds. + //_HOUR_PARTS: 1080, + //_DAY_PARTS: 24*1080, + + // An approximate value for the length of a lunar month. + // It is used to calculate the approximate year and month of a given + // absolute date. + //_MONTH_FRACT: 12*1080 + 793, + //_MONTH_PARTS: 29*24*1080 + 12*1080 + 793, + + // The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch) + // counting from noon on the day before. BAHARAD is an abbreviation of + // Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204). + //_BAHARAD: 11*1080 + 204, + + // The Julian day of the Gregorian epoch, that is, January 1, 1 on the + // Gregorian calendar. + //_JAN_1_1_JULIAN_DAY: 1721426, + + /** + * The lengths of the Hebrew months. This is complicated, because there + * are three different types of years, or six if you count leap years. + * Due to the rules for postponing the start of the year to avoid having + * certain holidays fall on the sabbath, the year can end up being three + * different lengths, called "deficient", "normal", and "complete". + */ + + //"Absolute" indexes of months: Tishri - 0, Heshvan - 1, Kislev - 2, Tevet - 3, Shevat - 4, Adar I (leap years only) - 5, Adar - 6, Nisan - 7, Iyar - 8, Sivan - 9, Tammuz-10, Av - 11, Elul - 12. + + _MONTH_LENGTH: [ + // Deficient Normal Complete + [ 30, 30, 30 ], //Tishri 0 + [ 29, 29, 30 ], //Heshvan 1 + [ 29, 30, 30 ], //Kislev 2 + [ 29, 29, 29 ], //Tevet 3 + [ 30, 30, 30 ], //Shevat 4 + [ 30, 30, 30 ], //Adar I (leap years only) 5 + [ 29, 29, 29 ], //Adar 6 + [ 30, 30, 30 ], //Nisan 7 + [ 29, 29, 29 ], //Iyar 8 + [ 30, 30, 30 ], //Sivan 9 + [ 29, 29, 29 ], //Tammuz 10 + [ 30, 30, 30 ], //Av 11 + [ 29, 29, 29 ] //Elul 12 + ], + + /** + * The cumulative # of days to the end of each month in a non-leap year + * Although this can be calculated from the MONTH_LENGTH table, + * keeping it around separately makes some calculations a lot faster + */ + _MONTH_START: [ + // Deficient Normal Complete + [ 0, 0, 0 ], // (placeholder) + [ 30, 30, 30 ], // Tishri + [ 59, 59, 60 ], // Heshvan + [ 88, 89, 90 ], // Kislev + [ 117, 118, 119 ], // Tevet + [ 147, 148, 149 ], // Shevat + [ 147, 148, 149 ], // (Adar I placeholder) + [ 176, 177, 178 ], // Adar + [ 206, 207, 208 ], // Nisan + [ 235, 236, 237 ], // Iyar + [ 265, 266, 267 ], // Sivan + [ 294, 295, 296 ], // Tammuz + [ 324, 325, 326 ], // Av + [ 353, 354, 355 ] // Elul + ], + + /** + * The cumulative # of days to the end of each month in a leap year + */ + _LEAP_MONTH_START: [ + // Deficient Normal Complete + [ 0, 0, 0 ], // (placeholder) + [ 30, 30, 30 ], // Tishri + [ 59, 59, 60 ], // Heshvan + [ 88, 89, 90 ], // Kislev + [ 117, 118, 119 ], // Tevet + [ 147, 148, 149 ], // Shevat + [ 177, 178, 179 ], // Adar I + [ 206, 207, 208 ], // Adar II + [ 236, 237, 238 ], // Nisan + [ 265, 266, 267 ], // Iyar + [ 295, 296, 297 ], // Sivan + [ 324, 325, 326 ], // Tammuz + [ 354, 355, 356 ], // Av + [ 383, 384, 385 ] // Elul + ], + + _GREGORIAN_MONTH_COUNT: [ + //len len2 st st2 + [ 31, 31, 0, 0 ], // Jan + [ 28, 29, 31, 31 ], // Feb + [ 31, 31, 59, 60 ], // Mar + [ 30, 30, 90, 91 ], // Apr + [ 31, 31, 120, 121 ], // May + [ 30, 30, 151, 152 ], // Jun + [ 31, 31, 181, 182 ], // Jul + [ 31, 31, 212, 213 ], // Aug + [ 30, 30, 243, 244 ], // Sep + [ 31, 31, 273, 274 ], // Oct + [ 30, 30, 304, 305 ], // Nov + [ 31, 31, 334, 335 ] // Dec + // len length of month + // len2 length of month in a leap year + // st days in year before start of month + // st2 days in year before month in leap year + ], + + _date: 0, + _month: 0, + _year: 0, + _hours: 0, + _minutes: 0, + _seconds: 0, + _milliseconds: 0, + _day: 0, + + constructor: function(){ + // summary: initialize the date object value + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | var date2 = new dojox.date.hebrew.Date(date1); + // | + // | var date3 = new dojox.date.hebrew.Date(5768,2,12); + + var len = arguments.length; + if(!len){// use the current date value, added "" to the similarity to date + this.fromGregorian(new Date()); + }else if(len == 1){ + var arg0 = arguments[0]; + if(typeof arg0 == "number"){ // this is time "valueof" + arg0 = new Date(arg0); + } + + if(arg0 instanceof Date){ + this.fromGregorian(arg0); + }else if(arg0 == ""){ + // date should be invalid. Dijit relies on this behavior. + this._date = new Date(""); //TODO: should this be NaN? _date is not a Date object + }else{ // this is hebrew.Date object + this._year = arg0._year; + this._month = arg0._month; + this._date = arg0._date; + this._hours = arg0._hours; + this._minutes = arg0._minutes; + this._seconds = arg0._seconds; + this._milliseconds = arg0._milliseconds; + } + }else if(len >= 3){ + // YYYY, MM, DD arguments passed, month is from 0-12, "absolute" index of month + this._year += arguments[0]; + this._month += arguments[1]; + this._date += arguments[2]; + + if(this._month > 12){ + console.warn("the month is incorrect , set 0 " + this._month + " " + this._year ); + this._month = 0; + } + this._hours += arguments[3] || 0; + this._minutes += arguments[4] || 0; + this._seconds += arguments[5] || 0; + this._milliseconds += arguments[6] || 0; + } + + this._setDay(); + }, + + getDate: function(){ + // summary: returns the date value (1 - 30) + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | console.log(date1.getDate()); + + return this._date; // int + }, + + getDateLocalized: function(/*String?*/locale){ + // summary: returns the date value as hebrew numerals for the Hebrew locale, + // a number for all others. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | console.log(date1.getDate()); + + return (locale || dojo.locale).match(/^he(?:-.+)?$/) ? + numerals.getDayHebrewLetters(this._date) : this.getDate(); + }, + + getMonth: function(){ + // summary: returns the month value (0 - 12) + // + // description: the result is the index in the month array: + // 0. Tishri + // 1. Heshvan + // 2. Kislev + // 3. Tevet + // 4. Shevat + // 5. Adar I (leap years only) + // 6. Adar + // 7. Nisan + // 8. Iyar + // 9. Sivan + // 10. Tammuz + // 11. Av + // 12. Elul - 12 + // For non leap years, for months after Shevat, the actual position of + // the month in the year (used for short format) is less than + // the "absolute" index by 1. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(5769, 6, 1); + // | + // | console.log(date1.getMonth()+1); + // | >> 7 + + return this._month; + }, + + getFullYear: function(){ + // summary: returns the Year value + // + // example: + // | var date1 = new dojox.date.hebrew.Date(5769, 6, 1); + // | + // | console.log(date1.getFullYear()); + // | >> 5769 + return this._year; + }, + + getHours: function(){ + //summary: returns the hour value + return this._hours; + }, + + getMinutes: function(){ + //summary: returns the minutes value + + return this._minutes; + }, + + getSeconds: function(){ + //summary: returns the seconds value + return this._seconds; + }, + + getMilliseconds: function(){ + //summary: returns the milliseconds value + + return this._milliseconds; + }, + + setDate: function(/*number*/date){ + // summary: sets the date number for a given month + // example: + // | var date1 = new dojox.date.hebrew.Date(5769, 6, 1); + // | date1.setDate(2); + + date = +date; + var mdays; + if(date>0){ + while (date > (mdays = this.getDaysInHebrewMonth(this._month, this._year))){ + date -= mdays; + this._month++; + if(this._month >= 13){this._year++; this._month -= 13;} + } + }else{ + while(date<=0){ + mdays = this.getDaysInHebrewMonth((this._month-1)>=0 ? (this._month-1) : 12, ((this._month-1)>=0)? this._year : this._year-1); + this._month--; + if(this._month < 0){this._year--; this._month += 13;} + date += mdays; + } + } + this._date = date; + this._setDay(); + return this; + }, + + + setFullYear: function(/*number*/year, /*number?*/month, /*number?*/ date){ + // summary: set the year + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | date1.setFullYear(5768); + // | date1.setFullYear(5768, 1, 1); + + this._year = year = +year; + if(!this.isLeapYear(year) && this._month==5){ //incorrect month number for non leap year + this._month++; + } + + if(month !== undefined){this.setMonth(month);} + if(date !== undefined){this.setDate(date);} + + var dnum = this.getDaysInHebrewMonth(this._month, this._year); + if(dnum < this._date){ + this._date = dnum; + } // if the date in this month more than number of the days in this month + + this._setDay(); + return this; + }, + + setMonth: function(/*number*/month){ + // summary: sets the month. You should use "absolute" index in the month array: + // 0. Tishri + // 1. Heshvan + // 2. Kislev + // 3. Tevet + // 4. Shevat + // 5. Adar I (leap years only) + // 6. Adar + // 7. Nisan + // 8. Iyar + // 9. Sivan + // 10. Tammuz + // 11. Av + // 12. Elul - 12 + // For non leap years, for months after Shevat, the actual position of + // the month in the year (used for short format) is less than + // the "absolute" index by 1. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | date1.setMonth(0); //first month + + month = +month; // coerce to a Number + if(!this.isLeapYear(this._year) && month == 5){month++;} + + if(month>=0){ + while(month >12){ + this._year++; + month -= 13; + if (!this.isLeapYear(this._year) && month >= 5){month++;} + } + }else{ + while(month<0){ + this._year--; + month += (!this.isLeapYear(this._year) && month < -7) ? 12 : 13; + } + } + + this._month = month; + + var dnum = this.getDaysInHebrewMonth(this._month, this._year); + if(dnum < this._date){ + this._date = dnum; + } // if the date in this month more than number of the days in this month + + this._setDay(); + return this; + }, + + setHours: function(){ + // summary: sets the hour + // + // description: Sets the hour and optionally minutes, seconds, milliseconds also. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | date1.setHours(12, 30, 0, 0); + + var hours_arg_no = arguments.length; + var hours = 0; + if(hours_arg_no >= 1){ + hours += +arguments[0]; + } + + if(hours_arg_no >= 2){ + this._minutes += +arguments[1]; + } + + if(hours_arg_no >= 3){ + this._seconds += +arguments[2]; + } + + if(hours_arg_no == 4){ + this._milliseconds += +arguments[3]; + } + + while(hours >= 24){ + this._date++; + var mdays = this.getDaysInHebrewMonth(this._month, this._year); + if(this._date > mdays) + { + this._month++; + if(!this.isLeapYear(this._year) && this._month==5){ this._month++; } + if(this._month >= 13){this._year++; this._month -= 13;} + this._date -= mdays; + } + hours -= 24; + } + this._hours = hours; + this._setDay(); + return this; + }, + + _addMinutes: function(/*Number*/minutes){ + minutes += this._minutes; + this.setMinutes(minutes); + this.setHours(this._hours + parseInt(minutes / 60)); + return this; + }, + + _addSeconds: function(/*Number*/seconds){ + seconds += this._seconds; + this.setSeconds(seconds); + this._addMinutes(parseInt(seconds / 60)); + return this; + }, + + _addMilliseconds: function(/*Number*/milliseconds){ + milliseconds += this._milliseconds; + this.setMilliseconds(milliseconds); + this._addSeconds(parseInt(milliseconds / 1000)); + return this; + }, + + setMinutes: function(/*Number*/minutes){ + //summary: sets the minutes (0-59) only. + this._minutes = minutes % 60; + return this; + }, + + setSeconds: function(/*Number*/seconds){ + //summary: sets the seconds (0-59) only. + this._seconds = seconds % 60; + return this; + }, + + setMilliseconds: function(/*Number*/milliseconds){ + this._milliseconds = milliseconds % 1000; + return this; + }, + + _setDay: function(){ + var day = this._startOfYear(this._year); + if(this._month != 0){ + day += (this.isLeapYear(this._year) ? this._LEAP_MONTH_START : this._MONTH_START)[this._month || 0][this._yearType(this._year)]; + } + day += this._date - 1; + this._day = (day+1) % 7; + }, + + toString: function(){ + // summary: returns a string representation of the date in "dd, MM, yyyy HH:mm:ss" format + // + // description: returns a string representation of the date in "dd, MM, yyyy HH:mm:ss" format (all numeric) + // For user presentation, use dojox.date.hebrew.locale.format which will present in the appropriate language + // and format. toString() language- and culturally-specific conventions to keep this module free of + // dependencies on dojox.date.locale and dojo.cldr. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(5769, 6, 1); + // | console.log(date1.toString()); + // | >>> "1, 6, 5769 0:0:0" + return this._date + ", " + this._month + ", " + this._year + " " + this._hours + ":" + this._minutes + ":" + this._seconds; // String + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar from ICU4J v3.6.1 at http://www.icu-project.org/ + getDaysInHebrewMonth: function(/*Number*/month, /*Number*/ year){ + // summary: returns the number of days in the given month and year + + // Aside from the leap month, these two months can vary: 1=HESHVAN, 2=KISLEV + // The rest are a fixed length + var yearType = (month == 1 || month == 2) ? this._yearType(year) : 0; + return (!this.isLeapYear(this._year) && month == 5) ? 0 : this._MONTH_LENGTH[month][yearType]; + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar from ICU4J v3.6.1 at http://www.icu-project.org/ + _yearType: function(/*Number*/year){ + var yearLength = this._handleGetYearLength(Number(year)); + if(yearLength > 380){ + yearLength -= 30; // Subtract length of leap month. + } + + var yearType = yearLength - 353; + if (yearType < 0 || yearType > 2){ + throw new Error("Illegal year length " + yearLength + " in year " + year); + } + return yearType; + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar from ICU4J v3.6.1 at http://www.icu-project.org/ + _handleGetYearLength: function(/*number*/eyear){ + return this._startOfYear(eyear+1) - this._startOfYear(eyear); + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar from ICU4J v3.6.1 at http://www.icu-project.org/ + _startOfYear: function(/*number*/year){ + var months = Math.floor((235 * year - 234) / 19), // # of months before year + frac = months * (12*1080 + 793) + 11*1080 + 204/*BAHARAD*/, // Fractional part of day # + day = months * 29 + Math.floor(frac / (24*1080)); // Whole # part of calculation + frac %= 24*1080; // Time of day + + var wd = day % 7; // Day of week (0 == Monday) + + if(wd == 2 || wd == 4 || wd == 6){ + // If the 1st is on Sun, Wed, or Fri, postpone to the next day + day += 1; + wd = day % 7; + } + if(wd == 1 && frac > 15 * 1080 + 204 && !this.isLeapYear(year)){ + // If the new moon falls after 3:11:20am (15h204p from the previous noon) + // on a Tuesday and it is not a leap year, postpone by 2 days. + // This prevents 356-day years. + day += 2; + }else if(wd == 0 && frac > 21 * 1080 + 589 && this.isLeapYear(year-1)){ + // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon) + // on a Monday and *last* year was a leap year, postpone by 1 day. + // Prevents 382-day years. + day += 1; + } + + return day; + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar from ICU4J v3.6.1 at http://www.icu-project.org/ + isLeapYear: function(/*Number*/year){ + // summary: + // Determines if the year (argument) is a leap year + // description: The Leap year contains additional month adar sheni + // + //return (year * 12 + 17) % 19 >= 12; + var x = (year*12 + 17) % 19; + return x >= ((x < 0) ? -7 : 12); + }, + + + fromGregorian: function(/*Date*/gdate){ + // summary: This function sets this Date to the Hebrew Date corresponding to the Gregorian Date + // example: + // | var dateHebrew = new dojox.date.hebrew.Date(); + // | var dateGregorian = new Date(2008,10,12); + // | dateHebrew.fromGregorian(dateGregorian); + + var result = (!isNaN(gdate)) ? this._computeHebrewFields(gdate) : NaN; + this._year = (!isNaN(gdate)) ? result[0] : NaN; + this._month = (!isNaN(gdate))? result[1] : NaN; + this._date = (!isNaN(gdate)) ? result[2] : NaN; + this._hours = gdate.getHours(); + this._milliseconds = gdate.getMilliseconds(); + this._minutes = gdate.getMinutes(); + this._seconds = gdate.getSeconds(); + if (!isNaN(gdate)) this._setDay(); + return this; + }, + + // ported from the Java class com.ibm.icu.util.HebrewCalendar.handleComputeFields from ICU4J v3.6.1 at http://www.icu-project.org/ + _computeHebrewFields: function(/*Date*/gdate){ + var julianDay = this._getJulianDayFromGregorianDate(gdate), + d = julianDay - 347997, + m = Math.floor((d * 24*1080) / (29*24*1080 + 12*1080 + 793)), // Months (approx) + year = Math.floor((19 * m + 234) / 235) + 1, // Years (approx) + ys = this._startOfYear(year), // 1st day of year + dayOfYear = (d - ys); + // Because of the postponement rules, it's possible to guess wrong. Fix it. + while(dayOfYear < 1){ + year--; + ys = this._startOfYear(year); + dayOfYear = d - ys; + } + + // Now figure out which month we're in, and the date within that month + + var typeofYear = this._yearType(year), + monthStart = this.isLeapYear(year) ? this._LEAP_MONTH_START : this._MONTH_START, + month = 0; + + while(dayOfYear > monthStart[month][typeofYear]){ + month++; + } + month--; + var dayOfMonth = dayOfYear - monthStart[month][typeofYear]; + return [year, month, dayOfMonth]; + }, + + // ported from the Java class com.ibm.icu.util.Calendar.computeGregorianFields from ICU4J v3.6.1 at http://www.icu-project.org/ + toGregorian: function(){ + // summary: returns the equivalent Grogorian date value as a native Date object + // example: + // | var dateHebrew = new dojox.date.hebrew.Date(5768,11,20); + // | var dateGregorian = dateHebrew.toGregorian(); + + var hYear = this._year || 0, + hMonth = this._month || 0, + hDate = this._date || 0, + day = this._startOfYear(hYear); + + if(hMonth != 0){ + day += (this.isLeapYear(hYear) ? this._LEAP_MONTH_START : this._MONTH_START)[hMonth][this._yearType(hYear)]; + } + + var julianDay = (hDate + day + 347997), + // The Gregorian epoch day is zero for Monday January 1, year 1. + gregorianEpochDay = julianDay - 1721426; + + // Here we convert from the day number to the multiple radix + // representation. We use 400-year, 100-year, and 4-year cycles. + // For example, the 4-year cycle has 4 years + 1 leap day; giving + // 1461 == 365*4 + 1 days. + var rem = []; + var n400 = this._floorDivide(gregorianEpochDay , 146097, rem), // 400-year cycle length + n100 = this._floorDivide(rem[0] , 36524, rem), // 100-year cycle length + n4 = this._floorDivide(rem[0] , 1461, rem), // 4-year cycle length + n1 = this._floorDivide(rem[0] , 365, rem), + year = 400*n400 + 100*n100 + 4*n4 + n1, + dayOfYear = rem[0]; // zero-based day of year + + if(n100 == 4 || n1 == 4){ + dayOfYear = 365; // Dec 31 at end of 4- or 400-yr cycle + }else{ + ++year; + } + + var isLeap = !(year%4) && // equiv. to (year%4 == 0) + (year%100 || !(year%400)), + correction = 0, + march1 = isLeap ? 60 : 59; // zero-based DOY for March 1 + if(dayOfYear >= march1){ correction = isLeap ? 1 : 2; } + var month = Math.floor((12 * (dayOfYear + correction) + 6) / 367); // zero-based month + var dayOfMonth = dayOfYear - + this._GREGORIAN_MONTH_COUNT[month][isLeap ? 3 : 2] + 1; // one-based DOM + + return new Date(year, month, dayOfMonth, this._hours, this._minutes, this._seconds, this._milliseconds); // Date + }, + _floorDivide: function(numerator, denominator, remainder){ + if(numerator >= 0){ + remainder[0] = (numerator % denominator); + return Math.floor(numerator / denominator); + } + var quotient = Math.floor(numerator / denominator); + remainder[0] = numerator - (quotient * denominator); + return quotient; + }, + + getDay: function(){ + // summary: returns weekday value (0 - 6) + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | console.log(date1.getDay()); + + var hYear = this._year, + hMonth = this._month, + hDate = this._date, + day = this._startOfYear(hYear); + + if(hMonth != 0){ + day += (this.isLeapYear(hYear) ? this._LEAP_MONTH_START : this._MONTH_START)[hMonth][this._yearType(hYear)]; + } + + day += hDate - 1; + return (day+1) % 7; + }, + + // ported from the Java class com.ibm.icu.util.Calendar.computeGregorianMonthStart from ICU4J v3.6.1 at http://www.icu-project.org/ + _getJulianDayFromGregorianDate: function(gdate){ + //summary: returns the Julian day of a Gregorian date + + var year = gdate.getFullYear(), + month = gdate.getMonth(), + d = gdate.getDate(), + isLeap = !(year%4) && (year%100 || !(year%400)), //TODO: dup + y = year - 1; + // This computation is actually ... + (_JAN_1_1_JULIAN_DAY - 3) + 2. + // Add 2 because Gregorian calendar starts 2 days after Julian + // calendar. + var julianDay = 365*y + Math.floor(y/4) - Math.floor(y/100) + + Math.floor(y/400) + 1721426 - 1; + // At this point julianDay indicates the day BEFORE the first day + // of January 1, <eyear> of the Gregorian calendar. + if(month > 0) { + julianDay += this._GREGORIAN_MONTH_COUNT[month][isLeap ? 3 : 2]; + } + + julianDay += d; + return julianDay; + } +}); + +dojox.date.hebrew.Date.prototype.valueOf = function(){ + return this.toGregorian().valueOf(); +}; +return dojox.date.hebrew.Date; +}); diff --git a/js/dojo/dojox/date/hebrew/locale.js b/js/dojo/dojox/date/hebrew/locale.js new file mode 100644 index 0000000..df3e401 --- /dev/null +++ b/js/dojo/dojox/date/hebrew/locale.js @@ -0,0 +1,511 @@ +//>>built +define("dojox/date/hebrew/locale", ["dojo/main", "dojo/date", "dojo/i18n", "dojo/regexp", "dojo/string", "./Date", "./numerals", "dojo/i18n!dojo/cldr/nls/hebrew"], + function(dojo, dd, i18n, regexp, string, hebrewDate, numerals){ + + dojo.getObject("date.hebrew.locale", true, dojox); + dojo.experimental("dojox.date.hebrew.locale"); + + //Load the bundles containing localization information for + // names and formats + dojo.requireLocalization("dojo.cldr", "hebrew"); + + // Format a pattern without literals + function formatPattern(dateObject, bundle, locale, fullYear, pattern){ + + return pattern.replace(/([a-z])\1*/ig, function(match){ + var s, pad; + var c = match.charAt(0); + var l = match.length; + var widthList = ["abbr", "wide", "narrow"]; + + switch(c){ + case 'y': + if(locale.match(/^he(?:-.+)?$/)){ + s = numerals.getYearHebrewLetters(dateObject.getFullYear()); + }else{ + s = String(dateObject.getFullYear()); + } + break; + case 'M': + var m = dateObject.getMonth(); + if(l<3){ + if(!dateObject.isLeapYear(dateObject.getFullYear()) && m>5){m--;} + if(locale.match(/^he(?:-.+)?$/)){ + s = numerals.getMonthHebrewLetters(m); + }else{ + s = m+1; pad = true; + } + }else{ + var monthNames = dojox.date.hebrew.locale.getNames('months',widthList[l-3], 'format', locale, dateObject); + s = monthNames[m]; + } + break; + case 'd': + if(locale.match(/^he(?:-.+)?$/)){ + s = dateObject.getDateLocalized(locale); + }else{ + s = dateObject.getDate(); pad = true; + } + break; + case 'E': + var d = dateObject.getDay(); + if(l<3){ + s = d+1; pad = true; + }else{ + var propD = ["days", "format", widthList[l-3]].join("-"); + s = bundle[propD][d]; + } + break; + case 'a': + var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm'; + s = bundle['dayPeriods-format-wide-' + timePeriod]; + break; + case 'h': + case 'H': + case 'K': + case 'k': + var h = dateObject.getHours(); + // strange choices in the date format make it impossible to write this succinctly + switch (c){ + case 'h': // 1-12 + s = (h % 12) || 12; + break; + case 'H': // 0-23 + s = h; + break; + case 'K': // 0-11 + s = (h % 12); + break; + case 'k': // 1-24 + s = h || 24; + break; + } + pad = true; + break; + case 'm': + s = dateObject.getMinutes(); pad = true; + break; + case 's': + s = dateObject.getSeconds(); pad = true; + break; + case 'S': + s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true; + break; + case 'z': + s = ""; + break; + default: + throw new Error("dojox.date.hebrew.locale.formatPattern: invalid pattern char: "+pattern); + } + if(pad){ s = string.pad(s, l); } + return s; + }); + } + + dojox.date.hebrew.locale.format = function(/*hebrew.Date*/dateObject, /*object?*/options){ + // based on and similar to dojo.date.locale.format + //summary: + // Format a Date object as a String, using settings. + // + // description: + // Create a string from a hebrew.Date object using a known pattern. + // By default, this method formats both date and time from dateObject. + // Default formatting lengths is 'short' + // + // dateObject: + // the date and/or time to be formatted. If a time only is formatted, + // the values in the year, month, and day fields are irrelevant. The + // opposite is true when formatting only dates. + + options = options || {}; + + var locale = i18n.normalizeLocale(options.locale); + var formatLength = options.formatLength || 'short'; + var bundle = dojox.date.hebrew.locale._getHebrewBundle(locale); + var str = []; + + var sauce = dojo.hitch(this, formatPattern, dateObject, bundle, locale, options.fullYear); + if(options.selector == "year"){ + var year = dateObject.getFullYear(); + return locale.match(/^he(?:-.+)?$/) ? + numerals.getYearHebrewLetters(year) : year; + } + if(options.selector != "time"){ + var datePattern = options.datePattern || bundle["dateFormat-"+formatLength]; + if(datePattern){str.push(_processPattern(datePattern, sauce));} + } + if(options.selector != "date"){ + var timePattern = options.timePattern || bundle["timeFormat-"+formatLength]; + if(timePattern){str.push(_processPattern(timePattern, sauce));} + } + var result = str.join(" "); //TODO: use locale-specific pattern to assemble date + time + + return result; // String + }; + + dojox.date.hebrew.locale.regexp = function(/*object?*/options){ + // based on and similar to dojo.date.locale.regexp + // summary: + // Builds the regular needed to parse a hebrew.Date + + return dojox.date.hebrew.locale._parseInfo(options).regexp; // String + }; + + dojox.date.hebrew.locale._parseInfo = function(/*oblect?*/options){ + /* based on and similar to dojo.date.locale._parseInfo */ + + options = options || {}; + var locale = i18n.normalizeLocale(options.locale); + var bundle = dojox.date.hebrew.locale._getHebrewBundle(locale); + + var formatLength = options.formatLength || 'short'; + var datePattern = options.datePattern || bundle["dateFormat-" + formatLength]; + var timePattern = options.timePattern || bundle["timeFormat-" + formatLength]; + + var pattern; + if(options.selector == 'date'){ + pattern = datePattern; + }else if(options.selector == 'time'){ + pattern = timePattern; + }else{ + pattern = (timePattern === undefined) ? datePattern : datePattern + ' ' + timePattern; //hebrew resource file does not contain time patterns - a bug? + } + + var tokens = []; + + var re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options)); + return {regexp: re, tokens: tokens, bundle: bundle}; + }; + + dojox.date.hebrew.locale.parse = function(/*String*/value, /*Object?*/options){ + // based on and similar to dojo.date.locale.parse + // summary: This function parse string date value according to options + // example: + // | var dateHebrew = dojox.date.hebrew.locale.parse('11/10/5740', {datePattern:'dd/MM/yy', selector:'date'}); + // | in Hebrew locale string for parsing contains Hebrew Numerals + // | + // | options = {datePattern:'dd MMMM yy', selector:'date'}; + // | + // | y - year + // | M, MM - short month + // | MMM, MMMM - long month + // | d - date + // | a - am, pm + // | E, EE, EEE, EEEE - week day + // | + // | h, H, k, K, m, s, S, - time format + + value = value.replace(/[\u200E\u200F\u202A-\u202E]/g, ""); //remove special chars + + if(!options){options={};} + var info = dojox.date.hebrew.locale._parseInfo(options); + + var tokens = info.tokens, bundle = info.bundle; + var re = new RegExp("^" + info.regexp + "$"); + + var match = re.exec(value); + + var locale = i18n.normalizeLocale(options.locale); + + if(!match){ + console.debug("dojox.date.hebrew.locale.parse: value "+value+" doesn't match pattern " + re); + return null; + } // null + + var date, date1; + + //var result = [1970,0,1,0,0,0,0]; // + var result = [5730,3,23,0,0,0,0]; // hebrew date for [1970,0,1,0,0,0,0] used in gregorian locale + var amPm = ""; + var mLength = 0; + var widthList = ["abbr", "wide", "narrow"]; + var valid = dojo.every(match, function(v, i){ + if(!i){return true;} + var token=tokens[i-1]; + var l=token.length; + switch(token.charAt(0)){ + case 'y': + if(locale.match(/^he(?:-.+)?$/)){ + result[0] = numerals.parseYearHebrewLetters(v); + }else{ + result[0] = Number(v); + } + break; + case 'M': + //if it is short format, month is one letter or two letter with "geresh" + if(l>2){ + //we do not know here if the year is leap or not + var months = dojox.date.hebrew.locale.getNames('months', widthList[l-3], 'format', locale, new hebrewDate(5769, 1, 1)), + leapmonths = dojox.date.hebrew.locale.getNames('months', widthList[l-3], 'format', locale, new hebrewDate(5768, 1, 1)); + if(!options.strict){ + //Tolerate abbreviating period in month part + //Case-insensitive comparison + v = v.replace(".","").toLowerCase(); + months = dojo.map(months, function(s){ return s ? s.replace(".","").toLowerCase() : s; } ); + leapmonths = dojo.map(leapmonths, function(s){ return s ? s.replace(".","").toLowerCase() : s; } ); + } + var monthName = v; + v = dojo.indexOf(months, monthName); + if(v == -1){ + v = dojo.indexOf(leapmonths, monthName); + if(v == -1){ + //console.debug("dojox.date.hebrew.locale.parse: Could not parse month name: second " + v +"'."); + return false; + } + } + mLength = l; + }else{ + if(locale.match(/^he(?:-.+)?$/)){ + v = numerals.parseMonthHebrewLetters(v); + }else{ + v--; + } + } + result[1] = Number(v); + break; + case 'D': + result[1] = 0; + // fallthrough... + case 'd': + if(locale.match(/^he(?:-.+)?$/)){ + result[2] = numerals.parseDayHebrewLetters(v); + }else{ + result[2] = Number(v); + } + break; + case 'a': //am/pm + var am = options.am || bundle['dayPeriods-format-wide-am'], + pm = options.pm || bundle['dayPeriods-format-wide-pm']; + if(!options.strict){ + var period = /\./g; + v = v.replace(period,'').toLowerCase(); + am = am.replace(period,'').toLowerCase(); + pm = pm.replace(period,'').toLowerCase(); + } + if(options.strict && v != am && v != pm){ + return false; + } + + // we might not have seen the hours field yet, so store the state and apply hour change later + amPm = (v == pm) ? 'p' : (v == am) ? 'a' : ''; + break; + case 'K': //hour (1-24) + if(v == 24){ v = 0; } + // fallthrough... + case 'h': //hour (1-12) + case 'H': //hour (0-23) + case 'k': //hour (0-11) + //in the 12-hour case, adjusting for am/pm requires the 'a' part + //which could come before or after the hour, so we will adjust later + result[3] = Number(v); + break; + case 'm': //minutes + result[4] = Number(v); + break; + case 's': //seconds + result[5] = Number(v); + break; + case 'S': //milliseconds + result[6] = Number(v); + } + return true; + }); + + var hours = +result[3]; + if(amPm === 'p' && hours < 12){ + result[3] = hours + 12; //e.g., 3pm -> 15 + }else if(amPm === 'a' && hours == 12){ + result[3] = 0; //12am -> 0 + } + var dateObject = new hebrewDate(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // hebrew.Date + //for non leap year, the index of the short month start from adar should be increased by 1 + if(mLength < 3 && result[1] >= 5 && !dateObject.isLeapYear(dateObject.getFullYear())){ + dateObject.setMonth(result[1]+1); + } + return dateObject; // hebrew.Date + }; + + + function _processPattern(pattern, applyPattern, applyLiteral, applyAll){ + //summary: Process a pattern with literals in it + + // Break up on single quotes, treat every other one as a literal, except '' which becomes ' + var identity = function(x){return x;}; + applyPattern = applyPattern || identity; + applyLiteral = applyLiteral || identity; + applyAll = applyAll || identity; + + //split on single quotes (which escape literals in date format strings) + //but preserve escaped single quotes (e.g., o''clock) + var chunks = pattern.match(/(''|[^'])+/g); + var literal = pattern.charAt(0) == "'"; + + dojo.forEach(chunks, function(chunk, i){ + if(!chunk){ + chunks[i]=''; + }else{ + chunks[i]=(literal ? applyLiteral : applyPattern)(chunk); + literal = !literal; + } + }); + return applyAll(chunks.join('')); + } + + function _buildDateTimeRE (tokens, bundle, options, pattern){ + // based on and similar to dojo.date.locale._buildDateTimeRE + // + + pattern = regexp.escapeString(pattern); + var locale = i18n.normalizeLocale(options.locale); + + return pattern.replace(/([a-z])\1*/ig, function(match){ + + // Build a simple regexp. Avoid captures, which would ruin the tokens list + var s; + var c = match.charAt(0); + var l = match.length; + var p2 = '', p3 = ''; + if(options.strict){ + if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; } + if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; } + }else{ + p2 = '0?'; p3 = '0{0,2}'; + } + switch(c){ + case 'y': + s = '\\S+'; + break; + case 'M': + if(locale.match('^he(?:-.+)?$')){ + s = (l>2) ? '\\S+ ?\\S+' : '\\S{1,4}'; + }else{ + s = (l>2) ? '\\S+ ?\\S+' : p2+'[1-9]|1[0-2]'; + } + break; + case 'd': + if(locale.match('^he(?:-.+)?$')){ + s = '\\S[\'\"\'\u05F3]{1,2}\\S?'; + }else{ + s = '[12]\\d|'+p2+'[1-9]|30'; + } + break; + case 'E': + if(locale.match('^he(?:-.+)?$')){ + s = (l>3) ? '\\S+ ?\\S+' : '\\S'; + }else{ + s = '\\S+'; + } + break; + case 'h': //hour (1-12) + s = p2+'[1-9]|1[0-2]'; + break; + case 'k': //hour (0-11) + s = p2+'\\d|1[01]'; + break; + case 'H': //hour (0-23) + s = p2+'\\d|1\\d|2[0-3]'; + break; + case 'K': //hour (1-24) + s = p2+'[1-9]|1\\d|2[0-4]'; + break; + case 'm': + case 's': + s = p2+'\\d|[0-5]\\d'; + break; + case 'S': + s = '\\d{'+l+'}'; + break; + case 'a': + var am = options.am || bundle['dayPeriods-format-wide-am'], + pm = options.pm || bundle['dayPeriods-format-wide-pm']; + if(options.strict){ + s = am + '|' + pm; + }else{ + s = am + '|' + pm; + if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); } + if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); } + } + break; + default: + s = ".*"; + } + if(tokens){ tokens.push(match); } + return "(" + s + ")"; // add capture + }).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace. Need explicit handling of \xa0 for IE. */ + } + + var _customFormats = []; + dojox.date.hebrew.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){ + // summary: + // Add a reference to a bundle containing localized custom formats to be + // used by date/time formatting and parsing routines. + // + // description: + // The user may add custom localized formats where the bundle has properties following the + // same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx` + // The pattern string should match the format used by the CLDR. + // See dojo.date.locale.format() for details. + // The resources must be loaded by dojo.requireLocalization() prior to use + + _customFormats.push({pkg:packageName,name:bundleName}); + }; + + dojox.date.hebrew.locale._getHebrewBundle = function(/*String*/locale){ + var hebrew = {}; + dojo.forEach(_customFormats, function(desc){ + var bundle = i18n.getLocalization(desc.pkg, desc.name, locale); + hebrew = dojo.mixin(hebrew, bundle); + }, this); + return hebrew; /*Object*/ + }; + + dojox.date.hebrew.locale.addCustomFormats("dojo.cldr","hebrew"); + + dojox.date.hebrew.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale, /*dojox.date.hebrew.Date?*/date){ + // summary: + // Used to get localized strings from dojo.cldr for day or month names. + // + // item: + // 'months' || 'days' + // type: + // 'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English) + // use: + // 'standAlone' || 'format' (default) + // locale: + // override locale used to find the names + // date: + // required for item=months to determine leap month name + // + // using var monthNames = dojox.date.hebrew.locale.getNames('months', 'wide', 'format', 'he', new hebrewDate(5768, 2, 12)); + + var label, + lookup = dojox.date.hebrew.locale._getHebrewBundle(locale), + props = [item, context, type]; + if(context == 'standAlone'){ + var key = props.join('-'); + label = lookup[key]; + // Fall back to 'format' flavor of name + if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr + } + props[1] = 'format'; + + // return by copy so changes won't be made accidentally to the in-memory model + var result = (label || lookup[props.join('-')]).concat(); + + if(item == "months"){ + if(date.isLeapYear(date.getFullYear())){ + // Adar I (6th position in the array) will be used. + // Substitute the leap month Adar II for the regular Adar (7th position) + props.push("leap"); + result[6] = lookup[props.join('-')]; + }else{ + // Remove Adar I but leave an empty position in the array + delete result[5]; + } + } + + return result; /*Array*/ + }; + + return dojox.date.hebrew.locale; +}); diff --git a/js/dojo/dojox/date/hebrew/numerals.js b/js/dojo/dojox/date/hebrew/numerals.js new file mode 100644 index 0000000..f561002 --- /dev/null +++ b/js/dojo/dojox/date/hebrew/numerals.js @@ -0,0 +1,141 @@ +//>>built +define("dojox/date/hebrew/numerals", ["dojo/_base/kernel", "dojo/_base/array"], function(dojo){ + dojo.getObject("date.hebrew.numerals", true, dojox); + dojo.experimental("dojox.date.hebrew.numerals"); + +//Conversion from "Hindi" numerals to Hebrew numerals and vice versa + + var DIG="אבגדהוזחט"; + var TEN="יכלמנסעפצ"; + var HUN="קרשת"; + + var transformChars = function(str, nogrsh){ + str = str.replace("יה", "טו").replace("יו", "טז"); + + if(!nogrsh){ + var len = str.length; + if(len > 1){ + str = str.substr(0, len - 1) + '"' + str.charAt(len - 1); + }else{ + str += "\u05F3"; // 05F3:geresh + } + } + return str; // String + }; + + var parseStrToNumber = function(str){ + var num = 0; + dojo.forEach(str, function(ch){ + var i; + if((i = DIG.indexOf(ch)) != -1){ + num += ++i; + }else if((i = TEN.indexOf(ch)) != -1){ + num += 10 * ++i; + }else if((i = HUN.indexOf(ch)) != -1){ + num += 100 * ++i; + } + }); + return num; //Number + }; + + var convertNumberToStr = function(num){ + var str = "", n = 4, j = 9; + while(num){ + if(num >= n*100){ + str += HUN.charAt(n-1); + num -= n*100; + continue; + }else if(n > 1){ + n--; + continue; + }else if(num >= j*10){ + str += TEN.charAt(j-1); + num -= j*10; + }else if(j > 1){ + j--; + continue; + }else if(num > 0){ + str += DIG.charAt(num-1); + num = 0; + } + } + return str; //String + }; + + dojox.date.hebrew.numerals.getYearHebrewLetters = function(/*Number */ year){ + // summary: converts the year from an integer to Hebrew numerals. + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | document.writeln(dojox.date.hebrew.numerals.getYearHebrewLetters(date1.getFullYear()); + + var rem = year % 1000; + //FIXME: tests include dates outside this range and seem to pass. + // if((year - rem) / 1000 != 5){ throw new Error("Hebrew year "+year+" is not in range 5001-5999");} + return transformChars(convertNumberToStr(rem)); // String + }; + + dojox.date.hebrew.numerals.parseYearHebrewLetters = function(/*String hebrew year*/ year){ + // summary: converts the year written in Hebrew numerals to an integer + // + // example: + // | var date = new dojox.date.hebrew.Date(); + // | date.setFullYear(dojox.date.hebrew.numerals.parseYearHebrewLetters('\u05ea\u05e9\u05e1\u05f4\u05d7')); + + return parseStrToNumber(year) + 5000; // int + }; + + dojox.date.hebrew.numerals.getDayHebrewLetters = function(day, /*boolean?*/ nogrsh){ + // summary: converts an integer to a String representing the number in Hebrew numerals. Can be formatted with or without geresh ׳ + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | document.writeln(dojox.date.hebrew.numerals.getDayHebrewLetters(date1.getDay()); + + return transformChars(convertNumberToStr(day), nogrsh); // String + }; + + dojox.date.hebrew.numerals.parseDayHebrewLetters = function(/*String hebrew*/ day){ + // summary: converts the string containing a Hebrew numeral to an integer + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | date1.setDate(dojox.date.hebrew.numerals.parseDayHebrewLetters('\u05d0')); // ALEPH + return parseStrToNumber(day); // int + }; + + dojox.date.hebrew.numerals.getMonthHebrewLetters = function(/*int*/month){ + // summary: converts an integer representing a month to a String written in Hebrew numerals + // + // example: + // | var date1 = new dojox.date.hebrew.Date(); + // | + // | document.writeln(dojox.date.hebrew.numerals.getMonthHebrewLetters(date1.getMonth()); + + return transformChars(convertNumberToStr(month+1)); // String + }; + + dojox.date.hebrew.numerals.parseMonthHebrewLetters = function(/*String*/monthStr){ + // summary: converts a Hebrew numeral string representing + // a month to an integer. The returned value + // is indexed in the month name array. To use it for + // setMonth, do correction for leap year + // + // example: + // | var date = new dojox.date.hebrew.Date(); + // | var number = dojox.date.hebrew.numerals.parseMonthHebrewLetters("\u05ea\u05de\u05d5\u05d6"); // Tammuz + // | date.setMonth(number); + + //month number from 0 to 12 + var monnum = dojox.date.hebrew.numerals.parseDayHebrewLetters(monthStr) - 1; + + if(monnum == -1 || monnum > 12){ + throw new Error("The month name is incorrect , month = " + monnum); + } + return monnum; + }; + return dojox.date.hebrew.numerals; +}); |
