diff --git a/dist/ng-quick-date.js b/dist/ng-quick-date.js
index 610d500..7c18551 100644
--- a/dist/ng-quick-date.js
+++ b/dist/ng-quick-date.js
@@ -20,6 +20,7 @@
defaultTime: null,
dayAbbreviations: ["Su", "M", "Tu", "W", "Th", "F", "Sa"],
dateFilter: null,
+ timezone: null,
parseDateFunction: function(str) {
var seconds;
seconds = Date.parse(str);
@@ -61,7 +62,8 @@
},
replace: true,
link: function(scope, element, attrs, ngModelCtrl) {
- var dateToString, datepickerClicked, datesAreEqual, datesAreEqualToMinute, getDaysInMonth, initialize, parseDateString, refreshView, setCalendarDate, setConfigOptions, setInputFieldValues, setupCalendarView, stringToDate;
+ var combineDateAndTime, dateToString, datepickerClicked, datesAreEqual, datesAreEqualToMinute, emptyTime, getDaysInMonth, initialize, parseDateString, refreshView, setCalendarDate, setConfigOptions, setInputFieldValues, setupCalendarView, stringToDate;
+ emptyTime = '00:00:00';
initialize = function() {
setConfigOptions();
scope.toggleCalendar(false);
@@ -87,6 +89,10 @@
scope[key] = ngQuickDateDefaults[key];
}
}
+ if (scope.timezone === "UTC") {
+ scope.dateFormat = "yyyy-MM-dd";
+ scope.timeFormat = "HH:mm:ss";
+ }
if (!scope.labelFormat) {
scope.labelFormat = scope.dateFormat;
if (!scope.disableTimepicker) {
@@ -113,13 +119,13 @@
date = ngModelCtrl.$modelValue ? parseDateString(ngModelCtrl.$modelValue) : null;
setupCalendarView();
setInputFieldValues(date);
- scope.mainButtonStr = date ? $filter('date')(date, scope.labelFormat) : scope.placeholder;
+ scope.mainButtonStr = date ? $filter('date')(date, scope.labelFormat, scope.timezone) : scope.placeholder;
return scope.invalid = ngModelCtrl.$invalid;
};
setInputFieldValues = function(val) {
if (val != null) {
- scope.inputDate = $filter('date')(val, scope.dateFormat);
- return scope.inputTime = $filter('date')(val, scope.timeFormat);
+ scope.inputDate = $filter('date')(val, scope.dateFormat, scope.timezone);
+ return scope.inputTime = $filter('date')(val, scope.timeFormat, scope.timezone);
} else {
scope.inputDate = null;
return scope.inputTime = null;
@@ -193,7 +199,7 @@
}
});
dateToString = function(date, format) {
- return $filter('date')(date, format);
+ return $filter('date')(date, format, scope.timezone);
};
stringToDate = function(date) {
if (typeof date === 'string') {
@@ -203,6 +209,13 @@
}
};
parseDateString = ngQuickDateDefaults.parseDateFunction;
+ combineDateAndTime = function(date, time) {
+ if (scope.timezone === "UTC") {
+ return "" + date + "T" + time + "Z";
+ } else {
+ return "" + date + " " + time;
+ }
+ };
datesAreEqual = function(d1, d2, compareTimes) {
if (compareTimes == null) {
compareTimes = false;
@@ -270,13 +283,13 @@
closeCalendar = false;
}
try {
- tmpDate = parseDateString(scope.inputDate);
+ tmpDate = parseDateString(combineDateAndTime(scope.inputDate, emptyTime));
if (!tmpDate) {
throw 'Invalid Date';
}
if (!scope.disableTimepicker && scope.inputTime && scope.inputTime.length && tmpDate) {
- tmpTime = scope.disableTimepicker ? '00:00:00' : scope.inputTime;
- tmpDateAndTime = parseDateString("" + scope.inputDate + " " + tmpTime);
+ tmpTime = scope.disableTimepicker ? emptyTime : scope.inputTime;
+ tmpDateAndTime = parseDateString(combineDateAndTime(scope.inputDate, tmpTime));
if (!tmpDateAndTime) {
throw 'Invalid Time';
}
diff --git a/dist/ng-quick-date.min.js b/dist/ng-quick-date.min.js
index 42eeb01..b4063f4 100644
--- a/dist/ng-quick-date.min.js
+++ b/dist/ng-quick-date.min.js
@@ -1 +1 @@
-(function(){var a;a=angular.module("ngQuickDate",[]),a.provider("ngQuickDateDefaults",function(){return{options:{dateFormat:"M/d/yyyy",timeFormat:"h:mm a",labelFormat:null,placeholder:"Click to Set Date",hoverText:null,buttonIconHtml:null,closeButtonHtml:"×",nextLinkHtml:"Next →",prevLinkHtml:"← Prev",disableTimepicker:!1,disableClearButton:!1,defaultTime:null,dayAbbreviations:["Su","M","Tu","W","Th","F","Sa"],dateFilter:null,parseDateFunction:function(a){var b;return b=Date.parse(a),isNaN(b)?null:new Date(b)}},$get:function(){return this.options},set:function(a,b){var c,d,e;if("object"==typeof a){e=[];for(c in a)d=a[c],e.push(this.options[c]=d);return e}return this.options[a]=b}}}),a.directive("quickDatepicker",["ngQuickDateDefaults","$filter","$sce",function(a,b,c){return{restrict:"E",require:"?ngModel",scope:{dateFilter:"=?",onChange:"&",required:"@"},replace:!0,link:function(d,e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t;return m=function(){return q(),d.toggleCalendar(!1),d.weeks=[],d.inputDate=null,d.inputTime=null,d.invalid=!0,"string"==typeof f.initValue&&g.$setViewValue(f.initValue),p(),o()},q=function(){var b,e;for(b in a)e=a[b],b.match(/[Hh]tml/)?d[b]=c.trustAsHtml(a[b]||""):!d[b]&&f[b]?d[b]=f[b]:d[b]||(d[b]=a[b]);return d.labelFormat||(d.labelFormat=d.dateFormat,d.disableTimepicker||(d.labelFormat+=" "+d.timeFormat)),f.iconClass&&f.iconClass.length?d.buttonIconHtml=c.trustAsHtml(""):void 0},i=!1,window.document.addEventListener("click",function(){return d.calendarShown&&!i&&(d.toggleCalendar(!1),d.$apply()),i=!1}),angular.element(e[0])[0].addEventListener("click",function(){return i=!0}),o=function(){var a;return a=g.$modelValue?n(g.$modelValue):null,s(),r(a),d.mainButtonStr=a?b("date")(a,d.labelFormat):d.placeholder,d.invalid=g.$invalid},r=function(a){return null!=a?(d.inputDate=b("date")(a,d.dateFormat),d.inputTime=b("date")(a,d.timeFormat)):(d.inputDate=null,d.inputTime=null)},p=function(a){var b;return null==a&&(a=null),b=null!=a?new Date(a):new Date,"Invalid Date"===b.toString()&&(b=new Date),b.setDate(1),d.calendarDate=new Date(b)},s=function(){var a,b,c,e,f,h,i,k,m,n,o,p,q,r;for(h=d.calendarDate.getDay(),e=l(d.calendarDate.getFullYear(),d.calendarDate.getMonth()),f=Math.ceil((h+e)/7),o=[],a=new Date(d.calendarDate),a.setDate(a.getDate()+-1*h),i=p=0,r=f-1;r>=0?r>=p:p>=r;i=r>=0?++p:--p)for(o.push([]),c=q=0;6>=q;c=++q)b=new Date(a),d.defaultTime&&(m=d.defaultTime.split(":"),b.setHours(m[0]||0),b.setMinutes(m[1]||0),b.setSeconds(m[2]||0)),k=g.$modelValue&&b&&j(b,g.$modelValue),n=j(b,new Date),o[i].push({date:b,selected:k,disabled:"function"==typeof d.dateFilter?!d.dateFilter(b):!1,other:b.getMonth()!==d.calendarDate.getMonth(),today:n}),a.setDate(a.getDate()+1);return d.weeks=o},g.$parsers.push(function(a){return d.required&&null==a?(g.$setValidity("required",!1),null):angular.isDate(a)?(g.$setValidity("required",!0),a):angular.isString(a)?(g.$setValidity("required",!0),d.parseDateFunction(a)):null}),g.$formatters.push(function(a){return angular.isDate(a)?a:angular.isString(a)?d.parseDateFunction(a):void 0}),h=function(a,c){return b("date")(a,c)},t=function(a){return"string"==typeof a?n(a):a},n=a.parseDateFunction,j=function(a,b,c){return null==c&&(c=!1),c?a-b===0:(a=t(a),b=t(b),a&&b&&a.getYear()===b.getYear()&&a.getMonth()===b.getMonth()&&a.getDate()===b.getDate())},k=function(a,b){return a&&b?parseInt(a.getTime()/6e4)===parseInt(b.getTime()/6e4):!1},l=function(a,b){return[31,a%4===0&&a%100!==0||a%400===0?29:28,31,30,31,30,31,31,30,31,30,31][b]},g.$render=function(){return p(g.$viewValue),o()},g.$viewChangeListeners.unshift(function(){return p(g.$viewValue),o(),d.onChange?d.onChange():void 0}),d.$watch("calendarShown",function(a){var b;return a?(b=angular.element(e[0].querySelector(".quickdate-date-input"))[0],b.select()):void 0}),d.toggleCalendar=function(a){return d.calendarShown=isFinite(a)?a:!d.calendarShown},d.selectDate=function(a,b){var c;return null==b&&(b=!0),c=!g.$viewValue&&a||g.$viewValue&&!a||a&&g.$viewValue&&a.getTime()!==g.$viewValue.getTime(),"function"!=typeof d.dateFilter||d.dateFilter(a)?(g.$setViewValue(a),b&&d.toggleCalendar(!1),!0):!1},d.selectDateFromInput=function(a){var b,c,e,f;null==a&&(a=!1);try{if(c=n(d.inputDate),!c)throw"Invalid Date";if(!d.disableTimepicker&&d.inputTime&&d.inputTime.length&&c){if(f=d.disableTimepicker?"00:00:00":d.inputTime,e=n(""+d.inputDate+" "+f),!e)throw"Invalid Time";c=e}if(!k(g.$viewValue,c)&&!d.selectDate(c,!1))throw"Invalid Date";return a&&d.toggleCalendar(!1),d.inputDateErr=!1,d.inputTimeErr=!1}catch(h){if(b=h,"Invalid Date"===b)return d.inputDateErr=!0;if("Invalid Time"===b)return d.inputTimeErr=!0}},d.onDateInputTab=function(){return d.disableTimepicker&&d.toggleCalendar(!1),!0},d.onTimeInputTab=function(){return d.toggleCalendar(!1),!0},d.nextMonth=function(){return p(new Date(new Date(d.calendarDate).setMonth(d.calendarDate.getMonth()+1))),o()},d.prevMonth=function(){return p(new Date(new Date(d.calendarDate).setMonth(d.calendarDate.getMonth()-1))),o()},d.clear=function(){return d.selectDate(null,!0)},m()},template:"
"}}]),a.directive("ngEnter",function(){return function(a,b,c){return b.bind("keydown keypress",function(b){return 13===b.which?(a.$apply(c.ngEnter),b.preventDefault()):void 0})}}),a.directive("onTab",function(){return{restrict:"A",link:function(a,b,c){return b.bind("keydown keypress",function(b){return 9!==b.which||b.shiftKey?void 0:a.$apply(c.onTab)})}}})}).call(this);
\ No newline at end of file
+(function(){var a;a=angular.module("ngQuickDate",[]),a.provider("ngQuickDateDefaults",function(){return{options:{dateFormat:"M/d/yyyy",timeFormat:"h:mm a",labelFormat:null,placeholder:"Click to Set Date",hoverText:null,buttonIconHtml:null,closeButtonHtml:"×",nextLinkHtml:"Next →",prevLinkHtml:"← Prev",disableTimepicker:!1,disableClearButton:!1,defaultTime:null,dayAbbreviations:["Su","M","Tu","W","Th","F","Sa"],dateFilter:null,timezone:null,parseDateFunction:function(a){var b;return b=Date.parse(a),isNaN(b)?null:new Date(b)}},$get:function(){return this.options},set:function(a,b){var c,d,e;if("object"==typeof a){e=[];for(c in a)d=a[c],e.push(this.options[c]=d);return e}return this.options[a]=b}}}),a.directive("quickDatepicker",["ngQuickDateDefaults","$filter","$sce",function(a,b,c){return{restrict:"E",require:"?ngModel",scope:{dateFilter:"=?",onChange:"&",required:"@"},replace:!0,link:function(d,e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v;return m="00:00:00",o=function(){return s(),d.toggleCalendar(!1),d.weeks=[],d.inputDate=null,d.inputTime=null,d.invalid=!0,"string"==typeof f.initValue&&g.$setViewValue(f.initValue),r(),q()},s=function(){var b,e;for(b in a)e=a[b],b.match(/[Hh]tml/)?d[b]=c.trustAsHtml(a[b]||""):!d[b]&&f[b]?d[b]=f[b]:d[b]||(d[b]=a[b]);return"UTC"===d.timezone&&(d.dateFormat="yyyy-MM-dd",d.timeFormat="HH:mm:ss"),d.labelFormat||(d.labelFormat=d.dateFormat,d.disableTimepicker||(d.labelFormat+=" "+d.timeFormat)),f.iconClass&&f.iconClass.length?d.buttonIconHtml=c.trustAsHtml(""):void 0},j=!1,window.document.addEventListener("click",function(){return d.calendarShown&&!j&&(d.toggleCalendar(!1),d.$apply()),j=!1}),angular.element(e[0])[0].addEventListener("click",function(){return j=!0}),q=function(){var a;return a=g.$modelValue?p(g.$modelValue):null,u(),t(a),d.mainButtonStr=a?b("date")(a,d.labelFormat,d.timezone):d.placeholder,d.invalid=g.$invalid},t=function(a){return null!=a?(d.inputDate=b("date")(a,d.dateFormat,d.timezone),d.inputTime=b("date")(a,d.timeFormat,d.timezone)):(d.inputDate=null,d.inputTime=null)},r=function(a){var b;return null==a&&(a=null),b=null!=a?new Date(a):new Date,"Invalid Date"===b.toString()&&(b=new Date),b.setDate(1),d.calendarDate=new Date(b)},u=function(){var a,b,c,e,f,h,i,j,l,m,o,p,q,r;for(h=d.calendarDate.getDay(),e=n(d.calendarDate.getFullYear(),d.calendarDate.getMonth()),f=Math.ceil((h+e)/7),o=[],a=new Date(d.calendarDate),a.setDate(a.getDate()+-1*h),i=p=0,r=f-1;r>=0?r>=p:p>=r;i=r>=0?++p:--p)for(o.push([]),c=q=0;6>=q;c=++q)b=new Date(a),d.defaultTime&&(l=d.defaultTime.split(":"),b.setHours(l[0]||0),b.setMinutes(l[1]||0),b.setSeconds(l[2]||0)),j=g.$modelValue&&b&&k(b,g.$modelValue),m=k(b,new Date),o[i].push({date:b,selected:j,disabled:"function"==typeof d.dateFilter?!d.dateFilter(b):!1,other:b.getMonth()!==d.calendarDate.getMonth(),today:m}),a.setDate(a.getDate()+1);return d.weeks=o},g.$parsers.push(function(a){return d.required&&null==a?(g.$setValidity("required",!1),null):angular.isDate(a)?(g.$setValidity("required",!0),a):angular.isString(a)?(g.$setValidity("required",!0),d.parseDateFunction(a)):null}),g.$formatters.push(function(a){return angular.isDate(a)?a:angular.isString(a)?d.parseDateFunction(a):void 0}),i=function(a,c){return b("date")(a,c,d.timezone)},v=function(a){return"string"==typeof a?p(a):a},p=a.parseDateFunction,h=function(a,b){return"UTC"===d.timezone?""+a+"T"+b+"Z":""+a+" "+b},k=function(a,b,c){return null==c&&(c=!1),c?a-b===0:(a=v(a),b=v(b),a&&b&&a.getYear()===b.getYear()&&a.getMonth()===b.getMonth()&&a.getDate()===b.getDate())},l=function(a,b){return a&&b?parseInt(a.getTime()/6e4)===parseInt(b.getTime()/6e4):!1},n=function(a,b){return[31,a%4===0&&a%100!==0||a%400===0?29:28,31,30,31,30,31,31,30,31,30,31][b]},g.$render=function(){return r(g.$viewValue),q()},g.$viewChangeListeners.unshift(function(){return r(g.$viewValue),q(),d.onChange?d.onChange():void 0}),d.$watch("calendarShown",function(a){var b;return a?(b=angular.element(e[0].querySelector(".quickdate-date-input"))[0],b.select()):void 0}),d.toggleCalendar=function(a){return d.calendarShown=isFinite(a)?a:!d.calendarShown},d.selectDate=function(a,b){var c;return null==b&&(b=!0),c=!g.$viewValue&&a||g.$viewValue&&!a||a&&g.$viewValue&&a.getTime()!==g.$viewValue.getTime(),"function"!=typeof d.dateFilter||d.dateFilter(a)?(g.$setViewValue(a),b&&d.toggleCalendar(!1),!0):!1},d.selectDateFromInput=function(a){var b,c,e,f;null==a&&(a=!1);try{if(c=p(h(d.inputDate,m)),!c)throw"Invalid Date";if(!d.disableTimepicker&&d.inputTime&&d.inputTime.length&&c){if(f=d.disableTimepicker?m:d.inputTime,e=p(h(d.inputDate,f)),!e)throw"Invalid Time";c=e}if(!l(g.$viewValue,c)&&!d.selectDate(c,!1))throw"Invalid Date";return a&&d.toggleCalendar(!1),d.inputDateErr=!1,d.inputTimeErr=!1}catch(i){if(b=i,"Invalid Date"===b)return d.inputDateErr=!0;if("Invalid Time"===b)return d.inputTimeErr=!0}},d.onDateInputTab=function(){return d.disableTimepicker&&d.toggleCalendar(!1),!0},d.onTimeInputTab=function(){return d.toggleCalendar(!1),!0},d.nextMonth=function(){return r(new Date(new Date(d.calendarDate).setMonth(d.calendarDate.getMonth()+1))),q()},d.prevMonth=function(){return r(new Date(new Date(d.calendarDate).setMonth(d.calendarDate.getMonth()-1))),q()},d.clear=function(){return d.selectDate(null,!0)},o()},template:""}}]),a.directive("ngEnter",function(){return function(a,b,c){return b.bind("keydown keypress",function(b){return 13===b.which?(a.$apply(c.ngEnter),b.preventDefault()):void 0})}}),a.directive("onTab",function(){return{restrict:"A",link:function(a,b,c){return b.bind("keydown keypress",function(b){return 9!==b.which||b.shiftKey?void 0:a.$apply(c.onTab)})}}})}).call(this);
\ No newline at end of file
diff --git a/src/ng-quick-date.coffee b/src/ng-quick-date.coffee
index 239bb35..d542126 100644
--- a/src/ng-quick-date.coffee
+++ b/src/ng-quick-date.coffee
@@ -27,6 +27,7 @@ app.provider "ngQuickDateDefaults", ->
defaultTime: null
dayAbbreviations: ["Su", "M", "Tu", "W", "Th", "F", "Sa"],
dateFilter: null
+ timezone: null
parseDateFunction: (str) ->
seconds = Date.parse(str)
if isNaN(seconds)
@@ -55,6 +56,8 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
replace: true
link: (scope, element, attrs, ngModelCtrl) ->
+ emptyTime = '00:00:00'
+
# INITIALIZE VARIABLES AND CONFIGURATION
# ================================
initialize = ->
@@ -78,10 +81,19 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
scope[key] = attrs[key]
else if !scope[key]
scope[key] = ngQuickDateDefaults[key]
+
+ # Use the ISO format if timezone is UTC.
+ # This is necessary to ensure the date string is parsed in correct timezone.
+ if scope.timezone is "UTC"
+ scope.dateFormat = "yyyy-MM-dd"
+ scope.timeFormat = "HH:mm:ss"
+
+ # Generate the label format if not set
if !scope.labelFormat
scope.labelFormat = scope.dateFormat
unless scope.disableTimepicker
scope.labelFormat += " " + scope.timeFormat
+
if attrs.iconClass && attrs.iconClass.length
scope.buttonIconHtml = $sce.trustAsHtml("")
@@ -109,15 +121,15 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
date = if ngModelCtrl.$modelValue then parseDateString(ngModelCtrl.$modelValue) else null
setupCalendarView()
setInputFieldValues(date)
- scope.mainButtonStr = if date then $filter('date')(date, scope.labelFormat) else scope.placeholder
+ scope.mainButtonStr = if date then $filter('date')(date, scope.labelFormat, scope.timezone) else scope.placeholder
scope.invalid = ngModelCtrl.$invalid
# Set the values used in the 2 input fields
setInputFieldValues = (val) ->
if val?
- scope.inputDate = $filter('date')(val, scope.dateFormat)
- scope.inputTime = $filter('date')(val, scope.timeFormat)
+ scope.inputDate = $filter('date')(val, scope.dateFormat, scope.timezone)
+ scope.inputTime = $filter('date')(val, scope.timeFormat, scope.timezone)
else
scope.inputDate = null
scope.inputTime = null
@@ -194,7 +206,7 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
# HELPER METHODS
# =================================
dateToString = (date, format) ->
- $filter('date')(date, format)
+ $filter('date')(date, format, scope.timezone)
stringToDate = (date) ->
if typeof date == 'string'
@@ -204,6 +216,12 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
parseDateString = ngQuickDateDefaults.parseDateFunction
+ combineDateAndTime = (date, time) ->
+ if scope.timezone is "UTC"
+ "#{date}T#{time}Z"
+ else
+ "#{date} #{time}"
+
datesAreEqual = (d1, d2, compareTimes=false) ->
if compareTimes
(d1 - d2) == 0
@@ -221,7 +239,7 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
# DATA WATCHES
# ==================================
-
+
# Called when the model is updated from outside the datepicker
ngModelCtrl.$render = ->
setCalendarDate(ngModelCtrl.$viewValue)
@@ -266,12 +284,12 @@ app.directive "quickDatepicker", ['ngQuickDateDefaults', '$filter', '$sce', (ngQ
# This is triggered when the date or time inputs have a blur or enter event.
scope.selectDateFromInput = (closeCalendar=false) ->
try
- tmpDate = parseDateString(scope.inputDate)
+ tmpDate = parseDateString(combineDateAndTime(scope.inputDate, emptyTime))
if !tmpDate
throw 'Invalid Date'
if !scope.disableTimepicker && scope.inputTime and scope.inputTime.length and tmpDate
- tmpTime = if scope.disableTimepicker then '00:00:00' else scope.inputTime
- tmpDateAndTime = parseDateString("#{scope.inputDate} #{tmpTime}")
+ tmpTime = if scope.disableTimepicker then emptyTime else scope.inputTime
+ tmpDateAndTime = parseDateString(combineDateAndTime(scope.inputDate, tmpTime))
if !tmpDateAndTime
throw 'Invalid Time'
tmpDate = tmpDateAndTime