diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js
index 1692061a0146..3de490f8ba5e 100644
--- a/src/ng/directive/input.js
+++ b/src/ng/directive/input.js
@@ -14,10 +14,10 @@ var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
-var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d))?$/;
+var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
-var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d))?$/;
+var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
var $ngModelMinErr = new minErr('ngModel');
@@ -281,8 +281,14 @@ var inputType = {
*/
'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
- createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss']),
- 'yyyy-MM-ddTHH:mm:ss'),
+ createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
+ function(value, step) {
+ if (value.getMilliseconds() || (step && parseFloat(step) < 1)) {
+ return 'yyyy-MM-ddTHH:mm:ss.sss';
+ } else {
+ return 'yyyy-MM-ddTHH:mm:ss';
+ }
+ }),
/**
* @ngdoc input
@@ -370,8 +376,14 @@ var inputType = {
*/
'time': createDateInputType('time', TIME_REGEXP,
- createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss']),
- 'HH:mm:ss'),
+ createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
+ function(value, step) {
+ if (value.getMilliseconds() || (step && parseFloat(step) < 1)) {
+ return 'HH:mm:ss.sss';
+ } else {
+ return 'HH:mm:ss';
+ }
+ }),
/**
* @ngdoc input
@@ -1067,7 +1079,7 @@ function createDateParser(regexp, mapping) {
HH: date.getHours(),
mm: date.getMinutes(),
ss: date.getSeconds(),
- sss: date.getMilliseconds()
+ sss: date.getMilliseconds() / 1000
};
} else {
map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
@@ -1078,7 +1090,7 @@ function createDateParser(regexp, mapping) {
map[mapping[index]] = +part;
}
});
- return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss || 0);
+ return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
}
}
@@ -1110,9 +1122,10 @@ function createDateInputType(type, regexp, parseDate, format) {
return undefined;
});
+ var invokeFormat = isFunction(format);
ctrl.$formatters.push(function(value) {
if (isDate(value)) {
- return $filter('date')(value, format, timezone);
+ return $filter('date')(value, invokeFormat ? format(value, attr.step) : format, timezone);
}
return '';
});
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js
index a50c1640cfc5..2f8c8794fba1 100644
--- a/test/ng/directive/inputSpec.js
+++ b/test/ng/directive/inputSpec.js
@@ -2590,13 +2590,33 @@ describe('input', function() {
});
it('should set the view if the model if a valid Date object.', function(){
- compileInput('');
+ compileInput('');
scope.$apply(function (){
- scope.tenSecondsToNextYear = new Date(2013, 11, 31, 23, 59, 0);
+ scope.oneSecondToNextYear = new Date(2013, 11, 31, 23, 59, 59);
});
- expect(inputElm.val()).toBe('2013-12-31T23:59:00');
+ expect(inputElm.val()).toBe('2013-12-31T23:59:59');
+ });
+
+ it('should set the view with milliseconds', function(){
+ compileInput('');
+
+ scope.$apply(function (){
+ scope.halfSecondToNextYear = new Date(2013, 11, 31, 23, 59, 59, 500);
+ });
+
+ expect(inputElm.val()).toBe('2013-12-31T23:59:59.500');
+ });
+
+ it('should set the view with milliseconds if step < 1', function(){
+ compileInput('');
+
+ scope.$apply(function (){
+ scope.halfSecondToNextYear = new Date(2013, 11, 31, 23, 59, 59);
+ });
+
+ expect(inputElm.val()).toBe('2013-12-31T23:59:59.000');
});
it('should set the model undefined if the view is invalid', function (){
@@ -2666,6 +2686,20 @@ describe('input', function() {
expect(inputElm.val()).toBe('2001-01-01T01:02:00');
});
+ it('should allow to specify the milliseconds', function() {
+ compileInput('');
+
+ changeInputValueTo('2000-01-01T01:02:03.500');
+ expect(+scope.value).toBe(+new Date(2000, 0, 1, 1, 2, 3, 500));
+ });
+
+ it('should allow to specify single digit milliseconds', function() {
+ compileInput('');
+
+ changeInputValueTo('2000-01-01T01:02:03.4');
+ expect(+scope.value).toBe(+new Date(2000, 0, 1, 1, 2, 3, 400));
+ });
+
it('should allow to specify the seconds', function() {
compileInput('');
@@ -2860,6 +2894,26 @@ describe('input', function() {
expect(inputElm.val()).toBe('15:41:00');
});
+ it('should set the view with milliseconds', function(){
+ compileInput('');
+
+ scope.$apply(function (){
+ scope.threeFortyOnePm = new Date(1970, 0, 1, 15, 41, 0, 500);
+ });
+
+ expect(inputElm.val()).toBe('15:41:00.500');
+ });
+
+ it('should set the view with milliseconds if step < 1', function(){
+ compileInput('');
+
+ scope.$apply(function (){
+ scope.threeFortyOnePm = new Date(1970, 0, 1, 15, 41, 0);
+ });
+
+ expect(inputElm.val()).toBe('15:41:00.000');
+ });
+
it('should set the model undefined if the view is invalid', function (){
compileInput('');
@@ -2927,6 +2981,20 @@ describe('input', function() {
expect(inputElm.val()).toBe('23:02:00');
});
+ it('should allow to specify the milliseconds', function() {
+ compileInput('');
+
+ changeInputValueTo('01:02:03.500');
+ expect(+scope.value).toBe(+new Date(1970, 0, 1, 1, 2, 3, 500));
+ });
+
+ it('should allow to specify single digit milliseconds', function() {
+ compileInput('');
+
+ changeInputValueTo('01:02:03.4');
+ expect(+scope.value).toBe(+new Date(1970, 0, 1, 1, 2, 3, 400));
+ });
+
it('should allow to specify the seconds', function() {
compileInput('');
@@ -3192,13 +3260,13 @@ describe('input', function() {
scope.val = new Date(2013, 1, 2, 3, 4, 5, 6);
});
- expect(timeElm.val()).toBe('03:04:05');
+ expect(timeElm.val()).toBe('03:04:05.006');
expect(monthElm.val()).toBe('2013-02');
expect(weekElm.val()).toBe('2013-W05');
changeGivenInputTo(monthElm, '2012-02');
expect(monthElm.val()).toBe('2012-02');
- expect(timeElm.val()).toBe('03:04:05');
+ expect(timeElm.val()).toBe('03:04:05.006');
expect(weekElm.val()).toBe('2012-W05');
changeGivenInputTo(timeElm, '04:05:06');
@@ -3211,7 +3279,7 @@ describe('input', function() {
expect(timeElm.val()).toBe('04:05:06');
expect(weekElm.val()).toBe('2014-W01');
- expect(+scope.val).toBe(+new Date(2014, 0, 2, 4, 5, 6, 6));
+ expect(+scope.val).toBe(+new Date(2014, 0, 2, 4, 5, 6, 0));
function changeGivenInputTo(inputElm, value) {
inputElm.val(value);