All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartclient.debug.public.sc.client.language.Date.js Maven / Gradle / Ivy

The newest version!
/*
 * Isomorphic SmartClient
 * Version SC_SNAPSHOT-2011-08-08 (2011-08-08)
 * Copyright(c) 1998 and beyond Isomorphic Software, Inc. All rights reserved.
 * "SmartClient" is a trademark of Isomorphic Software, Inc.
 *
 * [email protected]
 *
 * http://smartclient.com/license
 */

 





//> @class DateUtil
// Static singleton class containing APIs for interacting with Dates.
// @visibility external
// @treeLocation Client Reference/System
// @visibility external
//<

isc.defineClass("DateUtil");

//>	@class Date
//
//	Extensions to the Date class, including added static methods on the Date object, and 
//  additional instance methods available on all date instances.
//
//  @treeLocation Client Reference/System
//  @visibility external
//<

//>	@classMethod    isc.timeStamp()
//  Shorthand for new Date().getTime();, this returns a timeStamp - a large number
//  which is incremented by 1 every millisecond.  Can be used to generate unique identifiers,
//  or perform timing tasks.
//
//  @visibility external
//	@return	(number)	a large integer (actually the number of milliseconds since 1/1/1970)
//<

isc.addGlobal("timeStamp", function () {
    
    return new Date().getTime()
});


// synonym
isc.addGlobal("timestamp", isc.timeStamp);


  //>DEBUG
// This lets us label methods with a name within addMethods
Date.prototype.Class = "Date";
Date.Class = "Date";
  //	@classMethod	Date.newInstance()
//			Cover function for creating a date in the 'Isomorphic-style', 
//				eg:   Date.newInstance(args)
//			rather than new Date(args)
//		@return				(Date)		Date object
//      @deprecated As of SmartClient 5.5, use +link{Date.create}.
//<
newInstance : function (arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
	return new Date(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
},


//>	@classMethod	Date.create()
//  Create a new Date object - synonym for new Date(arguments)
//	@return (Date) Date object
//  @visibility external
//<
create : function (arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
    // handle being passed a subset of parameters
    // Note that passing undefined into new Date() results in an invalid date where
    // getTime() returns NaN
    var undef;
    if (arg1 === undef) return new Date();
    if (arg2 === undef) return new Date(arg1);
    if (arg3 === undef) arg3 = 0;
    if (arg4 === undef) arg4 = 0;
    if (arg5 === undef) arg5 = 0;
    if (arg6 === undef) arg6 = 0;
    if (arg7 === undef) arg7 = 0;
	return new Date(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
},

//> @classMethod Date.createLogicalDate()
// Create a new Date to represent a logical date value (rather than a specific datetime value),
// typically for display in a +link{DataSourceField.type,date type field}. The generated
// Date value will have year, month and date set to the specified values 
// (in browser native local time).
// @param year (integer) full year
// @param month (integer) month (zero based, so 0 is January)
// @param date (integer) date within the month
// @return (Date) new javascript Date object representing the Date in question
// @visibility external
//<
// For logical dates, the only requirement for the "time" component value is that the
// date shows up correctly in local time.

createLogicalDate : function (year, month, date, suppressConversion) {
    var d = new Date(); 
    d.setHours(12);
    d.setMinutes(0);
    d.setSeconds(0);
    d.setMilliseconds(0);
    if (date != null) d.setDate(1);
    if (year != null) d.setYear(year);
    if (month != null) d.setMonth(month);
    if (date != null) d.setDate(date);
    
    if (suppressConversion) {
        // If the 'suppressConversion' flag was passed, we will want to return null to indicate
        // we were passed an invalid date if the values passed in had to be converted
        // (For example a month of 13 effecting the year, etc)
        var isValid = (d.getFullYear() == year &&
                       d.getMonth() == month &&
                       d.getDate() == date );
        if (!isValid) return null;
    }
    
    d.logicalDate = true;
    return d;
},

//> @classMethod Date.createLogicalTime()
// Create a new Date object to represent a logical time value (rather than a specific datetime
// value), typically for display in a +link{DataSourceField.type,time type field}. The generated
// Date value will have year, month and date set to the epoch date (Jan 1 1970), and time 
// elements set to the supplied hour, minute and second (in browser native local time).
// @param hour (integer) hour (0-23)
// @param minute (integer) minute (0-59)
// @param second (integer) second (0-59)
// @return (Date) new Javascript Date object representing the time in question
// @visibility external
//<
// This is a synonym for Time.createLogicalTime();
createLogicalTime : function (hour, minute, second, millisecond) {
    return isc.Time.createLogicalTime(hour,minute,second,millisecond);
},

createDatetime : function (year, month, date, hours, minutes, seconds, milliseconds, suppressConversion) {
    var hasHours = hours != null,
        hasMinutes = minutes != null,
        hasSeconds = seconds != null;
    
    // Handle being passed strings
    if (isc.isA.String(hours)) hours = parseInt(hours || 12, 10);
    if (isc.isA.String(minutes)) minutes = parseInt(minutes || 0, 10);
    if (isc.isA.String(seconds)) seconds = parseInt(seconds || 0, 10);

    var newDate;
    if (!isc.Time._customTimezone) {
        newDate = new Date(year, month, date);
        if (hasHours) {
            if (hours != null) newDate.setHours(hours);
            if (minutes != null) newDate.setMinutes(minutes);
            if (seconds != null) newDate.setSeconds(seconds);
            if (milliseconds != null) newDate.setMilliseconds(milliseconds);
        }
                   
        if (!suppressConversion) return newDate;
        
        // If the 'suppressConversion' flag was passed, we will want to return null to indicate
        // we were passed an invalid date if the values passed in had to be converted
        // (For example a month of 13 effecting the year, etc)
        var isValid = (newDate.getFullYear() == year &&
                       newDate.getMonth() == month &&
                       newDate.getDate() == date &&
                       (!hasHours || newDate.getHours() == hours) &&
                       (!hasMinutes || newDate.getMinutes() == minutes) &&
                       (!hasSeconds || newDate.getSeconds() == seconds)
                       );
        return (isValid ? newDate : null);
    } else {
        
        // We need a date where the UTCTime is set such that when we apply our
        // custom timezone offset we get back the local time.
        // Do this by creating a new date with UTC time matching this custom display time
        // and then shifting that date by the inverse of our display timezone offset.
        if (hours == null) hours = 0;
        if (minutes == null) minutes = 0;
        if (seconds == null) seconds = 0;
        if (milliseconds == null) milliseconds = 0;
        newDate = new Date(Date.UTC(year, month, date, hours, minutes, seconds, milliseconds));
        // If the 'suppressConversion' flag was passed, we will want to return null to indicate
        // we were passed an invalid date if the values passed in had to be converted
        // (For example a month of 13 effecting the year, etc)
        // Easiest to check this against the date before we apply the offset to correct for
        // our timezone           
        if (suppressConversion) {
            var isValid = (newDate.getUTCFullYear() == year &&
                           newDate.getUTCMonth() == month &&
                           newDate.getUTCDate() == date &&
                           (!hasHours || newDate.getUTCHours() ==hours) &&
                           (!hasMinutes || newDate.getUTCMinutes() == minutes) &&
                           (!hasSeconds || newDate.getUTCSeconds() == seconds)
                           );
            if (!isValid) newDate = null;
        }
        if (newDate != null) {
            newDate._applyTimezoneOffset(
                -isc.Time.getUTCHoursDisplayOffset(newDate), 
                -isc.Time.getUTCMinutesDisplayOffset(newDate)
            );
        }
        return newDate;
    }
},

//>	@classMethod	Date.compareDates()
// Compare two dates; returns 0 if equal, -1 if the first date is greater (later), or 1 if
// the second date is greater.
//  @param  date1   (date)  first date to compare
//  @param  date2   (date)  second date to compare
//  @return (number)    0 if equal, -1 if first date > second date, 1 if second date > first date
// @visibility external
//<
compareDates : function (a, b) {
	var aval = (a != null ? a.getTime() : 0),
        bval = (b != null ? b.getTime() : 0);
	return aval > bval ? -1 : (bval > aval ? 1 : 0); 
},

//>	@classMethod	Date.compareLogicalDates()
// Compare two dates, normalizing out the time elements so that only the date elements are 
// considered; returns 0 if equal, -1 if the first date is greater (later), or 1 if
// the second date is greater.
//  @param  date1   (date)  first date to compare
//  @param  date2   (date)  second date to compare
//  @return (number)    0 if equal, -1 if first date > second date, 1 if second date >
//                      first date.  Returns false if either argument is not a date
// @visibility external
//<
compareLogicalDates : function (a, b) {
    if (a == b) return 0; // same date instance
    if (!isc.isA.Date(a) || !isc.isA.Date(b)) return false; // bad arguments, so return false
	var aYear = a.getFullYear(),
	    aMonth = a.getMonth(),
	    aDay = a.getDate(),
	    bYear = b.getFullYear(),
	    bMonth = b.getMonth(),
	    bDay = b.getDate();

    var aval = aYear * 10000 + aMonth * 100 + aDay,
        bval = bYear * 10000 + bMonth * 100 + bDay;
        
	return aval > bval ? -1 : (bval > aval ? 1 : 0); 
},

//>	@type DateInputFormat
//  3 character string containing the "M", "D" and "Y"
//  characters to indicate the format of strings being parsed into Date instances via 
//  Date.parseInput().
//  

// As an example - an input format of "MDY" would parse "01/02/1999" to Jan 2nd 1999 //

// Note: In addition to these standard formats, a custom date string parser function may be // passed directly to +link{Date.setInputFormat()} or passed into +link{Date.parseInput()} as // the inputFormat parameter. // @visibility external //< //> @classMethod Date.setInputFormat() // Sets up the default system-wide input format for strings being parsed into dates via // Date.parseInput(). This will effect how SmartClient components showing editable // date or datetime fields parse user-entered values into live Date objects. //

// The input format can be specified as a +link{type:DateInputFormat} - a 3 character string like // "MDY" indicating the order of the Month, Day and Year components of date strings. //

// As an example - an input format of "MDY" would parse "01/02/1999" to Jan 2nd 1999
// This standard parsing logic will also handle date-time strings such as "01/02/1999 08:45", or // "01/02/1999 16:21:05". //

// Notes: //

    //
  • If the inputFormat is not explicitly set,the system automatically determines // the standard input format will be based on the specified +link{Date.shortDisplayFormat} // wherever possible. // For example if the short display format has been set to "toEuropeanShortDate" the input // format will default to "DMY".
  • //
  • The default date parsing functionality built into SmartClient will handle dates presented // with any separator string, and can 1 or 2 digit day and month values and 2 or 4 digit year // values. This means that in many cases custom date display formats can be parsed back to // Date values without the need for a custom parser function. However if more sophisticated // parsing logic is required, a function may be passed into this method. In this case the // parser function should be able to handle parsing date and datetime values formatted // via +link{Date.toShortDate()} and +link{Date.toShortDateTime()}.
  • //
  • Date parsing and formatting logic may be overridden at the component level by setting // properties directly on the component or field in question.
  • //
// @param format (DateInputFormat | function) Default format for strings to be parsed into Dates. // If this method is passed a function, it is expected to take a single parameter // (the formatted date string), and return the appropriate Javascript Date object (or null if // appropriate). // @see Date.parseInput() // @example dateFormat // @example customDateFormat // @visibility external //< setInputFormat : function (format) { this._inputFormat = format; }, //> @classMethod Date.getInputFormat() // Retrieves the default format for strings being parsed into dates via // Date.parseInput() // @see Date.setInputFormat() // @visibility external //< getInputFormat : function () { if (this._inputFormat != null) return this._inputFormat; return this.mapDisplayFormatToInputFormat("toShortDate"); }, // Given a display format return the associated input format _inputFormatMap:{ toUSShortDate:"MDY", toUSShortDateTime:"MDY", toUSShortDatetime:"MDY", toEuropeanShortDate:"DMY", toEuropeanShortDateTime:"DMY", toEuropeanShortDatetime:"DMY", toJapanShortDate:"YMD", toJapanShortDateTime:"YMD", toJapanShortDatetime:"YMD" }, mapDisplayFormatToInputFormat : function (displayFormat) { if (displayFormat == "toShortDate") { displayFormat = Date.prototype._shortFormat; } else if (displayFormat == "toNormalDate") { displayFormat = Date.prototype.formatter; } if (isc.isA.Function(displayFormat)) { isc.Log.logInfo("Unable to determine input format associated with display format " + "function - returning default input format", "Date"); return this._inputFormat || "MDY"; } var inputFormat = this._inputFormatMap[displayFormat]; // Note: isA.String check is necessary - all objects have toString / toLocaleString // present on them and we definitely don't want to return those native object formatters // as what will become a dateString parsing function! if (inputFormat != null && isc.isA.String(inputFormat)) return inputFormat; // a couple of special cases where we actually return functions. if (displayFormat == "toSerializeableDate") return this.parseSchemaDate; // Otherwise you're on your own - assume you've set up input foramt, or overridden this method isc.Log.logInfo("Unable to determine input format associated with display format " + displayFormat + " - returning default input format", "Date"); return this._inputFormat || "MDY"; }, //> @classMethod Date.parseInput() // Parse a date passed in as a string, returning the appropriate date object. // @group dateFormatting // // @param dateString (string) date value as a string // @param [format] (DateInputFormat) Format of the date string being passed. // If not passed, the default date input format as set up // via setInputFormat() will be used. // @param [centuryThreshold] (number) For date formats that support a 2 digit // year, if parsed year is 2 digits and less than this // number, assume year to be 20xx rather than 19xx // @param [suppressConversion] (boolean) // If the string passed in was not a valid date, in some cases we can convert to a // valid date (for example incrementing the year if the month is greater than 12). // This optional parameter will suppress such conversions - anything that doesn't // parse directly to a valid date will simply return null. // @return (Date) date value, or null if the string could not be parsed to a valid date. // @visibility external //< // Note: undocumented isDatetime parameter. Are we creating a logical "date" value or a standard // datetime type value where the time component is important? If ommitted assume datetime. // Implementation-wise, if isDatetime is explicitly false, we will use the system local timezone // rather than any timezone specified via Time.setDisplayTimezone(). parseInput : function (dateString, format, centuryThreshold, suppressConversion, isDatetime) { var logicalDate = (isDatetime == false); if (isc.isA.Date(dateString)) return dateString; if (!isc.isA.String(dateString) || isc.isAn.emptyString(dateString)) { return null; } // Default to the standard input format if (format == null) format = this.getInputFormat(); // If the format passed in is the name of a function on the Date class, or an // explicit function, assume its a parser and call it directly if (isc.isA.Function(Date[format])) format = Date[format]; if (isc.isA.Function(format)) { return format(dateString, centuryThreshold, suppressConversion); } // use the helper method _splitDateString() to get an array of values back // (representing year / month / day, etc.) // If null is returned, this was not a valid date - just return null. // Otherwise make the month zero-based, by reducing by one, and pass construct a new date // from the values returned. var array = this._splitDateString(dateString, format); if (array != null) { var year = array[0]; if (year && year.length <= 2) { year = parseInt(year, 10); if (year < centuryThreshold) year += 2000; else year += 1900 array[0] = year; } if (logicalDate) { return Date.createLogicalDate(array[0], array[1], array[2], suppressConversion); } else { return Date.createDatetime(array[0], array[1], array[2], array[3], array[4], array[5], null, suppressConversion); } } else { return null; } }, // Parse a date or datetime value from a dataset or specified in code. // NB: unlike parseInput, this method should not change behavior in different locales, or dates // coming over the wire or specified in code will suddenly break! // // For Datetime, XML Schema uses "2005-08-01T21:35:48.350Z", see // http://www.w3.org/TR/xmlschema-2/#dateTime // SmartClient Server parses "yyyy-mm-dd" format parseSchemaDate : function (value) { if (isc.isA.Date(value)) return value; if (!isc.isA.String(value)) value = (value.toString ? value.toString() : value + ""); // Notes on regex: // - result[4] is the optional timestamp including the T and colon separators // - result[8] would be the optional milliseconds including the ".", whereas // result[9] is just the numeric part // results[10] is the timezone - either "Z" (zulu time or GMT) or +/- HH:MM var result = value.match(/(\d{4})[\/-](\d{2})[\/-](\d{2})([T ](\d{2}):(\d{2}):(\d{2}))?(\.(\d+))?([+-]\d{2}:\d{2}|Z)?/); //isc.Log.logWarn("isDate: '" + value + "', regex match: " + result); if (result == null) return null; var dateValue; // NOTE: pass only the relevant arguments as Moz does not like being passed nulls if (!result[4]) { // no time dateValue = Date.createLogicalDate(result[1], result[2] - 1, result[3]); } else if (!result[9]) { // no ms dateValue = new Date(Date.UTC(result[1], result[2] - 1, result[3], result[5], result[6], result[7])); } else { var ms = result[9]; // XML Schema says any number of fractional digits can be specified. new Date() is // expecting a whole number of milliseconds (and further precision would be ignored). // Multiply by a power of ten based on the number of digits provided, such that ".9" // becomes 900 and ".98367" becomes 984. if (ms.length != 3) { var multiplier = Math.pow(10,3-ms.length); ms = Math.round(parseInt(ms,10) * multiplier); } //isc.Log.logWarn("ms is: " + ms); dateValue = new Date(Date.UTC(result[1], result[2] - 1, result[3], result[5], result[6], result[7], ms)); } // Handle timezone offset from GMT if (result[10] && result[10].toLowerCase() != "z") { var HM = result[10].split(":"), H = HM[0], negative = H && H.startsWith("-"), M = HM[1]; H = parseInt(H, 10); M = parseInt(M, 10); var dateTime = dateValue.getTime(); // Note no need to account for negative on hours since the "+" or "-" prefix was picked up // in parseInt if (isc.isA.Number(H)) dateTime -= (3600000 * H); if (isc.isA.Number(M)) dateTime -= (60000 * M * (negative ? -1 : 1)); dateValue.setTime(dateTime); } return dateValue }, //>!BackCompat 2005.11.3 // parseDate() was old name for parseInput parseDate : function (dateString, format, centuryThreshold, suppressConversion) { return this.parseInput(dateString, format, centuryThreshold, suppressConversion); }, // For completeness also support parseDatetime() parseDateTime : function (dateString, format, centuryThreshold, suppressConversion) { return this.parseDatetime(dateString,format,centuryThreshold,suppressConversion); }, parseDatetime : function (dateString, format, centuryThreshold, suppressConversion) { return this.parseInput(dateString, format, centuryThreshold, suppressConversion); }, //Safari12 if (isc.Browser.isSafari && isc.Browser.safariVersion <= 312) { var splitDate = this._splitDateViaSubstring(string, monthIndex, dayIndex, yearIndex); year = splitDate[0]; month = splitDate[1]; day = splitDate[2]; hour = splitDate[3]; minute = splitDate[4]; second = splitDate[5]; // For browsers that support RegExp properly, use regexp pattern matching to get the result // (This has the advantage that we can deal with dates of the form 1/1/1999, and attempt to // convert MM/YY/DD -- though we're relying on the native browser handling for the // Date constructor being passed a 2 digit year) } else { //Safari12 } // @type DateDisplayFormat // Valid display formats for dates. These strings are the names of formatters which can be // passed to Date.setNormalDisplayFormat() or Date.setShortDisplayFormat() // and will be subsequently used as default long or short formatters for date objects by // SmartClient components.
// Default set of valid display formats is as follows:

// // @value toString // Default native browser 'toString()' implementation. May vary by browser.
// Example: Fri Nov 04 2005 11:03:00 GMT-0800 (Pacific Standard Time) // @value toLocaleString // Default native browser 'toLocaleString()' implementation. May vary by browser. // Example: Friday, November 04, 2005 11:03:00 AM // @value toUSShortDate Short date in format MM/DD/YYYY.
// Example: 11/4/2005 // @value toUSShortDatetime Short date with time in format MM/DD/YYYY HH:MM
// Example: 11/4/2005 11:03 // @value toEuropeanShortDate Short date in format DD/MM/YYYY.
// Example: 4/11/2005 // @value toEuropeanShortDatetime Short date with time in format DD/MM/YYYY HH:MM
// Example: 4/11/2005 11:03 // @value toJapanShortDate Short date in format YYYY/MM/DD.
// Example: 2005/11/4 // @value toJapanShortDatetime Short date with time in format YYYY/MM/DD HH:MM
// Example: 2005/11/4 11:03 // @value toSerializeableDate Date in the format YYYY-MM-DD HH:MM:SS
// Example: 2005-11-04 11:09:15 // @value toDateStamp Date in the format <YYYYMMDD>T<HHMMSS>Z // Example: 20051104T111001Z //
//
// Note: In addition to these standard formats, custom formatting can be set by passing // a function directly to +link{Date.setNormalDisplayFormat()} et al. This // function will then be executed whenever the appropriate formatter method is called [eg // +link{date.toNormalDate()}], in the scope of the date instance in question. // // @visibility external //< //> @classMethod Date.setNormalDisplayFormat() // Set the default formatter for date objects to the method name passed in. After calling this // method, subsequent calls to +link{Date.toNormalDate()} will return a string formatted // according to this format specification. Note: this will be the standard long date format used // by SmartClient components.
// The format parameter may be either a +link{DateDisplayFormat} string, or // a function. If passed a function, this function will be executed in the scope of the Date // and should return the formatted string.
// Initial default normalDisplayFormat is "toLocaleString" // @group dateFormatting // @param format (DateDisplayFormat | function) new formatter // @visibility external //< setNormalDisplayFormat : function (format) { // if a valid formatter was passed in, set our .formatter property if (isc.isA.Function(Date.prototype[format]) || isc.isA.Function(format)) { Date.prototype.formatter = format; } }, //> @classMethod Date.setShortDisplayFormat() // Set the default short format for dates. After calling this method, subsequent calls to // +link{Date.toShortDate()} will return a string formatted according to this format // specification. Note that this will be the standard short date format used by // SmartClient components. //

// The format parameter may be either a +link{DateDisplayFormat} string, or // a function. If passed a function, this function will be executed in the scope of the Date // and should return the formatted string. //

// Initial default shortDateFormat is "toUSShortDate". This property // is commonly modified for localization of applications. See // +externalLink{http://en.wikipedia.org/wiki/Date_format_by_country} // for a useful overview of standard date formats per country. // // @group dateFormatting // @param format (DateDisplayFormat | function) new formatter // @example dateFormat // @example customDateFormat // @visibility external //< setShortDisplayFormat : function (format) { if (isc.isA.Function(Date.prototype[format]) || isc.isA.Function(format)) { Date.prototype._shortFormat = format; } }, //> @classMethod Date.setDefaultDateSeparator // Sets a new default separator that will be used when formatting dates. By default, this // is a forward slash character: "/" // @group dateFormatting // @param separator (string) separator to use in dates // @visibility external //< setDefaultDateSeparator : function (separator) { Date.prototype._shortDateTemplate = [,,,,separator,,,,,separator,,,,null]; Date.prototype._separator = separator; }, //> @classMethod Date.getDefaultDateSeparator // gets the default date separator string // @group dateFormatting // @return(string) the default date separator // @visibility external //< getDefaultDateSeparator : function (separator) { if (Date.prototype._separator) return Date.prototype._separator; else return "/"; }, //> @classMethod Date.setShortDatetimeDisplayFormat() // Set the default short format for datetime values. After calling this method, subsequent calls to // +link{Date.toShortDateTime()} will return a string formatted according to this format // specification. Note that this will be the standard datetime format used by // SmartClient components. //

// The format parameter may be either a +link{DateDisplayFormat} string, or // a function. If passed a function, this function will be executed in the scope of the Date // and should return the formatted string. //

// Initial default format is "toUSShortDatetime". See // +externalLink{http://en.wikipedia.org/wiki/Date_format_by_country} // for a useful overview of standard date formats per country. // // @group dateFormatting // @param format (DateDisplayFormat | function) new formatter // @example dateFormat // @example customDateFormat // @visibility external //< setShortDatetimeDisplayFormat : function (format) { if (isc.isA.Function(Date.prototype[format]) || isc.isA.Function(format)) { Date.prototype._shortDatetimeFormat = format; } }, //>!BackCompat 2005.11.3 // -- Older depracated synonym of setNormalDisplayFormat //> @classMethod Date.setFormatter() // Set the formatter for all date objects to the method name passed in. After this call // all theDate.toNormalDate() calls will fall through to this formatter function to // return the date as a string. // @group dateFormatting // @param functionName (string) name of a date formatter method on this Date // @visibility internal //< setFormatter : function (formatter) { Date.setNormalDisplayFormat(formatter); }, // @classMethod Date.setLocaleStringFormatter() (A) // Set default the +link{Date.iscToLocaleString()} formatter for all date instances. // // @param format (DateDisplayFormat | function) new formatter for iscToLocaleString() // @group dateFormatting // @visibility internal //< setLocaleStringFormatter : function (functionName) { if (isc.isA.Function(Date.prototype[functionName]) || isc.isA.Function(functionName)) Date.prototype.localeStringFormatter = functionName; }, // Localizing dayName / monthNames //> @classAttr Date.shortDayNames (Array : null : IRWA) // This property may be set to an array of names of days of the week.
// For example: //

// ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
// 
// The appropriate day name will then be returned from +link{date.getShortDayName()}, and may // be used whenever SmartClient components display day-names (for example in the // +link{class:DateItem, DateItem class}).
// Note: For US based applications the first item in the array should be the name for Sunday, // then Monday, Tuesday, etc. For browsers with different locales this may vary. // To determine the first day for some locale, you can run the following code: //
//    alert(new Date(2000, 0, 2).getDay());
// 
// You should see an alert with a number between zero and 6. This represents the numerical // 'day' value for Sunday for your browser's locale, since Jan 2nd 2000 was a Sunday. // Therefore if this code alerted the number 6, Sunday should appear last in your list // of day-names, and Monday first. // @group i18nMessages // @visibility external //< //> @classAttr Date.shortMonthNames (Array : null : IRWA) // This property may be set to an array of names of months.
// For example: //
// ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
// 
// The appropriate month name will then be returned from +link{date.getShortMonthName()}, // and may be used whenever SmartClient components display month-names (for example in the // +link{class:DateItem, DateItem class}). // @group i18nMessages // @visibility external //< //> @method date.getShortMonthNames() (A) // Return an array of the short names of each month, suitable for us in a selection list, etc. // If +link{Date.shortMonthNames} is specified, this list will be used. Otherwise the value // will be derived from the native browser date formatters. // @group dateFormatting // // @param length (number) Number of characters for each day (Defaults to 3, can't be // longer than 3) // @return (string[]) array of short month names //< getShortMonthNames : function (length) { length = length || 3; var rawNames = Date.shortMonthNames; if (rawNames == null) rawNames = Date._derivedShortMonthNames; if (rawNames == null) { var list = Date._derivedShortMonthNames = []; for (var i = 0; i < 12; i++) { // Changed the day in this synthetic date to 2 in order to derive the // correct month in timezones that are ahead of GMT (if you convert // midnight on the first of a month to UTC in such timezones, you // get the previous month...) var date = Date.createLogicalDate(2000,i,2); list[i] = date.deriveShortMonthName(); } rawNames = Date._derivedShortMonthNames; } var names = []; for (var i =0; i< 12; i++) { names[i] = rawNames[i].substring(0,length); } return names; }, //> @method date.getShortDayNames() (A) // Return an array of the short names of each day, suitable for us in a selection list, etc. // Day names will be picked up from +link{Date.shortDayNames} if specified - otherwise derived // from the native browser date string. // @group dateFormatting // // @param length (number) Number of characters for each day (Defaults to 3, can't be // longer than 3) // @return (string[]) array of short day names //< getShortDayNames : function (length) { length = length || 3; var rawNames = Date.shortDayNames; if (rawNames == null) rawNames = Date._derivedShortDayNames; if (rawNames == null) { Date._derivedShortDayNames = []; var dateObj = new Date(); dateObj.setDate(1); if (dateObj.getDay() > 0) dateObj.setDate(dateObj.getDate() + (7-dateObj.getDay())); var startDate = dateObj.getDate(); for (var i = 0; i < 7; i++) { dateObj.setDate(startDate + i); Date._derivedShortDayNames[i] = dateObj.deriveShortDayName(); } rawNames = Date._derivedShortDayNames; } var names = []; for (var i = 0; i < 7; i++) { names[i] = rawNames[i].substring(0,length); } return names; }, //> @classAttr Date.weekendDays (Array of int : [0, 6] : IR) // Days that are considered "weekend" days. Values should be the integers returned by the // JavaScript built-in Date.getDay(), eg, 0 is Sunday and 6 is Saturday. Override to // accommodate different workweeks such as Saudi Arabia (Saturday -> Wednesday) or Israel // (Sunday -> Thursday). // // @visibility external //< //> @classMethod Date.getWeekendDays() // Return an array of days that are considered "weekend" days. Values will be the integers // returned by the JavaScript built-in Date.getDay(), eg, 0 is Sunday and 6 is Saturday. // Override +link{date.weekendDays} to accommodate different workweeks such as Saudi Arabia // (Saturday -> Wednesday) or Israel (Sunday -> Thursday). // @group dateFormatting // // @return (int[]) array of weekend days //< getWeekendDays : function () { var daysArr = Date.weekendDays; if (daysArr == null) daysArr = Date._derivedWeekendDays; if (daysArr == null) { daysArr = Date._derivedWeekendDays = [0, 6]; } return daysArr; }, getFormattedDateRangeString : function (fromDate, toDate) { if (fromDate != null && !isc.isA.Date(fromDate)) { fromDate = null; } if (toDate != null && !isc.isA.Date(toDate)) { toDate = null; } var fromMonth = fromDate ? fromDate.getMonth() : null, fromMonthName = fromDate ? fromDate.getShortMonthName() : null, fromYear = fromDate ? fromDate.getFullYear() : null, fromDay = fromDate ? fromDate.getDate() : null, toMonth = toDate ? toDate.getMonth() : null, toMonthName = toDate ? toDate.getShortMonthName() : null, toYear = toDate ? toDate.getFullYear() : null, toDay = toDate ? toDate.getDate() : null, result = "" ; if (fromDate && toDate) { if (fromYear == toYear) { // dates are in the same year - check the months if (fromMonth == toMonth) { // dates are in the same month - check the day-numbers if (fromDay == toDay) { // dates are the same - use just the one date result = fromMonthName + " " + fromDate.getDate() + ", " + fromYear; } else { // day-numbers are different, use "month start - end, year" result = fromMonthName + " " + fromDate.getDate() + " - " + toDate.getDate() + ", " + fromYear; } } else { // dates are in different months, use "month start - month end, year" result = fromMonthName + " " + fromDate.getDate() + " - " + toMonthName + " " + toDate.getDate() + ", " + fromYear; } } else { // different years - use "month start year - month end year" result = fromMonthName + " " + fromDate.getDate() + ", " + fromYear + " - " + toMonthName + " " + toDate.getDate() + ", " + toYear; } } else if (fromDate) { // only a fromDate provided use "month start - end, year" result = fromMonthName + " " + fromDate.getDate() + ", " + fromYear; } else if (toDate) { // only a toDate provided use "month start - end, year" result = toMonthName + " " + toDate.getDate() + ", " + toYear; } return result; } }); // // add methods to the Date.prototype for additional formatting options // isc.addMethods(Date.prototype, { //> @method date.duplicate() (A) // Copy the value of this date into a new Date() object for independent manipulation // @visibility external //< duplicate : function () { var newDate = new Date(); newDate.setTime(this.getTime()); newDate.logicalDate = this.logicalDate; newDate.logicalTime = this.logicalTime; return newDate; }, //> @method date.clearTimeFields() (A) // Zero-out the time fields for a date. // @group dateFormatting //< clearTimeFields : function () { this.setHours(0); this.setMinutes(0); this.setSeconds(0); this.setMilliseconds(0); return this; }, // Determine the day name from this.toString() deriveShortDayName : function (length) { var string = this.toString(); if (length == null || length <=0 || length > 3) length = 3; return string.substring(0,length); }, //> @method date.getShortDayName() // Return the abbreviated (up to 3 chars) day of week name for this date (Mon, Tue, etc). // To modify the value returned by this method, set +link{Date.shortDayNames} // // @group dateFormatting // @param length (number) Number of characters to return (Defaults to 3, can't be // longer than 3) // @return (string) Abbreviated day name // @visibility external //< getShortDayName : function () { return Date.getShortDayNames()[this.getDay()]; }, // deriveShortMonthNames() - figure out the names of months from the native browser // date formatting methods. deriveShortMonthName : function (length) { // Use this.toUTCString - to work around Opera's different toString format var string = this.toUTCString(); var start = 8; // The correct start point if we have a 2-digit day portion in the date if (length == null || length < 0 || length > 3) length = 3; if (string.substring(6, 7) == ' ') { // we have a single-digit day number - only IE // does this, the others put a leading 0 in start = 7; } return string.substring(start, (start+length)); }, //> @method date.getShortMonthName() // Return the abbreviated (up to 3 chars) name of the month for this date (Jan, Feb, etc) // To modify the value returned by this method, set +link{Date.shortMonthNames} // @group dateFormatting // @param length (number) Number of characters to return (Defaults to 3, can't be // longer than 3) // @return (string) Abbreviated month name (3 character string) // @visibility external //< getShortMonthName : function () { return Date.getShortMonthNames()[this.getMonth()]; }, //> @method date.getShortYear() // Return a 2 digit year for this date. // @group dateFormatting // @return (string) year number, padded to 2 characters // @visibility external //< getShortYear : function () { var year = this.getFullYear(); return (year % 100).stringify(2); }, //> @method date.getWeek() // Returns an integer containing the week number // @group dateFormatting // @return (integer) week number, starting with 1 // @visibility external //< getWeek : function() { var yearstart = new Date(this.getFullYear(),0,1); return Math.ceil((((this - yearstart) / 86400000) + yearstart.getDay())/7); }, // // Date Formatters (toNormalDate(), toShortDate(), etc.) // // Date formatters are applied to date objects to convert them into strings for display. // Dates are intended to be localizable. // For localization, a developer would typically set either the shortDateFormatter or // normalDateFormatter, as well as the inputDateFormat, and then call // "toNormalDate()" / "toShortDate()" and "parseInput()" as normal. //> @method date.toDateStamp() // Return this date in the format (UTC timezone): // YYYYMMDDTHHMMSS[Z] // @group dateFormatting // @return (string) formatted date string // @visibility external //< toDateStamp : function () { return this.getUTCFullYear() + (this.getUTCMonth()+1).stringify() + this.getUTCDate().stringify() + "T" + this.getUTCHours().stringify() + this.getUTCMinutes().stringify() + this.getUTCSeconds().stringify() + "Z"; }, //> @method date.toNormalDate() // Returns the date as a formatted string using the format set up via the // setNormalDisplayFormat() method. Note that the default formatter for this // method is "toLocaleString". // @group dateFormatting // @param format (DateDisplayFormat) Optional Format for the date returned // @return (string) formatted date string // @visibility external //< // This method is used by our data components such as ListGrid to display long format dates. // @param useCustomTimezone (boolean) If true, format the date using the timezone // setDefaultDisplayTimezone() rather than the native browser locale. // Defaults to true. // Has no effect if no custom timezone applied // * Note that the native browser formatters including toLocaleString won't respect the // developer specified timezone of course. We could workaround this (create a new date, shift // by offset between specified timezone and native timezone, and call the native formatter on that) // but we currently don't. toNormalDate : function (formatter, useCustomTimezone) { if (!formatter) formatter = this.formatter; // fire the formatter in the scope of this date, so date is available as 'this' if (isc.isA.Function(formatter)) { return formatter.apply(this, [useCustomTimezone]) } else if (this[formatter]) { return this[formatter](useCustomTimezone); } }, //> @method date.toShortDate() // Returns the date as a formatted string using the format set up via the // setShortDisplayFormat() method. // @group dateFormatting // @param format (DateDisplayFormat) Optional Format for the date returned // @param [useCustomTimezone] (boolean) If a custom timezone has been set via // Time.setDefaultDisplayTimezone(), by default date formatters will respect this timezone. // to suppress this behavior, this parameter should be set to false. // @return (string) formatted date string // @visibility external //< toShortDate : function (formatter, useCustomTimezone) { if (!formatter) formatter = this._shortFormat; if (isc.isA.Function(formatter)) return formatter.apply(this, [useCustomTimezone]); else if (isc.isA.Function(this[formatter])) return this[formatter](useCustomTimezone); isc.logWarn("Date.toShortDate() specified formatter not understood:" + formatter); return this.toUSShortDate(); }, //> @method date.toShortDateTime() // Returns the datetime as a formatted string using the format set up via the // setShortDatetimeDisplayFormat() method. // @group dateFormatting // @param format (DateDisplayFormat) Optional Format for the date returned // @param [useCustomTimezone] (boolean) If a custom timezone has been set via // Time.setDefaultDisplayTimezone(), by default date formatters will respect this timezone. // to suppress this behavior, this parameter should be set to false. // @return (string) formatted date string // @visibility external //< toShortDateTime : function (formatter, useCustomTimezone) { return this.toShortDatetime(formatter,useCustomTimezone); }, toShortDatetime : function (formatter, useCustomTimezone) { if (!formatter) formatter = this._shortDatetimeFormat; return this.toShortDate(formatter, useCustomTimezone); }, //> @method date.setDefaultDateSeparator // Sets a new default separator that will be used when formatting dates. By default, this // is a forward slash character: "/" // @group dateFormatting // @param separator (string) separator to use in dates // @visibility external //< setDefaultDateSeparator : function (separator) { this._shortDateTemplate = [,,,,separator,,,,,separator,,,,null]; this._separator = separator; }, //> @method date.getDefaultDateSeparator // gets the default date separator string // @group dateFormatting // @return(string) the default date separator // @visibility external //< getDefaultDateSeperator : function (separator) { if (this._separator) return this._separator; else return "/"; }, _shortDateTemplate:[,,,,"/",,,,,"/",,,,null], _$MDY:"MDY", _$DMY:"DMY", _$YMD:"YMD", _$MDY:"MDY", // _applyTimezoneOffset() // shift a date by some arbitrary number of hours/minutes // third parameter allows you to specify the starting date time [result of date.getTime()] // to offset from _applyTimezoneOffset : function (hourOffset, minuteOffset, dateTime) { if (dateTime == null) dateTime = this.getTime(); if (isc.isA.Number(hourOffset)) dateTime += (3600000 * hourOffset); if (isc.isA.Number(minuteOffset)) dateTime += (60000 * minuteOffset); this.setTime(dateTime); }, // _getTimezoneOffsetDate() // This is a helper method - given a date with a certain UTC time, apply an explicit timezone // offset to return a date where the UTC time is offset by the specified hours/minutes. // We'll use this when formatting dates for display in arbitrary local times [so we can't just // use the native browser local timezone methods like getHours()] _getTimezoneOffsetDate : function (hourOffset, minuteOffset) { var offsetDate = Date._timezoneOffsetDate; if (offsetDate == null) offsetDate = Date._timezoneOffsetDate = new Date(); offsetDate._applyTimezoneOffset(hourOffset, minuteOffset, this.getTime()); return offsetDate; }, // _toShortDate() // Internal method to give us a shortDate - either DD/MM/YYYY, MM/DD/YYYY or YYYY/MM/DD. // this will be passed "MDY" / "DYM" / etc. as a format parameter. // useCustomTimezone parameter: use the hour and minute offset specified by // Time.setDefaultDisplayTimezone() rather than the native browser local timezone _$zero:"0", _toShortDate : function (format, useCustomTimezone) { // if this is a "logical date", don't use the developer-specified custom timezone when // formatting. Typically handled by DBC's passing in the useCustomTimezone parameter, but // we can also check for the logical date marker if (useCustomTimezone == null) { useCustomTimezone = !this.logicalDate; } var template = this._shortDateTemplate, month,day,year; // Browser native locale timezone if (!useCustomTimezone || !isc.Time._customTimezone) { month = this.getMonth()+1; day = this.getDate(); year = this.getFullYear(); // Developer specified custom timezone } else { var offsetDate = this._getTimezoneOffsetDate( isc.Time.getUTCHoursDisplayOffset(this), isc.Time.getUTCMinutesDisplayOffset(this) ); month = offsetDate.getUTCMonth() + 1; day = offsetDate.getUTCDate(); year = offsetDate.getUTCFullYear(); } var monthIndex, dayIndex, yearIndex; if (format == this._$MDY) { monthIndex = 0; dayIndex = 5; yearIndex = 10; } else if (format == this._$DMY) { dayIndex = 0; monthIndex = 5; yearIndex = 10; } else if (format == this._$YMD) { yearIndex = 0; monthIndex = 5; dayIndex = 10 // Unlikely - don't bother avoiding string alloc's for every one of these options } else { dayIndex = format.indexOf("D")*5; yearIndex = format.indexOf("Y")*5; monthIndex = format.indexOf("M")*5; } // Note: each number has 4 slots so it can accommodate a full year // For month/day - if we need a leading zero, fill the first slot with it // Use fillNumber to fill 3 slots even though we have a max of 2 digits to ensure // the last slot gets cleared out if it was populated by a year already. template[dayIndex] = day < 10 ? this._$zero : null isc._fillNumber(template, day, dayIndex+1, 3); template[monthIndex] = month < 10 ? this._$zero : null isc._fillNumber(template, month, monthIndex+1, 3); isc._fillNumber(template, year, yearIndex, 4); return template.join(isc.emptyString); }, //> @method date.toUSShortDate() // Return this date in the format: MM/DD/YYYY // @group dateFormatting // @return (string) formatted date string // @visibility external //< toUSShortDate : function (useCustomTimezone) { return this._toShortDate(this._$MDY, useCustomTimezone); }, // _toShortTime - returns the time portion of the date in HH:MM _timeTemplate:[null,null], _toShortTime : function (useCustomTimezone) { return isc.Time.toShortTime(this, "toShortPadded24HourTime"); }, //> @method date.toUSShortDateTime() // Return this date in the format: MM/DD/YYYY HH:MM // // @group dateFormatting // @return (string) formatted date string // @visibility external //< toUSShortDateTime : function (useCustomTimezone) { return this.toUSShortDatetime(useCustomTimezone); }, toUSShortDatetime : function (useCustomTimezone) { return this.toUSShortDate(useCustomTimezone) + " " + this._toShortTime(useCustomTimezone); }, //> @method date.toEuropeanShortDate() // Return this date in the format: DD/MM/YYYY // @group dateFormatting // @return (string) formatted date string // @visibility external //< toEuropeanShortDate : function (useCustomTimezone) { return this._toShortDate(this._$DMY, useCustomTimezone); }, //> @method date.toEuropeanShortDateTime() // Return this date in the format: DD/MM/YYYY HH:MM. // @group dateFormatting // @return (string) formatted date string // @visibility external //< toEuropeanShortDateTime : function (useCustomTimezone) { return this.toEuropeanShortDatetime(); }, toEuropeanShortDatetime : function (useCustomTimezone) { return this.toEuropeanShortDate(useCustomTimezone) + " " + this._toShortTime(useCustomTimezone); }, //> @method date.toJapanShortDate() // Return the date in this format: YYYY/MM/DD // @group dateFormatting // @return (string) formatted date string // @visibility external //< toJapanShortDate : function (useCustomTimezone) { return this._toShortDate(this._$YMD, useCustomTimezone); }, //> @method date.toJapanShortDateTime() // Return this date in the format: YYYY/MM/DD HH:MM:SS // @group dateFormatting // @return (string) formatted date string // @visibility external //< toJapanShortDateTime : function (useCustomTimezone) { return this.toJapanShortDatetime(useCustomTimezone); }, toJapanShortDatetime : function (useCustomTimezone) { return this.toJapanShortDate(useCustomTimezone) + " " + this._toShortTime(useCustomTimezone); }, //> @method date._serialize() (A) // Serialize this date to a string in a format that can be reinstantiated back into a date. // $$DATE$$:YYYY-MM-DD // @group dateFormatting // @return (string) formatted date string // @visibility internal //< _serialize : function () { if (isc.Comm._legacyJSMode) { // legacy mode: add $$DATE$$ that only our server-side JS parser understands return isc.SB.concat('"' + this.toDBDate(), '"'); } else { // any other caller: return code that would reconstruct the same Date in a JS // interpreter return isc.SB.concat("new Date(", this.getTime(), ")"); } }, //> @groupDef dateFormatAndStorage // The SmartClient system has the following features for handling Date and Time type values // within DataSources and databound components. //

// DataSources and databound components may define fields of type date, // time, or datetime. //

//

"date" handling

//

// Fields of type +link{type:FieldType,date} are considered to be logical Dates with no time // value, such as a holiday or birthday. In the browser, values for "date" fields are stored // as Date objects, but when formatted for display to the user, they are typically displayed // without any time information. //

// When using the SmartClient server framework, "date" values are automatically transmitted // with year, month and day preserved and time value ignored. //

// When sent or received in XML or JSON, date field values should be serialized in the // XML Schema date format - // YYYY-MM-DD - are expected to be received in the same format. Any time value // present for a "date" field is ignored. //

// System wide formatting for dates may be controlled via the // +link{Date.setNormalDisplayFormat()} and +link{Date.setShortDisplayFormat()} methods. //

//

"datetime" handling

//

// Fields of type +link{type:FieldType,datetime} are dates with full time information. // In the browser, values for datetime fields are stored as Date objects. //

// When using the SmartClient server framework, "datetime" values are automatically transmitted // such that the resulting Date object has the same GMT/UTC timestamp (milliseconds since // epoch). //

// When sent or received in XML or JSON, datetime field values should be serialized out as full // datetimes using the standard // XML Schema date format // (EG:2006-01-10T12:22:04-04:00). If no timezone offset is supplied, the value // is assumed to be GMT/UTC. //

// System wide formatting for datetimes may be controlled via the // +link{Date.setShortDatetimeDisplayFormat()} method. Datetimes will be displayed to the user // in browser local time by default (see also timezone notes below). //

//

"time" handling

//

// Fields of type +link{type:FieldType,time} are time values in the absence of a day, such as // the beginning of the workday (9:00). In the browser, values for "time" fields are stored as // Date objects with the time in browser local time. The date information has no meaning and // only the time information is displayed to the user. //

// Time formatting is handled by the +link{Time} class APIs. //
// When using the SmartClient server framework, "time" values are automatically transmitted // such that the resulting Date object has the same hour, minute and second values in local // time, and year/month/day is ignored. //

// When sent or received in XML or JSON, date field values should be serialized as hours, // minutes and seconds using the standard // XML Schema time // format - "22:01:45". Timezone is not relevant and should be omitted. //

//

Timezone settings and Daylight Savings Time

//

// By default, "datetime" values will be shown to the user in browser local time, as derived // from the native browser locale. Developers may modify this behavior by specifying an // explicit display timezone via +link{Time.setDefaultDisplayTimezone()}. //

// Note that depending on the specific date being displayed, a Daylight Savings Time offset may // also be applied based on the browser locale. To disable this behavior set // +link{isc.Time.adjustForDST} to false. //

// If a custom timezone is specified, it will be respected by all +link{TimeDisplayFormat}s, and // by the standard short +link{DateDisplayFormat}s when formatting dates representing datetime // type values. However native JavaScript Date formatters, // including toLocaleString() will not respect the specified timezone. Developers // specifying a custom timezone may therefore wish to modify the +link{Date.setNormalDisplayFormat()} // to avoid using a native JS Date formatter function. //

// Note that in addition to the system-wide date, datetime and time-formatting settings described // above, databound components also support applying custom display formats for date values. // Typically this can be achieved via a custom dateFormatter or // timeFormatter at the field level (see +link{dataSourceField.dateFormatter}, // +link{dataSourceField.timeFormatter} and for example +link{listGridField.dateFormatter}). // Date formatting may also be configured at the component level by setting the // dateFormatter, datetimeFormatter and timeFormatter // attributes (See for example +link{listGrid.dateFormatter}, +link{listGrid.timeFormatter}, // and +link{listGrid.datetimeFormatter}). // // @title Date and Time Format and Storage // @treeLocation Concepts // @visibility external //< _xmlSerialize : function (name, type, namespace, prefix) { return isc.Comm._xmlValue(name, this.toSchemaDate(), type || (this.logicalDate ? "date" : (this.logicalTime && !isc.DataSource.serializeTimeAsDatetime ? "time" : "datetime")), namespace, prefix); }, // logicalType parameter - option to specify "date" vs "datetime" vs "time" which impacts // how this date instance should be serialized out. // Alternatively logicalDate / logicalTime attributes may be hung onto the date objet // directly. // Used by DataSources when serializing dates out toSchemaDate : function (logicalType) { // logical date values have no meaningful time // Note that they also have "no meaningful timezone" - we display native browser locale time // to the user and when we serialize to send to the server we serialize in that same // local timezone. if ((logicalType == "date") || this.logicalDate) { return isc.SB.concat( this.getFullYear().stringify(4), "-", (this.getMonth() + 1).stringify(2), // getMonth() is zero-based "-", this.getDate().stringify(2) ); }; // logical times are serialized as truncated schema strings (HH:MM:SS) by default if ((!isc.DataSource || !isc.DataSource.serializeTimeAsDatetime) && (logicalType == "time" || this.logicalTime)) { return isc.SB.concat( this.getHours().stringify(2), ":", this.getMinutes().stringify(2), ":", this.getSeconds().stringify(2) ); } // represent date time values in UTC return isc.SB.concat( this.getUTCFullYear().stringify(4), "-", (this.getUTCMonth() + 1).stringify(2), // getMonth() is zero-based "-", this.getUTCDate().stringify(2), "T", this.getUTCHours().stringify(2), ":", this.getUTCMinutes().stringify(2), ":", this.getUTCSeconds().stringify(2) ); }, //> @method date.toSerializeableDate() (A) // Return this date in 'serialized' format YYYY-MM-DD HH:MM:SS // @group dateFormatting // @return (String) formatted date string // @visibility external //< toSerializeableDate : function (omitTime) { var output = isc.SB.create(); output.append( this.getFullYear().stringify(4), "-", (this.getMonth() + 1).stringify(2), // getMonth() is zero-based "-", this.getDate().stringify(2) ); if (!omitTime) output.append( (isc.Comm.xmlSchemaMode ? "T" : " "), this.getHours().stringify(2), ":", this.getMinutes().stringify(2), ":", this.getSeconds().stringify(2) ); return output.toString(); }, //> @method date.toDBDate() (A) // Return this date in the format the database can parse as a datetime: // $$DATE$$:YYYY-MM-DD HH:MM:SS // @group dateFormatting // // @return (string) formatted date string // @visibility internal //< // Leave this internal for now toDBDate : function () { return isc.StringBuffer.concat( "$$DATE$$:", this.toSerializeableDate() ); }, //> @method date.toDBDateTime() (A) // Return this date in the format the database can parse as a dateTime: // $$DATE$$:YYYY-MM-DD HH:MM:SS // @group dateFormatting // // @return (string) formatted date string // @visibility internal //< toDBDateTime : function () { return this.toDBDate(); }, //> @method date.setFormatter() // Set the formatter for this date object to the method name passed in. After this call // wherever appropriate SmartClient components will use this formatter function to return // the date as a string. // @group dateFormatting // @param functionName (string) name of a date formatter method on this Date // @visibility external // @deprecated As of SmartClient 5.5 use the static methods // +link{classMethod:Date.setNormalDisplayFormat} and // +link{classMethod:Date.setShortDisplayFormat} to set default formatters for all dates //< setFormatter : function (formatter) { this.setNormalDisplayFormat(formatter); }, //> @method date.setLocaleStringFormatter() (A) // Set the iscToLocaleString() formatter for a specific date object. // After this call, all theDate.toLocaleString() calls will yield a string // in this format. // // @param functionName (string) name of a dateFormatting function // @group dateFormatting // @visibility internal // @deprecated As of SmartClient 5.5 use the static method // +link{classMethod:Date.setLocaleStringFormatter} instead //< setLocaleStringFormatter : function (functionName) { if (isc.isA.Function(this[functionName]) || isc.isA.Function(functionName)) this.localeStringFormatter = functionName; }, // ------------------------Advanced Date Comparison ------------------------------------------- // (currently undocd) isBeforeToday : function (dateObj) { var today = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0).getTime(); if (dateObj.getTime() < today) return true; else return false; }, isToday : function (dateObj) { if (this.getFullYear() == dateObj.getFullYear() && this.getMonth() == dateObj.getMonth() && this.getDate() == dateObj.getDate()) return true; else return false; }, isTomorrow : function (dateObj) { var tomorrowStart = new Date(this.getFullYear(), this.getMonth(), this.getDate() + 1, 0); var tomorrowEnd = new Date(this.getFullYear(), this.getMonth(), this.getDate() + 1, 23); var dateTime = dateObj.getTime(); if (dateTime >= tomorrowStart.getTime() && dateTime <= tomorrowEnd.getTime()) { return true; } else { return false; } }, isThisWeek : function (dateObj) { var weekStart = new Date(this.getFullYear(), this.getMonth(), this.getDate() - this.getDay(), 0); var weekEnd = new Date(this.getFullYear(), this.getMonth(), this.getDate() + (7 - this.getDay()), 23); var dateTime = dateObj.getTime(); if (dateTime >= weekStart.getTime() && dateTime <= weekEnd.getTime()) { return true; } else { return false; } }, isNextWeek : function (dateObj) { var weekStart = new Date(this.getFullYear(), this.getMonth(), (this.getDate() - this.getDay()) + 7, 0); var weekEnd = new Date(this.getFullYear(), this.getMonth(), (this.getDate() - this.getDay()) + 14, 23); var dateTime = dateObj.getTime(); if (dateTime >= weekStart.getTime() && dateTime <= weekEnd.getTime()) { return true; } else { return false; } }, isNextMonth : function (dateObj) { var monthStart = new Date(this.getFullYear(), this.getMonth()); monthStart.setMonth(monthStart.getMonth() + 1); if (monthStart.getFullYear() == dateObj.getFullYear() && monthStart.getMonth() == dateObj.getMonth()) { return true; } else { return false; } } }); //> @method date.toBrowserString() // Native date.toString() provided by the browser for Date objects // @group dateFormatting // @visibility internal // @deprecated As of SmartClient 5.5 //< // Note that the default formatter varies by browser/platform so it's not that useful. // This was exposed in 5.2 so we're keeping it around for back-compat only Date.prototype.toBrowserString = Date.prototype.toString; //> @method date.toBrowserLocaleString() (A) // Synonym for date.toLocaleString() provided by the browser for Date objects // @group dateFormatting // @visibility internal // @deprecated As of SmartClient 5.5 //< Date.prototype.toBrowserLocaleString = Date.prototype.toLocaleString; // set the standard formatter for the date prototype to the native browser string // so everything works as normal until it is overridden. if (!Date.prototype.formatter) Date.prototype.formatter = "toLocaleString" // set the standard toShortDate() formatter to US Short Date if (!Date.prototype._shortFormat) Date.setShortDisplayFormat("toUSShortDate"); if (!Date.prototype._shortDatetimeFormat) Date.setShortDatetimeDisplayFormat("toUSShortDatetime"); //> @method date.iscToLocaleString() (A) // Customizeable toLocaleString() type method. // This method is called when isc.iscToLocaleString(date) is called. // // @group dateFormatting // @return (string) formatted date string // @visibility internal //< // Leave this internal - we don't really expect this to be called directly or overridden by // the developer Date.prototype.iscToLocaleString = function () { var formatter = this.localeStringFormatter; if (isc.isA.Function(formatter)) return formatter.apply(this); else if (this[formatter]) return this[formatter](); } // By default have iscToLocaleString() call date.toLocaleString() if (!Date.prototype.localeStringFormatter) Date.prototype.localeStringFormatter = "toLocaleString"; //>Safari12 isc.addMethods(Date, { // Simple substring matching for splitting up a date string to avoid using unsupported // string.match() method in early Safari // Note - somewhat flawed: we're assuming well never be handed a single digit month or day _splitDateViaSubstring : function (string, monthIndex, dayIndex, yearIndex) { // We know that year may be after month and/or day - allow 3 chars ("DD/") for each var yearCharIndex = yearIndex * 3, year = string.substring(yearCharIndex, yearCharIndex +4) ; // If we have a 2 char year, this may effect the position of the day/month in the string var twoCharYear = (parseInt(year) != year); if (twoCharYear) year = year.substring(0,2); var monthCharIndex = 0, dayCharIndex = 0; if (monthIndex > dayIndex) monthCharIndex += 3; else dayCharIndex += 3; if (monthIndex > yearIndex) monthCharIndex += (twoCharYear?3 : 5); if (dayIndex > yearIndex) dayCharIndex += (twoCharYear ? 3 : 5); // Note: Month is zero based rather than 1 based. var month = string.substring(monthCharIndex, monthCharIndex + 2) -1; var day = string.substring(dayCharIndex, dayCharIndex +2); // Hour minute second are not expected to change orders var hourCharIndex = twoCharYear ? 9 : 11, hour = (string.substring(hourCharIndex,hourCharIndex + 2) || 0), minute = (string.substring(hourCharIndex + 3, hourCharIndex + 5) || 0), second = (string.substring(hourCharIndex + 6, hourCharIndex + 8) || 0); return[year,month,day,hour,minute,second]; } }); //!BackCompat 2005.11.3 isc.addMethods(Date.prototype, { //> @method date.toPrettyString() // Return this date in the format: MM/DD/YY HH:MM // @group dateFormatting // @return (string) formatted date string // @visibility external // @deprecated As of SmartClient 5.5 use +link{date.toShortDate()} instead //< toPrettyString : function () { return this.toUSShortDatetime(); } }); isc.addMethods(Date, { // --- Parsing functions --- : // In 5.2 the paradigm was to provide formatters and complimentary parsers, like // 'toEuropeanShortDate' and 'parseEuropeanShortDate'. // We've moved away from this to instead use a single 'parseInput' function which takes a // 'format' parameter specifying "MDY" / "DMY", etc. // This is appropriate since we do not plan to provide parsing functions for every date formatter // format. // Leaving the older explicit parsing functions in place for back-compat only. //> @classMethod Date.parseStandardDate() // Parse a date passed in as a string of format: // YYYY-MM-DD HH:MM:SS or YYYY-MM-DD // Returning a new Date object with the appropriate value. // // @group dateFormatting // // @param dateString (string) date value as a string // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseStandardDate : function (dateString) { if (!isc.isA.String(dateString)) return null; // Note: we could be using a regexp here rather than substring matches var year = dateString.substring(0,4), month = dateString.substring(5,7)-1, day = dateString.substring(8,10), hour = dateString.substring(11, 13), minute = dateString.substring(14, 16), second = dateString.substring(17, 19); // If they all are numbers, construct a new date // NOTE: If year - month - day gives a number then they // are all numbers, or strings that implicitly convert to numbers. // We could also use this syntax: // if(parseInt(year) == year && parseInt(month) == month ...) // but this is slower in both Moz and IE if (dateString.length < 19) { if (!isc.isA.Number(year - month - day)) return null; } else { if (!isc.isA.Number(year - month - day - hour - minute - second)) return null; } return new Date(year, month, day, hour, minute, second); }, //> @classMethod Date.parseSerializeableDate() // Parse a date passed in as a string of format: // YYYY-MM-DD HH:MM:SS or YYYY-MM-DD // Returning a new Date object with the appropriate value. // This is a synonym for Date.parseStandardDate() // // @group dateFormatting // @param dateString (string) date value as a string // @return (Date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseSerializeableDate : function (dateString) { // synonym for parseStandardDate return this.parseStandardDate(dateString); }, //> @classMethod Date.parseDBDate() // Parse a date passed in as a string of format: // $$DATE$$:YYYY-MM-DD HH:MM:SS // Returning a new Date object with the appropriate value. // // @group dateFormatting // @param dateString (string) date value as a string // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseDBDate : function (dateString) { // remove the leading "$$DATE$$:" if (isc.isA.String(dateString) && dateString.startsWith("$$DATE$$:")) { dateString = dateString.substring(9) return this.parseStandardDate(dateString); } return null; }, //> @classMethod Date.parseDateStamp() // // Parse a dateStamp of the format: YYYYMMDDTHHMMSS[Z]

// // @group dateFormatting // @param dateString (string) String to parse // @return (Date) Date object, or null if not parsed correctly. // // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseDateStamp : function (string) { if (string == null || isc.isA.Date(string)) return string; var date = new Date( Date.UTC( string.substring(0,4), // year parseInt(string.substring(4,6), 10)-1, // mon string.substring(6,8), // day // omit this character (T) string.substring(9,11), // hour string.substring(11,13), // min string.substring(13,15) // Technically we should look at the last character - if its something other // than "z" the timezone would be something other than UTC. )); if (isc.isA.Date(date)) return date; else return null; }, //> @classMethod Date.parseShortDate() // Parse a date passed in as a string of format: MM/DD/YYYY // // @group dateFormatting // @param dateString (string) date value as a string // @param [centuryThreshold] (number) if parsed year is 2 digits and less than this // number, assume year to be 20xx // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseShortDate : function (string, centuryThreshold) { return this.parseInput(string, "MDY", centuryThreshold); }, //> @classMethod Date.parseShortDateTime() // Parse a date passed in as a string of format: MM/DD/YYYY HH:MM:SS // // @group dateFormatting // @param dateString (string) date value as a string // @param [centuryThreshold] (number) if parsed year is 2 digits and less than this // number, assume year to be 20xx // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseShortDateTime : function (string, centuryThreshold) { // synonym for parseShortDate - included for completeness and to provide the appropriate // compliment to date.toShortDateTime() return this.parseShortDate(string, centuryThreshold); }, //> @classMethod Date.parsePrettyString() // Parse a date passed in as a string of format: MM/DD/YY HH:MM:SS // // @group dateFormatting // @param dateString (string) date value as a string // @param [centuryThreshold] (number) if parsed year is less than this // number, assume year to be 20xx rather than 19xx // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parsePrettyString : function (string, centuryThreshold) { // this is just the same as a short date with a 2 digit year. return this.parseShortDate(string, centuryThreshold); }, //> @classMethod Date.parseEuropeanShortDate() // parse a date passed in as a string of format: DD/MM/YYYY // @group dateFormatting // @param dateString (string) date value as a string // @param [centuryThreshold] (number) if parsed year is 2 digits and less than this // number, assume year to be 20xx // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseEuropeanShortDate : function (string, centuryThreshold) { return this.parseInput(string, "DMY", centuryThreshold); }, //> @classMethod Date.parseEuropeanShortDateTime() // parse a date passed in as a string of format: DD/MM/YYYY HH:MM:SS // @group dateFormatting // @param dateString (string) date value as a string // @param [centuryThreshold] (number) if parsed year is 2 digits and less than this // number, assume year to be 20xx // // @return (date) date value // @visibility internal // @deprecated As of SmartClient 5.5 use +link{date.parseInput} instead //< parseEuropeanShortDateTime : function (string, centuryThreshold) { return this.parseInput(string, "DMY", centuryThreshold); }, // Helper to set the time to zero for a datetime setToZeroTime : function (date) { if (date == null || !isc.isA.Date(date)) return date; // Clear the "logicalDate" flag so when we run through formatters we respect // developer specified timezone rather than displaying time in the browser native timezone var wasLogicalDate = date.logicalDate; date.logicalDate = false; var timestamp = date.getTime(); // Apply the timezone offset such that if the default system-wide formatter is used // and applies the display timezone offset, 00:00 will be seen. var hourOffset = isc.Time.getUTCHoursDisplayOffset(date), minuteOffset = isc.Time.getUTCMinutesDisplayOffset(date), utcHours = hourOffset > 0 ? 24-hourOffset : 0-hourOffset, utcMins = minuteOffset > 0 ? 60-minuteOffset : 0-minuteOffset; var oldDisplayDate; if (wasLogicalDate) { oldDisplayDate = date.getDate(); } else { var offsetDate = date._getTimezoneOffsetDate(hourOffset, minuteOffset); oldDisplayDate = offsetDate.getUTCDate(); } date.setUTCHours(utcHours); var displayOffsetDate = date._getTimezoneOffsetDate(hourOffset, minuteOffset), displayDate = displayOffsetDate.getUTCDate(), adjustedUTCHours = utcHours; if (displayDate != oldDisplayDate) { // Cant just check for displayDate > oldDisplayDate since it might be the first or // last of a month... var moveForward = date.getTime() < timestamp; adjustedUTCHours += moveForward ? 24 : -24; date.setUTCHours(adjustedUTCHours); } if (date.getUTCHours() != utcHours) { date.setTime(timestamp); date.setUTCHours(adjustedUTCHours+1); if (date.getUTCHours() != utcHours+1) { date.setTime(timestamp); date.setUTCHours(adjustedUTCHours+2); } } date.setUTCMinutes(utcMins); // No need to return the date - we updated it directly. } }); //





© 2015 - 2024 Weber Informatics LLC | Privacy Policy