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

com.smartclient.debug.public.sc.client.language.Time.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 Time
// Helper methods and system-wide defaults for dealing with time values and time display formats.
// 

// This class includes utility methods for the creation and display of logical time values, as well // as modifying the default display timezone for datetime type values. See // +link{group:dateForamtAndStorage} for more information on working with dates, times and datetimes // in SmartClient. // // @treeLocation Client Reference/System // @visibility external //< isc.ClassFactory.defineClass("Time"); isc.Time.addClassProperties({ //> @classAttr Time.UTCHoursOffset (number : null : IRA) // Hour offset from UTC to use when formatting +link{fieldType,"datetime"} type fields for // display to the user. //

// Has no effect on fields specified as logical date (field.type = "date";) and // logical time (field.type = "time") fields. // // @visibility external // @deprecated As of 7.0 this attribute has been deprecated in favor of // +link{Time.setDefaultDisplayTimezone()} //< //UTCHoursOffset:0, // ** On page load we check for this property being set and use it to call // setDefaultDisplayTimezone() with a deprecated warning //> @classMethod Time.setDefaultDisplayTimezone() // Sets the offset from UTC to use when formatting values of type +link{FieldType,datetime} // with standard display formatters. //

// This property effects how dates are displayed and also the // assumed timezone for user-input. For a concrete example - assume this method has been called // and passed a value of "+01:00", and an application has a +link{DateTimeItem} visible in // a DynamicForm. If the value of this field is set to the current date, with UTC time set to // "10:00", the time portion of the value displayed in the form item will be "11:00". // Similarly if a user modifies the time value in the text box to be "16:00", a call to // +link{FormItem.getValue()} for the item will return a date object with UTC time set to 15:00. //

// Interaction with daylight savings time: By default the specified displayTimezone will be // adjusted to account for DST if the native browser locale applies DST. The specified // "defaultDisplayTimezone" will always be exactly respected for the current date, and // further adjusted for dates that fall outside the current daylight savings time mode.
// In other words if DST is currently not in effect (IE: the current date is a Winter date), // any other dates where DST is not in effect will be formatted to exactly respect the specified // defaultDisplayTimezone (so for defaultDisplayTimezone of "+01:00", the display // string will be 1 hour ahead of the UTC time on the date in question), and any // dates where DST is in effect would be further adjusted to account for DST // (so the display string would be 2 hours ahead for dates that fall in the Summer).
// Alternatively if DST currently is in effect (EG: Current date is a Summer date) // the situation is reversed. Any date value for which DST should be applied // will be be formatted for display with an offset of 1 hour from UTC - and any date value // for which DST should not be applied would be formatted with an offset of 0 hours from UTC. //
// Note that the +link{Time.adjustForDST} property may be set to false to // disable this logic - in this case the time portion of dates will always be offset from // UTC by exactly the specified defaultDisplayOffset, regardless of whether they fall in the // range where Daylight Savings Time would usually be applied or not. //

// Note that if a custom timezone is specified, it will not effect native javascript // date formatting functions such as toLocaleString(). // See +link{group:dateFormatAndStorage} for more on how SmartClient handles date and time // formatting and storage. //

// If this method is never called, the default display timezone for times and datetimes will // be derived from the native browser local timezone. //

// Note that the displayTimezone effects datetime fields only and has no effect on fields // specified as logical date (field.type = "date";) or // logical time (field.type = "time"). // // @param offset (string) offset from UTC. This should be a string in the format // +/-HH:MM for example "-08:00" // @see group:dateFormatAndStorage // @visibility external //< setDefaultDisplayTimezone : function (offset, isBrowserDefault) { this._customTimezone = !isBrowserDefault; if (offset == null) return; // Handle being passed an offset in minutes - this matches the format returned by // native Date.getTimezoneOffset() var hours, minutes; if (isc.isA.Number(offset)) { offset = -offset; hours = Math.floor(offset/60); minutes = offset - (hours*60); } else if (isc.isA.String(offset)) { var HM = offset.split(":"); hours = HM[0]; // If the string starts with "-", hours and minutes will be negative var negative = hours && hours.startsWith("-"); if (negative) hours = hours.substring(1); minutes = HM[1]; hours = (negative ? -1 : 1) * parseInt(hours,10); minutes = (negative ? -1 : 1) * parseInt(minutes,10); } if (isc.isA.Number(hours) && isc.isA.Number(minutes)) { this.UTCHoursDisplayOffset = hours; this.UTCMinutesDisplayOffset = minutes; } }, //> @classMethod Time.getDefaultDisplayTimezone() // Returns the default display timezone set up by +link{Time.setDefaultDisplayTimezone}. // If no explicit timezone has been set this will return the browser locale timezone offset. // @return (string) String of the format +/-HH:MM // @visibility external //< // we don't call this internally since it's easier to to work with the stored hours/minutes // directly getDefaultDisplayTimezone : function () { var H = this.UTCHoursDisplayOffset, M = this.UTCMinutesDisplayOffset, negative = H < 0; return (!negative ? "+" : "") + H.stringify(2) + ":" + ((negative ? -1 : 1) * M).stringify(2); }, //> @classAttr isc.Time._timeExpressions (Array : [..] : IRA) // List of regular expressions to parse a time string // @group parsing //< _timeExpressions : [ /^\s*(\d?\d)\s*[: ]\s*(\d?\d)\s*[: ]\s*(\d?\d)?\s*([AaPp][Mm]?)?\s*([+-]\d{2}:\d{2}|Z)?\s*$/, /^\s*(\d?\d)\s*[: ]\s*(\d?\d)(\s*)([AaPp][Mm]?)?\s*([+-]\d{2}:\d{2}|Z)?\s*$/, /^\s*(\d\d)(\d\d)(\d\d)?\s*([AaPp][Mm]?)?\s*([+-]\d{2}:\d{2}|Z)?\s*$/, /^\s*(\d)(\d\d)(\d\d)?\s*([AaPp][Mm]?)?\s*([+-]\d{2}:\d{2}|Z)?\s*$/, /^\s*(\d\d?)(\s)?(\s*)([AaPp][Mm]?)?\s*([+-]\d{2}:\d{2}|Z)?\s*$/ ], //> @type TimeDisplayFormat // String designating a standard time format for displaying the times associated with // dates strings. // @value toTime // String will display with seconds and am/pm indicator:[H]H:MM:SS am|pm.
// Example: 3:25:15 pm // @value to24HourTime // String will display with seconds in 24 hour time: [H]H:MM:SS.
// Example: 15:25:15 // @value toPaddedTime // String will display with seconds, with a 2 digit hour and am/pm indicator: // HH:MM:SS am|pm
// Example: 03:25:15 pm // @value toPadded24HourTime // String will display with seconds, with a 2 digit hour in 24 hour format: // HH:MM:SS
// Examples: 15:25:15, 03:16:45 // @value toShortTime // String will have no seconds and be in 12 hour format:[H]H:MM am|pm
// Example: 3:25 pm // @value toShort24HourTime // String will have no seconds and be in 24 hour format: [H]H:MM
// Example:15:25 // @value toShortPaddedTime // String will have no seconds and will display a 2 digit hour, in 12 hour clock format: // HH:MM am|pm
// Example: 03:25 pm // @value toShortPadded24HourTime // String will have no seconds and will display with a 2 digit hour in 24 hour clock format: // HH:MM
// Examples: 15:25, 03:16 // // @visibility external //< // To simplify parsing / formatting, map valid formatter names to the details of the format formatterMap:{ toTime:{showSeconds:true, padded:false, show24:false}, to24HourTime:{showSeconds:true, padded:false, show24:true}, toPaddedTime:{showSeconds:true, padded:true, show24:false}, toPadded24HourTime:{showSeconds:true, padded:true, show24:true}, toShortTime:{showSeconds:false, padded:false, show24:false}, toShort24HourTime:{showSeconds:false, padded:false, show24:true}, toShortPaddedTime:{showSeconds:false, padded:true, show24:false}, toShortPadded24HourTime:{showSeconds:false, padded:true, show24:true} }, //> @classAttr Time.displayFormat (TimeDisplayFormat | function : "toTime" : RWA) // Standard formatter to be used when converting a date to a time-string via +link{Time.toTime()} // @setter Time.setNormalDisplayFormat() // @visibility external //< displayFormat:"toTime", //> @classAttr Time.shortDisplayFormat (TimeDisplayFormat | function : "toShortTime" : RWA) // Standard formatter to be used when converting a date to a time-string via +link{Time.toShortTime()} // @setter Time.setShortDisplayFormat() // @visibility external //< shortDisplayFormat:"toShortTime", //> @classAttr Time.AMIndicator (string : " am" : RWA) // String appended to times to indicate am (when not using 24 hour format). // @visibility external // @group i18nMessages //< AMIndicator:" am", //> @classAttr Time.PMIndicator (string : " pm" : RWA) // String appended to times to indicate am (when not using 24 hour format). // @visibility external // @group i18nMessages //< PMIndicator:" pm" //> @classAttr Time.adjustForDST (boolean : true (see description) : RWA) // Determines whether datetime formatters should consider the effect of Daylight Saving // Time when computing offsets from UTC. By default, this flag is set during framework // initialization if SmartClient detects that it is running in a locale that is observing // DST this year. If you do not want DST adjustments to be applied, set this flag to // false.

// Note that setting this flag to true will have no effect unless you are in a locale // that is observing Daylight Saving Time for the date in question; this is because // we rely on the browser for offset information, and browsers are only capable of // returning local date and time information for the computer's current locale. //

// This setting will not have any impact on the display of fields specified as type "time" or // "date" (logical dates and logical times) - only on datetime type values. See // +link{group:dateFormatAndStorage} for information on working with dates, times and datetimes // in SmartClient. // @visibility external //< }); isc.Time.addClassMethods({ //> @classMethod Time.toTime() // Given a date object, return the time associated with the date as a formatted string. // If no formatter is passed, use the standard formatter set up via // +link{Time.setNormalDisplayFormat()}. // // @param date (Date) Date to convert to a time string. // @param [formatter] (TimeDisplayFormat | function) Optional custom formatter to use. Will accept // a function (which will be passed a pointer to the date to perform the conversion), or // a string designating a standard formatter // @param [logicalTime] Is the date passed in a representation of a logical time value such as // a value from a "time" type field on a dataSource or a datetime value? // For datetime values the formatted string will respect any custom // +link{Time.setDefaultDisplayTimezone,display timezone}. // If not explicitly specified, the date passed in will be assumed to be a datetime unless // it was created explicitly as a time via +link{Time.createLogicalTime()} or similar APIs. // @visibility external //< toTime : function (date, formatter, logicalTime) { return this.format(date, formatter, false, logicalTime); }, //> @classMethod Time.toShortTime() // Given a date object, return the time associated with the date as a short string. // If no formatter is passed, use the standard formatter set up via +link{Time.setShortDisplayFormat()} // @param date (Date) Date to convert to a time string. // @param [formatter] (TimeDisplayFormat | function) Optional custom formatter to use. Will accept // a function (which will be passed a pointer to the Date to format), or // a string designating a standard formatter // @param [logicalTime] Is the date passed in a representation of a logical time value such as // a value from a "time" type field on a dataSource or a datetime value? // For datetime values the formatted string will respect any custom // +link{Time.setDefaultDisplayTimezone,display timezone}. // If not explicitly specified, the date passed in will be assumed to be a datetime unless // it was created explicitly as a time via +link{Time.createLogicalTime()} or similar APIs. // @visibility external //< toShortTime : function (date, formatter, logicalTime) { return this.format(date, formatter, true, logicalTime); }, // Given a date return a formatted time string _$timeTemplate:[null, ":", null, ":"], _$shortTimeTemplate:[null, ":"], format : function (date, formatter, shortFormat, logicalTime) { // If we're passed a random object (most likely null or a string), just return it if (!isc.isA.Date(date)) return date; var originalFormatter = formatter; // Sanity check - don't allow unexpected things passed in as a formatter to give us // odd results if (!formatter && !isc.isA.String(formatter) && !isc.isA.Function(formatter)) { formatter = shortFormat ? this.shortDisplayFormat : this.displayFormat; } // Support passing in a completely arbitrary formatter function if (isc.isA.Function(formatter)) return formatter(date, logicalTime); if (isc.isA.String(formatter)) formatter = this.formatterMap[formatter]; if (!isc.isAn.Object(formatter)) { this.logWarn("Invalid time formatter:" + originalFormatter + " - using 'toTime'"); formatter = this.formatterMap.toTime; } var showSeconds = formatter.showSeconds, padded = formatter.padded, show24 = formatter.show24; var useCustomTimezone; if (logicalTime != null) useCustomTimezone = !logicalTime; else useCustomTimezone = !date.logicalTime && !date.logicalDate; var hour,minutes; if (!useCustomTimezone) { hour = date.getHours(); minutes = date.getMinutes(); } else { var hour = date.getUTCHours(), minutes = date.getUTCMinutes(); // Add the display timezone offset to the hours / minutes so we display the // time in the appropriate timezone var hm = this._applyTimezoneOffset(hour, minutes, this.getUTCHoursDisplayOffset(date), this.getUTCMinutesDisplayOffset(date)); hour = hm[0]; minutes = hm[1]; } var seconds = showSeconds ? date.getUTCSeconds() : null, pm = show24 ? null : (hour >=12); // Hour will be in 24 hour format by default if (!show24) { if (hour > 12) hour = hour - 12; if (hour == 0) hour = 12; } if (padded) hour = hour.stringify(2); var template = showSeconds ? this._$timeTemplate : this._$shortTimeTemplate; template[0] = hour; template[2] = minutes.stringify(); if (showSeconds) template[4] = seconds.stringify(); if (!show24) template[5] = (pm ? this.PMIndicator : this.AMIndicator); else template[5] = null; return template.join(isc.emptyString); }, //> @classMethod Time.parseInput() // Converts a time-string such as 1:00pm to a new Date object // representing a logical time value (rather than a specific datetime // value), typically for display in a +link{DataSourceField.type,time type field}. // Accepts most formats of time string. 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). //

// See +link{group:dateFormatAndStorage} for more information on date, time and datetime // values in SmartClient. // // @param timeString (string) time string to convert to a date // @param validTime (boolean) If this method is passed a timeString in an unrecognized format, // return null rather than a date object with time set to 00:00:00 // @visibility external //< // UTCTime param deprecated - leaving supported (though now undocumented) for backCompat only. // // Additional 'isDatetime' and 'baseDatetime' parameters: These are used for the case where we // need to set the time portion of a datetime based on a user-entered time string. // In this case we need to respect the local timezone specified by // +link{time.setDefaultDisplayTimezone}, and we'll also support respecting an explicit // timezone offset from UTC being present in the string (EG: "00:00:00+02:00"). // // Assuming we're not passed a 'baseDatetime', the returned date is always set to 1/1/1970. // This is deliberate: It'll make DST never // an issue and it matches the format for Time values returned by the server for JSON format // DataSources. // // EXTREMELY forgiving of formatting, can accept the following: // 11:34:45 AM => 11:34:45 // 11:34:45 => 11:34:45 // 1:3:5 AM => 01:30:50 // 1:3p => 13:30:00 // 11 34 am => 11:34:00 // 11-34 => 11:34:00 // 113445 => 11:34:45 // 13445 => 01:34:45 // 1134 => 11:34:00 // 134 => 01:34:00 // 11 => 11:00:00 // 1p => 13:00:00 // 9 => 09:00:00 // Also supports explicitly specified timezone offset specified by "+/-HH:MM" at the end, though // we only care about this for the datetime case. logical times are literally a way for us // to work with numbers for H, M and S. // Note: technically being passed "1:00" is ambiguous - could be AM or PM. // We always interpret as 24 hour clock (so <12 = AM) unless am/pm is passed in. parseInput : function (string, validTime, UTCTime, isDatetime, baseDatetime) { var hours = 0, minutes = 0, seconds = 0, // We don't currently extract milliseconds from a time-string. Instead we zero them // out for consistency across times created by this method. milliseconds = 0; var hoursOffset, minutesOffset; // if we're passed a date we'll return a new date with the same time (h/m/s/ms, not the same // date). if (isc.isA.Date(string)) { // We'll match the specified time exactly - no need to manipulate timezone offsets // here since the underlying UTC time will match and any offsetting for display // will occur in formatters. UTCTime = true; hours = string.getUTCHours(); minutes = string.getUTCMinutes(); seconds = string.getUTCSeconds(); milliseconds = string.getUTCMilliseconds(); } else if (string) { // iterate through the time expressions, trying to find a match for (var i = 0; i < isc.Time._timeExpressions.length; i++) { var match = isc.Time._timeExpressions[i].exec(string); if (match) break; } if (match) { // get the hours, minutes and seconds from the match // NOTE: this results in 24:00 going to 23:00 rather than 23:59... var hours = Math.min(parseInt(match[1]|0, 10),23), minutes = Math.min(parseInt(match[2]|0, 10),59), seconds = Math.min(parseInt(match[3]|0, 10),59), ampm = match[4]; ; if (ampm) { if (!this._pmStrings) this._pmStrings = {p:true, P:true, pm:true, PM:true, Pm:true}; if (this._pmStrings[ampm] == true) { if (hours < 12) hours += 12; } else if (hours == 12) hours = 0; } // For dateTimes only, if a timezone was explicitly specified on the value passed in, // respect it. // So we'll handle 18:00:01 -01:00 as 6pm one hour offset from UTC on the generated // date value. // NOTE: the offset specifies the timezone the date is already in, so // to get to UTC we have to subtract the offset if (isDatetime && match[5] != null && match[5] != "" && match[5].toLowerCase() != "z") { var HM = match[5].split(":"), H = HM[0], negative = H && H.startsWith("-"), M = HM[1]; hoursOffset = parseInt(H,10); minutesOffset = (negative ? -1 : 1) * parseInt(M,10); } } else if (validTime) return null; } else if (validTime) return null; var date = isDatetime && baseDatetime != null ? baseDatetime.duplicate() : new Date(null); if (isDatetime || UTCTime) { if (hoursOffset == null) { hoursOffset = UTCTime ? 0 : this.getUTCHoursDisplayOffset(date); } if (minutesOffset == null) { minutesOffset = UTCTime ? 0 : this.getUTCMinutesDisplayOffset(date); } // NOTE: we're creating UTC time -- any offset indicates the offset for the timezone // the inputted time is currently in [either browser local time or explicit offset // passed in as part of the time string], so we need to subtract this offset to get to // UTC time (not add it) var hm = this._applyTimezoneOffset(hours, minutes, (0-hoursOffset), (0-minutesOffset)); hours = hm[0]; minutes = hm[1]; if (hours != null) date.setUTCHours(hours); if (minutes != null) date.setUTCMinutes(minutes); if (seconds != null) date.setUTCSeconds(seconds); if (milliseconds != null) date.setUTCMilliseconds(milliseconds); } else { if (hours != null) date.setHours(hours); if (minutes != null) date.setMinutes(minutes); if (seconds != null) date.setSeconds(seconds); if (milliseconds != null) date.setMilliseconds(milliseconds); } // Mark as logical time so we format / serialize correctly without requiring // explicit "logicalTime" param to formatter functions if (!isDatetime) date.logicalTime = true; return date; }, // Helper method to apply an arbitrary timezone offset to hours / minutes // Returns array: [newHours,newMinutes,dayOffset] // dayOffset ignored for time fields, but can be used to update datetimes _applyTimezoneOffset : function (hours, minutes, hOffset, mOffset) { if (minutes == null || hours == null) { this.logWarn("applyTimezoneOffset passed null hours/minutes"); return [hours,minutes]; } if (hOffset == null) hOffset = 0; if (mOffset == null) hOffset = 0; if (hOffset == 0 && mOffset == 0) return [hours,minutes,0]; hours += hOffset; minutes += mOffset; // Catch the case where the display offset from UTC pushes the hours / minutes // past 60 [or 24] or below zero // (Don't worry about the date - we're only interested in the time!) while (minutes >= 60) { minutes -= 60; hours += 1; } while (minutes < 0) { minutes += 60; hours -= 1; } var dayOffset = 0; while (hours >= 24) { hours -= 24; dayOffset += 1; } while (hours < 0) { hours += 24; dayOffset -= 1; } return [hours,minutes, dayOffset]; }, //> @classMethod Time.createDate() // Creates a date object with the time set to the hours, minutes and seconds passed in. // Unless the UTCTime parameter is passed in, parameters are assumed // to specify the time in native local display time. // @param [hours] (number) Hours for the date (defaults to zero) // @param [minutes] (number) Minutes for the date (defaults to zero) // @param [seconds] (number) Seconds for the date (defaults to zero) // @param [milliseconds] (number) Milliseconds for the date (defaults to zero) // @param [UTCTime] (boolean) If true, treat the time passed in as UTC time rather than local time // @visibility external // @deprecated use +link{Time.createLogicalTime()} instead. //< createDate : function (hours, minutes, seconds, milliseconds, UTCTime) { return this.createLogicalTime(hours, minutes, seconds, milliseconds, UTCTime); }, //> @classMethod Time.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). //

// See +link{group:dateFormatAndStorage} for more information on date, time and datetime // values in SmartClient. // // @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 also available as Date.createLogicalTime [and the deprecated Time.createDate] // The returned date is always set to 1/1/1970. This is deliberate: It'll make DST never // an issue and it matches the format for Time values returned by the server for JSON format // DataSources. createLogicalTime : function (hours, minutes, seconds, milliseconds, UTCTime) { var date = new Date(null); if (hours == null) hours = 0; if (minutes == null) minutes = 0; if (seconds == null) seconds = 0; if (milliseconds == null) milliseconds = 0; if (UTCTime) { date.setUTCHours(hours); date.setUTCMinutes(minutes); date.setUTCSeconds(seconds); date.setUTCMilliseconds(milliseconds); } else { date.setHours(hours); date.setMinutes(minutes); date.setSeconds(seconds); date.setMilliseconds(milliseconds); } date.logicalTime = true; return date; }, //> @classMethod Time.setShortDisplayFormat() // Sets the default format for strings returned by +link{Time.toShortTime()}. // @param formatter (TimeDisplayFormat | function) Optional custom formatter to use. Will accept // a function (which will be passed a pointer to the date to perform the conversion), or // a string designating a standard formatter // @visibility external //< setShortDisplayFormat : function (format) { this.shortDisplayFormat = format; }, //> @classMethod Time.setNormalDisplayFormat() // Sets the default format for strings returned by +link{Time.toTime()}. // @param formatter (TimeDisplayFormat | function) Optional custom formatter to use. Will accept // a function (which will be passed a pointer to the date to perform the conversion), or // a string designating a standard formatter // @visibility external //< setNormalDisplayFormat : function (format) { this.displayFormat = format; }, //> @classMethod Time.compareTimes() // Compares the times of 2 dates, or strings. If a string is passed as one of the // parameters it should be in a format that converts to a valid time such as "1:30pm", // "13:30", or "1:30:45pm" // @param time1 (Date|string) First time to compare // @param time2 (Date|string) Second time to compare // @return (boolean) True if the times match, false if not // @visibility external //< compareTimes : function (time1, time2) { // If this method becomes time-critical we could speed this up by avoiding the // date conversion and having parseInput return just an array of H,M,S if (isc.isA.String(time1)) time1 = isc.Time.parseInput(time1); if (isc.isA.String(time2)) time2 = isc.Time.parseInput(time2); if (time1 == null && time2 == null) return true; // If we get non-dates at this point just return false - we don't want to be // comparing other types if (!isc.isA.Date(time1) || !isc.isA.Date(time2)) return false; return ((time1.getUTCHours() == time2.getUTCHours()) && (time1.getUTCMinutes() == time2.getUTCMinutes()) && (time1.getUTCSeconds() == time2.getUTCSeconds())); }, _performDstInit : function () { var now = new Date(), january = new Date(0), july = new Date(0); // Daylight Saving Time involves moving the clock forward in order to shift some of // the daylight from very early morning (when most people are asleep) to mid-evening // (when people benefit from more hours of daylight, and energy can be saved that // would otherwise be needed for lighting). Not every country observes DST, and those // countries that do observe it set their own start and end dates, though there are // common approaches - for example, many European countries start DST during the last // weekend of March and end it during the last weekend of October. // // Daylight Saving Time, if it is applicable at all, always starts sometime in spring // and ends ends sometime in autumn, but there is no more accurate rule than that. // Currently, every country that observes DST does so by moving their local time // forward by one hour; however, other values have been used, so this cannot be relied // upon either. // // It is common to transition to and from DST ar 02:00 local time - when // DST starts, the local time jumps instantly to 03:00, when DST ends it jumps // instantly back to 01:00. However, this is again a common approach rather than a // rule. // // Note that it is important to think in terms of seasons rather than months, because // the northern and southern hemispheres have opposite seasons. Hence DST (if it // applies at all) starts in March/April and ends in October/November in the northern // hemisphere, and does the exact opposite in the southern hemisphere. // // Because of all of this, and because the only timezone information you can retrieve // from a Javascript Date object is the number of minutes that particular date/time // is offset from UTC, we have quite limited information and must resort to roundabout // techniques. We can discover if we are in a locale that observes DST by checking // the UTC offsets in January and July; if they are different, the current locale // observes DST. // // Going a step further than this, we can tell whether we are observing DST or normal // time on an arbitrary date: by looking to see whether the clock goes forward or // backward in the early part of the year (spring in the northern hemisphere), we can // infer which hemisphere the current locale is in, and from that we can decide if // the offset in January is the DST or non-DST offset. Then, we can check the offset // of the given date against the offset in January; if it matches then it is in DST // if we're in the southern hemisphere, and in normal time if we're in the northern // hemisphere. // // For more interesting information on this subject, see // http://www.timeanddate.com/time/aboutdst.html january.setUTCFullYear(now.getUTCFullYear()); january.setUTCMonth(0); january.setUTCDate(1); july.setUTCFullYear(now.getUTCFullYear()); july.setUTCMonth(6); july.setUTCDate(1); var nowOffset = now.getTimezoneOffset(); this.januaryDstOffset = january.getTimezoneOffset(); var julyOffset = july.getTimezoneOffset(); this.dstDeltaMinutes = this.januaryDstOffset - julyOffset; if (this.dstDeltaMinutes > 0) { // Time is offset further forward from UTC in July; this locale observes DST // and is in the northern hemisphere (this logic is curiously backwards, because // getTimezoneOffset() returns negative numbers for positive offsets) this.southernHemisphere = false; this.adjustForDST = true; if (nowOffset == julyOffset) this.currentlyInDST = true; } else if (this.dstDeltaMinutes < 0) { // Time is offset further forward from UTC in January; this locale observes DST // and is in the southern hemisphere this.southernHemisphere = true; this.adjustForDST = true; if (nowOffset == this.januaryDstOffset) this.currentlyInDST = true; } else { // the delta is 0 and DST is not a factor in this locale this.adjustForDST = false; } // As noted above, all current observations of Daylight Saving Time involve moving // local time one hour forward, so right now these variables will always end up as // 1 and 0 this.dstDeltaMinutes = Math.abs(this.dstDeltaMinutes); this.dstDeltaHours = Math.floor(this.dstDeltaMinutes / 60); this.dstDeltaMinutes -= (this.dstDeltaHours * 60); }, getUTCHoursDisplayOffset : function (date) { // If we're currently inside DST and wanting to calculate an offset for a datetime // that is outside DST, we need to move the offset backwards because the offset we // stored on the Time class during startup already includes the DST offset var dstDelta = this.currentlyInDST ? -(this.dstDeltaHours) : 0; if (this.adjustForDST) { if (date.getTimezoneOffset() == this.januaryDstOffset) { if (this.southernHemisphere) { dstDelta += this.dstDeltaHours; } } else { if (!this.southernHemisphere) { dstDelta += this.dstDeltaHours; } } } return this.UTCHoursDisplayOffset + (this.adjustForDST ? dstDelta : 0); }, getUTCMinutesDisplayOffset : function (date) { var dstDelta = this.currentlyInDST ? -(this.dstDeltaMinutes) : 0; if (this.adjustForDST) { if (date.getTimezoneOffset() == this.januaryDstOffset) { if (this.southernHemisphere) { dstDelta += this.dstDeltaMinutes; } } else { if (!this.southernHemisphere) { dstDelta += this.dstDeltaMinutes; } } } return this.UTCMinutesDisplayOffset + (this.adjustForDST ? dstDelta : 0); } }); // Work out whether we're currently inside Daylight Saving Time, and compute the offset to // apply on the transition. isc.Time._performDstInit(); // set up the default timezone offset based on the browser locale here. isc.Time.setDefaultDisplayTimezone(new Date().getTimezoneOffset(), true);





© 2015 - 2024 Weber Informatics LLC | Privacy Policy