function createDateInputType(type, regexp, parseDate, format) {
  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
    badInputChecker(scope, element, attr, ctrl, type);
    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);

    var isTimeType = type === 'time' || type === 'datetimelocal';
    var previousDate;
    var previousTimezone;

    ctrl.$parsers.push(function(value) {
      if (ctrl.$isEmpty(value)) return null;

      if (regexp.test(value)) {
        // Note: We cannot read ctrl.$modelValue, as there might be a different
        // parser/formatter in the processing chain so that the model
        // contains some different data format!
        return parseDateAndConvertTimeZoneToLocal(value, previousDate);
      }
      ctrl.$$parserName = type;
      return undefined;
    });

    ctrl.$formatters.push(function(value) {
      if (value && !isDate(value)) {
        throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
      }
      if (isValidDate(value)) {
        previousDate = value;
        var timezone = ctrl.$options.getOption('timezone');

        if (timezone) {
          previousTimezone = timezone;
          previousDate = convertTimezoneToLocal(previousDate, timezone, true);
        }

        return formatter(value, timezone);
      } else {
        previousDate = null;
        previousTimezone = null;
        return '';
      }
    });

    if (isDefined(attr.min) || attr.ngMin) {
      var minVal;
      ctrl.$validators.min = function(value) {
        return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
      };
      attr.$observe('min', function(val) {
        minVal = parseObservedDateValue(val);
        ctrl.$validate();
      });
    }

    if (isDefined(attr.max) || attr.ngMax) {
      var maxVal;
      ctrl.$validators.max = function(value) {
        return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
      };
      attr.$observe('max', function(val) {
        maxVal = parseObservedDateValue(val);
        ctrl.$validate();
      });
    }

    function isValidDate(value) {
      // Invalid Date: getTime() returns NaN
      return value && !(value.getTime && value.getTime() !== value.getTime());
    }

    function parseObservedDateValue(val) {
      return isDefined(val) && !isDate(val) ? parseDateAndConvertTimeZoneToLocal(val) || undefined : val;
    }

    function parseDateAndConvertTimeZoneToLocal(value, previousDate) {
      var timezone = ctrl.$options.getOption('timezone');

      if (previousTimezone && previousTimezone !== timezone) {
        // If the timezone has changed, adjust the previousDate to the default timezone
        // so that the new date is converted with the correct timezone offset
        previousDate = addDateMinutes(previousDate, timezoneToOffset(previousTimezone));
      }

      var parsedDate = parseDate(value, previousDate);

      if (!isNaN(parsedDate) && timezone) {
        parsedDate = convertTimezoneToLocal(parsedDate, timezone);
      }
      return parsedDate;
    }

    function formatter(value, timezone) {
      var targetFormat = format;

      if (isTimeType && isString(ctrl.$options.getOption('timeSecondsFormat'))) {
        targetFormat = format
          .replace('ss.sss', ctrl.$options.getOption('timeSecondsFormat'))
          .replace(/:$/, '');
      }

      var formatted =  $filter('date')(value, targetFormat, timezone);

      if (isTimeType && ctrl.$options.getOption('timeStripZeroSeconds')) {
        formatted = formatted.replace(/(?::00)?(?:\.000)?$/, '');
      }

      return formatted;
    }
  };
}
@ngdoc directive
@name ngNonBindable
@restrict AC
@priority 1000
@element ANY

@description
The `ngNonBindable` directive tells AngularJS not to compile or bind the contents of the current
DOM element, including directives on the element itself that have a lower priority than
`ngNonBindable`. This is useful if the element contains what appears to be AngularJS directives
and bindings but which should be ignored by AngularJS. This could be the case if you have a site
that displays snippets of code, for instance.

@example
In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
but the one wrapped in `ngNonBindable` is left alone.

  <example name="ng-non-bindable">
    <file name="index.html">
      <div>Normal: {{1 + 2}}</div>
      <div ng-non-bindable>Ignored: {{1 + 2}}</div>
    </file>
    <file name="protractor.js" type="protractor">
     it('should check ng-non-bindable', function() {
       expect(element(by.binding('1 + 2')).getText()).toContain('3');
       expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
     });
    </file>
  </example>