function getRule(dt, zone, isUTC) {
      var date = typeof dt === 'number' ? new Date(dt) : dt;
      var ruleset = zone[1];
      var basicOffset = zone[0];

      //Convert a date to UTC. Depending on the 'type' parameter, the date
      // parameter may be:
      //
      // - `u`, `g`, `z`: already UTC (no adjustment).
      //
      // - `s`: standard time (adjust for time zone offset but not for DST)
      //
    // - `w`: wall clock time (adjust for both time zone and DST offset).
      //
      // DST adjustment is done using the rule given as third argument.
      var convertDateToUTC = function (date, type, rule) {
        var offset = 0;

        if (type === 'u' || type === 'g' || type === 'z') { // UTC
          offset = 0;
        } else if (type === 's') { // Standard Time
          offset = basicOffset;
        } else if (type === 'w' || !type) { // Wall Clock Time
          offset = getAdjustedOffset(basicOffset, rule);
        } else {
          throw("unknown type " + type);
        }
        offset *= 60 * 1000; // to millis

        return new Date(date.getTime() + offset);
      };

      //Step 1:  Find applicable rules for this year.
      //
      //Step 2:  Sort the rules by effective date.
      //
      //Step 3:  Check requested date to see if a rule has yet taken effect this year.  If not,
      //
      //Step 4:  Get the rules for the previous year.  If there isn't an applicable rule for last year, then
      // there probably is no current time offset since they seem to explicitly turn off the offset
      // when someone stops observing DST.
      //
      // FIXME if this is not the case and we'll walk all the way back (ugh).
      //
      //Step 5:  Sort the rules by effective date.
      //Step 6:  Apply the most recent rule before the current time.
      var convertRuleToExactDateAndTime = function (yearAndRule, prevRule) {
        var year = yearAndRule[0]
          , rule = yearAndRule[1];
          // Assume that the rule applies to the year of the given date.

        var hms = rule[5];
        var effectiveDate;

        if (!EXACT_DATE_TIME[year])
          EXACT_DATE_TIME[year] = {};

        // Result for given parameters is already stored
        if (EXACT_DATE_TIME[year][rule])
          effectiveDate = EXACT_DATE_TIME[year][rule];
        else {
          //If we have a specific date, use that!
          if (!isNaN(rule[4])) {
            effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4], hms[1], hms[2], hms[3], 0));
          }
          //Let's hunt for the date.
          else {
            var targetDay
              , operator;
            //Example: `lastThu`
            if (rule[4].substr(0, 4) === "last") {
              // Start at the last day of the month and work backward.
              effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]] + 1, 1, hms[1] - 24, hms[2], hms[3], 0));
              targetDay = SHORT_DAYS[rule[4].substr(4, 3)];
              operator = "<=";
            }
            //Example: `Sun>=15`
            else {
              //Start at the specified date.
              effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4].substr(5), hms[1], hms[2], hms[3], 0));
              targetDay = SHORT_DAYS[rule[4].substr(0, 3)];
              operator = rule[4].substr(3, 2);
            }
            var ourDay = effectiveDate.getUTCDay();
            //Go forwards.
            if (operator === ">=") {
              effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay + ((targetDay < ourDay) ? 7 : 0)));
            }
            //Go backwards.  Looking for the last of a certain day, or operator is "<=" (less likely).
            else {
              effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay - ((targetDay > ourDay) ? 7 : 0)));
            }
          }
          EXACT_DATE_TIME[year][rule] = effectiveDate;
        }


        //If previous rule is given, correct for the fact that the starting time of the current
        // rule may be specified in local time.
        if (prevRule) {
          effectiveDate = convertDateToUTC(effectiveDate, hms[4], prevRule);
        }
        return effectiveDate;
      };

      var findApplicableRules = function (year, ruleset) {
        var applicableRules = [];
        for (var i = 0; ruleset && i < ruleset.length; i++) {
          //Exclude future rules.
          if (ruleset[i][0] <= year &&
              (
                // Date is in a set range.
                ruleset[i][1] >= year ||
                // Date is in an "only" year.
                  (ruleset[i][0] === year && ruleset[i][1] === "only") ||
                //We're in a range from the start year to infinity.
                    ruleset[i][1] === "max"
          )
             ) {
               //It's completely okay to have any number of matches here.
               // Normally we should only see two, but that doesn't preclude other numbers of matches.
               // These matches are applicable to this year.
               applicableRules.push([year, ruleset[i]]);
             }
        }
        return applicableRules;
      };

      var compareDates = function (a, b, prev) {
        var year, rule;
        if (a.constructor !== Date) {
          year = a[0];
          rule = a[1];
          a = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule])
            ? EXACT_DATE_TIME[year][rule]
            : convertRuleToExactDateAndTime(a, prev);
        } else if (prev) {
          a = convertDateToUTC(a, isUTC ? 'u' : 'w', prev);
        }
        if (b.constructor !== Date) {
          year = b[0];
          rule = b[1];
          b = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule]) ? EXACT_DATE_TIME[year][rule]
            : convertRuleToExactDateAndTime(b, prev);
        } else if (prev) {
          b = convertDateToUTC(b, isUTC ? 'u' : 'w', prev);
        }
        a = Number(a);
        b = Number(b);
        return a - b;
      };

      var year = date.getUTCFullYear();
      var applicableRules;

      applicableRules = findApplicableRules(year, _this.rules[ruleset]);
      applicableRules.push(date);
      //While sorting, the time zone in which the rule starting time is specified
      // is ignored. This is ok as long as the timespan between two DST changes is
      // larger than the DST offset, which is probably always true.
      // As the given date may indeed be close to a DST change, it may get sorted
      // to a wrong position (off by one), which is corrected below.
      applicableRules.sort(compareDates);

      //If there are not enough past DST rules...
      if (applicableRules.indexOf(date) < 2) {
        applicableRules = applicableRules.concat(findApplicableRules(year-1, _this.rules[ruleset]));
        applicableRules.sort(compareDates);
      }
      var pinpoint = applicableRules.indexOf(date);
      if (pinpoint > 1 && compareDates(date, applicableRules[pinpoint-1], applicableRules[pinpoint-2][1]) < 0) {
        //The previous rule does not really apply, take the one before that.
        return applicableRules[pinpoint - 2][1];
      } else if (pinpoint > 0 && pinpoint < applicableRules.length - 1 && compareDates(date, applicableRules[pinpoint+1], applicableRules[pinpoint-1][1]) > 0) {

        //The next rule does already apply, take that one.
        return applicableRules[pinpoint + 1][1];
      } else if (pinpoint === 0) {
        //No applicable rule found in this and in previous year.
        return null;
      }
      return applicableRules[pinpoint - 1][1];
    }
function getRule(dt, zone, isUTC) {
      var date = typeof dt === 'number' ? new Date(dt) : dt;
      var ruleset = zone[1];
      var basicOffset = zone[0];

      //Convert a date to UTC. Depending on the 'type' parameter, the date
      // parameter may be:
      //
      // - `u`, `g`, `z`: already UTC (no adjustment).
      //
      // - `s`: standard time (adjust for time zone offset but not for DST)
      //
    // - `w`: wall clock time (adjust for both time zone and DST offset).
      //
      // DST adjustment is done using the rule given as third argument.
      var convertDateToUTC = function (date, type, rule) {
        var offset = 0;

        if (type === 'u' || type === 'g' || type === 'z') { // UTC
          offset = 0;
        } else if (type === 's') { // Standard Time
          offset = basicOffset;
        } else if (type === 'w' || !type) { // Wall Clock Time
          offset = getAdjustedOffset(basicOffset, rule);
        } else {
          throw("unknown type " + type);
        }
        offset *= 60 * 1000; // to millis

        return new Date(date.getTime() + offset);
      };

      //Step 1:  Find applicable rules for this year.
      //
      //Step 2:  Sort the rules by effective date.
      //
      //Step 3:  Check requested date to see if a rule has yet taken effect this year.  If not,
      //
      //Step 4:  Get the rules for the previous year.  If there isn't an applicable rule for last year, then
      // there probably is no current time offset since they seem to explicitly turn off the offset
      // when someone stops observing DST.
      //
      // FIXME if this is not the case and we'll walk all the way back (ugh).
      //
      //Step 5:  Sort the rules by effective date.
      //Step 6:  Apply the most recent rule before the current time.
      var convertRuleToExactDateAndTime = function (yearAndRule, prevRule) {
        var year = yearAndRule[0]
          , rule = yearAndRule[1];
          // Assume that the rule applies to the year of the given date.

        var hms = rule[5];
        var effectiveDate;

        if (!EXACT_DATE_TIME[year])
          EXACT_DATE_TIME[year] = {};

        // Result for given parameters is already stored
        if (EXACT_DATE_TIME[year][rule])
          effectiveDate = EXACT_DATE_TIME[year][rule];
        else {
          //If we have a specific date, use that!
          if (!isNaN(rule[4])) {
            effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4], hms[1], hms[2], hms[3], 0));
          }
          //Let's hunt for the date.
          else {
            var targetDay
              , operator;
            //Example: `lastThu`
            if (rule[4].substr(0, 4) === "last") {
              // Start at the last day of the month and work backward.
              effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]] + 1, 1, hms[1] - 24, hms[2], hms[3], 0));
              targetDay = SHORT_DAYS[rule[4].substr(4, 3)];
              operator = "<=";
            }
            //Example: `Sun>=15`
            else {
              //Start at the specified date.
              effectiveDate = new Date(Date.UTC(year, SHORT_MONTHS[rule[3]], rule[4].substr(5), hms[1], hms[2], hms[3], 0));
              targetDay = SHORT_DAYS[rule[4].substr(0, 3)];
              operator = rule[4].substr(3, 2);
            }
            var ourDay = effectiveDate.getUTCDay();
            //Go forwards.
            if (operator === ">=") {
              effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay + ((targetDay < ourDay) ? 7 : 0)));
            }
            //Go backwards.  Looking for the last of a certain day, or operator is "<=" (less likely).
            else {
              effectiveDate.setUTCDate(effectiveDate.getUTCDate() + (targetDay - ourDay - ((targetDay > ourDay) ? 7 : 0)));
            }
          }
          EXACT_DATE_TIME[year][rule] = effectiveDate;
        }


        //If previous rule is given, correct for the fact that the starting time of the current
        // rule may be specified in local time.
        if (prevRule) {
          effectiveDate = convertDateToUTC(effectiveDate, hms[4], prevRule);
        }
        return effectiveDate;
      };

      var findApplicableRules = function (year, ruleset) {
        var applicableRules = [];
        for (var i = 0; ruleset && i < ruleset.length; i++) {
          //Exclude future rules.
          if (ruleset[i][0] <= year &&
              (
                // Date is in a set range.
                ruleset[i][1] >= year ||
                // Date is in an "only" year.
                  (ruleset[i][0] === year && ruleset[i][1] === "only") ||
                //We're in a range from the start year to infinity.
                    ruleset[i][1] === "max"
          )
             ) {
               //It's completely okay to have any number of matches here.
               // Normally we should only see two, but that doesn't preclude other numbers of matches.
               // These matches are applicable to this year.
               applicableRules.push([year, ruleset[i]]);
             }
        }
        return applicableRules;
      };

      var compareDates = function (a, b, prev) {
        var year, rule;
        if (a.constructor !== Date) {
          year = a[0];
          rule = a[1];
          a = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule])
            ? EXACT_DATE_TIME[year][rule]
            : convertRuleToExactDateAndTime(a, prev);
        } else if (prev) {
          a = convertDateToUTC(a, isUTC ? 'u' : 'w', prev);
        }
        if (b.constructor !== Date) {
          year = b[0];
          rule = b[1];
          b = (!prev && EXACT_DATE_TIME[year] && EXACT_DATE_TIME[year][rule]) ? EXACT_DATE_TIME[year][rule]
            : convertRuleToExactDateAndTime(b, prev);
        } else if (prev) {
          b = convertDateToUTC(b, isUTC ? 'u' : 'w', prev);
        }
        a = Number(a);
        b = Number(b);
        return a - b;
      };

      var year = date.getUTCFullYear();
      var applicableRules;

      applicableRules = findApplicableRules(year, _this.rules[ruleset]);
      applicableRules.push(date);
      //While sorting, the time zone in which the rule starting time is specified
      // is ignored. This is ok as long as the timespan between two DST changes is
      // larger than the DST offset, which is probably always true.
      // As the given date may indeed be close to a DST change, it may get sorted
      // to a wrong position (off by one), which is corrected below.
      applicableRules.sort(compareDates);

      //If there are not enough past DST rules...
      if (applicableRules.indexOf(date) < 2) {
        applicableRules = applicableRules.concat(findApplicableRules(year-1, _this.rules[ruleset]));
        applicableRules.sort(compareDates);
      }
      var pinpoint = applicableRules.indexOf(date);
      if (pinpoint > 1 && compareDates(date, applicableRules[pinpoint-1], applicableRules[pinpoint-2][1]) < 0) {
        //The previous rule does not really apply, take the one before that.
        return applicableRules[pinpoint - 2][1];
      } else if (pinpoint > 0 && pinpoint < applicableRules.length - 1 && compareDates(date, applicableRules[pinpoint+1], applicableRules[pinpoint-1][1]) > 0) {

        //The next rule does already apply, take that one.
        return applicableRules[pinpoint + 1][1];
      } else if (pinpoint === 0) {
        //No applicable rule found in this and in previous year.
        return null;
      }
      return applicableRules[pinpoint - 1][1];
    }
function getRule ( dt , zone , isUTC ) { var date = typeof dt === 'number' ? new Date ( dt ) : dt ; var ruleset = zone [ 1 ] ; var basicOffset = zone [ 0 ] ; //Convert a date to UTC. Depending on the 'type' parameter, the date // parameter may be: // // - `u`, `g`, `z`: already UTC (no adjustment). // // - `s`: standard time (adjust for time zone offset but not for DST) // // - `w`: wall clock time (adjust for both time zone and DST offset). // // DST adjustment is done using the rule given as third argument. var convertDateToUTC = function ( date , type , rule ) { var offset = 0 ; if ( type === 'u' || type === 'g' || type === 'z' ) { // UTC offset = 0 ; } else if ( type === 's' ) { // Standard Time offset = basicOffset ; } else if ( type === 'w' || ! type ) { // Wall Clock Time offset = getAdjustedOffset ( basicOffset , rule ) ; } else { throw ( "unknown type " + type ) ; } offset *= 60 * 1000 ; // to millis return new Date ( date . getTime ( ) + offset ) ; } ; //Step 1:  Find applicable rules for this year. // //Step 2:  Sort the rules by effective date. // //Step 3:  Check requested date to see if a rule has yet taken effect this year.  If not, // //Step 4:  Get the rules for the previous year.  If there isn't an applicable rule for last year, then // there probably is no current time offset since they seem to explicitly turn off the offset // when someone stops observing DST. // // FIXME if this is not the case and we'll walk all the way back (ugh). // //Step 5:  Sort the rules by effective date. //Step 6:  Apply the most recent rule before the current time. var convertRuleToExactDateAndTime = function ( yearAndRule , prevRule ) { var year = yearAndRule [ 0 ] , rule = yearAndRule [ 1 ] ; // Assume that the rule applies to the year of the given date. var hms = rule [ 5 ] ; var effectiveDate ; if ( ! EXACT_DATE_TIME [ year ] ) EXACT_DATE_TIME [ year ] = { } ; // Result for given parameters is already stored if ( EXACT_DATE_TIME [ year ] [ rule ] ) effectiveDate = EXACT_DATE_TIME [ year ] [ rule ] ; else { //If we have a specific date, use that! if ( ! isNaN ( rule [ 4 ] ) ) { effectiveDate = new Date ( Date . UTC ( year , SHORT_MONTHS [ rule [ 3 ] ] , rule [ 4 ] , hms [ 1 ] , hms [ 2 ] , hms [ 3 ] , 0 ) ) ; } //Let's hunt for the date. else { var targetDay , operator ; //Example: `lastThu` if ( rule [ 4 ] . substr ( 0 , 4 ) === "last" ) { // Start at the last day of the month and work backward. effectiveDate = new Date ( Date . UTC ( year , SHORT_MONTHS [ rule [ 3 ] ] + 1 , 1 , hms [ 1 ] - 24 , hms [ 2 ] , hms [ 3 ] , 0 ) ) ; targetDay = SHORT_DAYS [ rule [ 4 ] . substr ( 4 , 3 ) ] ; operator = "<=" ; } //Example: `Sun>=15` else { //Start at the specified date. effectiveDate = new Date ( Date . UTC ( year , SHORT_MONTHS [ rule [ 3 ] ] , rule [ 4 ] . substr ( 5 ) , hms [ 1 ] , hms [ 2 ] , hms [ 3 ] , 0 ) ) ; targetDay = SHORT_DAYS [ rule [ 4 ] . substr ( 0 , 3 ) ] ; operator = rule [ 4 ] . substr ( 3 , 2 ) ; } var ourDay = effectiveDate . getUTCDay ( ) ; //Go forwards. if ( operator === ">=" ) { effectiveDate . setUTCDate ( effectiveDate . getUTCDate ( ) + ( targetDay - ourDay + ( ( targetDay < ourDay ) ? 7 : 0 ) ) ) ; } //Go backwards.  Looking for the last of a certain day, or operator is "<=" (less likely). else { effectiveDate . setUTCDate ( effectiveDate . getUTCDate ( ) + ( targetDay - ourDay - ( ( targetDay > ourDay ) ? 7 : 0 ) ) ) ; } } EXACT_DATE_TIME [ year ] [ rule ] = effectiveDate ; } //If previous rule is given, correct for the fact that the starting time of the current // rule may be specified in local time. if ( prevRule ) { effectiveDate = convertDateToUTC ( effectiveDate , hms [ 4 ] , prevRule ) ; } return effectiveDate ; } ; var findApplicableRules = function ( year , ruleset ) { var applicableRules = [ ] ; for ( var i = 0 ; ruleset && i < ruleset . length ; i ++ ) { //Exclude future rules. if ( ruleset [ i ] [ 0 ] <= year && ( // Date is in a set range. ruleset [ i ] [ 1 ] >= year || // Date is in an "only" year. ( ruleset [ i ] [ 0 ] === year && ruleset [ i ] [ 1 ] === "only" ) || //We're in a range from the start year to infinity. ruleset [ i ] [ 1 ] === "max" ) ) { //It's completely okay to have any number of matches here. // Normally we should only see two, but that doesn't preclude other numbers of matches. // These matches are applicable to this year. applicableRules . push ( [ year , ruleset [ i ] ] ) ; } } return applicableRules ; } ; var compareDates = function ( a , b , prev ) { var year , rule ; if ( a . constructor !== Date ) { year = a [ 0 ] ; rule = a [ 1 ] ; a = ( ! prev && EXACT_DATE_TIME [ year ] && EXACT_DATE_TIME [ year ] [ rule ] ) ? EXACT_DATE_TIME [ year ] [ rule ] : convertRuleToExactDateAndTime ( a , prev ) ; } else if ( prev ) { a = convertDateToUTC ( a , isUTC ? 'u' : 'w' , prev ) ; } if ( b . constructor !== Date ) { year = b [ 0 ] ; rule = b [ 1 ] ; b = ( ! prev && EXACT_DATE_TIME [ year ] && EXACT_DATE_TIME [ year ] [ rule ] ) ? EXACT_DATE_TIME [ year ] [ rule ] : convertRuleToExactDateAndTime ( b , prev ) ; } else if ( prev ) { b = convertDateToUTC ( b , isUTC ? 'u' : 'w' , prev ) ; } a = Number ( a ) ; b = Number ( b ) ; return a - b ; } ; var year = date . getUTCFullYear ( ) ; var applicableRules ; applicableRules = findApplicableRules ( year , _this . rules [ ruleset ] ) ; applicableRules . push ( date ) ; //While sorting, the time zone in which the rule starting time is specified // is ignored. This is ok as long as the timespan between two DST changes is // larger than the DST offset, which is probably always true. // As the given date may indeed be close to a DST change, it may get sorted // to a wrong position (off by one), which is corrected below. applicableRules . sort ( compareDates ) ; //If there are not enough past DST rules... if ( applicableRules . indexOf ( date ) < 2 ) { applicableRules = applicableRules . concat ( findApplicableRules ( year - 1 , _this . rules [ ruleset ] ) ) ; applicableRules . sort ( compareDates ) ; } var pinpoint = applicableRules . indexOf ( date ) ; if ( pinpoint > 1 && compareDates ( date , applicableRules [ pinpoint - 1 ] , applicableRules [ pinpoint - 2 ] [ 1 ] ) < 0 ) { //The previous rule does not really apply, take the one before that. return applicableRules [ pinpoint - 2 ] [ 1 ] ; } else if ( pinpoint > 0 && pinpoint < applicableRules . length - 1 && compareDates ( date , applicableRules [ pinpoint + 1 ] , applicableRules [ pinpoint - 1 ] [ 1 ] ) > 0 ) { //The next rule does already apply, take that one. return applicableRules [ pinpoint + 1 ] [ 1 ] ; } else if ( pinpoint === 0 ) { //No applicable rule found in this and in previous year. return null ; } return applicableRules [ pinpoint - 1 ] [ 1 ] ; }
if isUTC is true, date is given in UTC, otherwise it's given in local time (ie. date.getUTC*() returns local time components)
if isUTC is true date is given in UTC otherwise it s given in local time ( ie . date . getUTC * () returns local time components )
Returns the rule for the given date and time zone.