I have two DateTime objects:
time1 = '2016-04-05T15:30:00';
time2 = '2016-04-05T14:48:41.7609724Z';
In my HTML, I have:
<div ng-if="time1 > time2">result</div>. This works well.
Now I want to know if time1 minus 30 minutes still > time2. So I did:
<div ng-if="time1 - 30*60*1000 > time2">result</div> This doesn't work.
It's like I can only compare the datetime object directly using > or <, but I can't do math on it using - or +. To verify:
<div>{{time1 > time2}}</div> shows True.
<div>{{time1 < time2}}</div> shows False.
<div>{{time1 - time2}}</div> shows NaN. I expect this to be a number of the result in milliseconds.
QUESTION: How to do math on the DateTime with ng-if, e.g. adding minutes on one DateTime, then compare these two DateTime.
NOTES: Some may say it's because my time1 and time2 have different format. I've verified this is not the issue. Same issue happens when I change time2 to same format as time1.
I suggest using a filter, then you can use standard angular paradigms. Using my example your markup will look like the following:
{{date1 | myFilter: date2: '-'}}
And the filter will look something like:
.filter('myFilter', function() {
return function(date1, date2, operation) {
switch(operation) {
case '===':
return date1.toString() === date2.toString();
break;
case '-':
return (date1 - date2).toString();
break
}
}
})
here is a plunker demonstrating the concept:
https://plnkr.co/edit/gqQ0OsdR6cN7u4VM5AvP?p=preview
You could also create a controller method for the comparison of the dates.
With the Date object you can do basic math (subtraction and adding) and afterward you can get the time in millisconds with getTime() from date object.
Then you'll only have to do some scaling to minutes (*1000 *60) and you can compare the minutes.
With a $watchGroup (angular >=1.3) you can watch every variable that's relevant for an update of you time delta. You could also use ng-change on every input field but watch is easier to write.
Something like in the demo below or in this jsfiddle should work.
angular.module('demoApp', ['ui.bootstrap'])
.controller('mainController', MainController);
function MainController($scope) {
var vm = this;
vm.date1 = new Date();
vm.diff = 35;
vm.date2 = new Date(vm.date1);
vm.date2.setMinutes(vm.date1.getMinutes() + vm.diff);
vm.date = {
deltaMinutes: vm.diff,
deltaBool: Date((vm.date2 - vm.date1))
};
vm.updateDate = function(date) {
//console.log('changed', date);
var deltaDate = new Date((vm.date2 - vm.date1));
vm.date.deltaMinutes = (deltaDate.getTime() / 1000 / 60);
vm.date.deltaBool = vm.date.deltaMinutes >= vm.diff;
//console.log(vm.diff);
};
vm.open1 = function() {
vm.popup1.opened = true;
console.log('clicked open', vm.popup1);
};
vm.open2 = function() {
vm.popup2.opened = true;
};
$scope.$watchGroup(['mainCtrl.date1', 'mainCtrl.date2', 'mainCtrl.diff'], vm.updateDate);
//$scope.formats = ['dd-MMMM-yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate'];
//$scope.format = $scope.formats[0];
//vm.altInputFormats = ['M!/d!/yyyy'];
vm.popup1 = {
opened: false
};
vm.popup2 = {
opened: false
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.3.1/ui-bootstrap-tpls.js"></script>
<div ng-app="demoApp" ng-controller="mainController as mainCtrl">
time difference in minutes:
<input ng-model="mainCtrl.diff"/>
<br/>date1:
<p class="input-group">
<input type="text" class="form-control" ng-model="mainCtrl.date1" is-open="mainCtrl.popup1.opened" ng-required="true" close-text="Close" uib-datepicker-popup alt-input-formats="mainCtrl.altInputFormats"/>
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="mainCtrl.open1()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
<uib-timepicker ng-model="mainCtrl.date1" ng-change="mainCtrl.changed(mainCtrl.date1)" show-meridian="ismeridian"></uib-timepicker>
date2:
<p class="input-group">
<input type="text" uib-datepicker-popup class="form-control" ng-model="mainCtrl.date2" is-open="mainCtrl.popup2.opened" ng-required="true" close-text="Close" alt-input-formats="mainCtrl.altInputFormats" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="mainCtrl.open2()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
<uib-timepicker ng-model="mainCtrl.date2" show-meridian="ismeridian"></uib-timepicker>
<br/>time difference in minutes = {{mainCtrl.date.deltaMinutes}}
<div ng-if="mainCtrl.date.deltaBool" class="alert alert-success">
date1 is at least {{mainCtrl.diff}} Minutes before date2
</div>
</div>
Related
I want to subtract a user input years from another input years, but so far I had no luck.
I'll create a snippet where you can play.
What I'm trying to do is to make an input field (A) to enter years only. Then after that select any date and subtract it from the input year (A) (date and month are fixed like 31.03.input_year)...
$(document).on('change', '#year_select', function() {
calculate();
});
$(document).on('change', '#new_date', function() {
calculate();
});
function calculate() {
var year_enter = $('#year_select').val();
var current_year = year_enter+'-03-31';
var new_date = $('#new_date').val();
if(year_enter != '') {
//alert(current_year);
}
if(new_date != '') {
//alert(new_date);
var total = new_date - current_year;
$('#answer').val(total);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Enter years (A)</p>
<input type="number" id="year_select" min="0" placeholder="Eg: 2018, 2001">
<br>
<p>Select Date (B)</p>
<input type="date" id="new_date">
<p>(A - B)</p>
<input type="text" readonly id="answer">
I always get NaN value, my subtract method is incorrect I guess. I tried using setDate(), getDate() etc, but I don't understand the logic.
Thanks in advance...
You can use new Date() to type cast them into date in order to do arithmetic
$(document).on('change', '#year_select', function() {
calculate();
});
$(document).on('change', '#new_date', function() {
calculate();
});
function calculate() {
var year_enter = $('#year_select').val();
var current_year = new Date(year_enter + '-03-31');
var new_date = new Date($('#new_date').val());
if (year_enter != '') {
}
if (new_date != '' && year_enter != '') {
if (current_year < new_date) {
$('#answer').val('A must be greater than B');
return;
}
var total = Math.round(Math.abs((current_year.getTime() - new_date.getTime()) / (24*60*60*1000)));
$('#answer').val(total);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Enter years (A)</p>
<input type="number" id="year_select" min="0" placeholder="Eg: 2018, 2001"><span style="opacity: 0.5;"> this currently has fixed -month-day(-03-31) </span>
<br>
<p>Select Date (B)</p>
<input type="date" id="new_date">
<p>(A - B)</p>
<input type="text" readonly id="answer">
Dates can be tricky to handle, but the moment library makes it a lot easier. In my example I take the input of the two fields, parse them into a moment object and calculate their difference in a duration. You can read more on duration in the Moment.js docs.
The code snippet difference is expressed in days. In case you want to change it to months, or years, update the below line.
log(Math.round(duration.as('days')) + 'days');
You can also include several if statements, to check if the difference is a year, display the result in years. If not, and there's a full month, express the result in months and so on.
Here's a working example in days.
$(document).on('change', '#year_select', function() {
calculate();
});
$(document).on('change', '#new_date', function() {
calculate();
});
function calculate() {
var yearSelect = document.querySelector('#year_select').value;
var newDate = document.querySelector('#new_date').value;
var first_date = new window.moment('31-03-' + yearSelect, 'DD-MM-YYYY');
var second_date = new window.moment(newDate, 'YYYY-MM-DD');
if(yearSelect.length !== 4 || newDate === '') {
log('');
return;
}
var duration = window.moment.duration(first_date.diff(second_date));
log(Math.round(duration.as('days')) + 'days');
}
function log(value) {
var answer = document.querySelector('#answer');
answer.value = value;
}
<script src="https://cdn.jsdelivr.net/momentjs/2.10.6/moment-with-locales.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Enter years (A)</p>
<input type="number" id="year_select" min="0" placeholder="Eg: 2018, 2001">
<br>
<p>Select Date (B)</p>
<input type="date" id="new_date">
<p>(A - B)</p>
<input type="text" readonly id="answer">
NOTE: There are a few discussions out there on how to format a date/duration, e.g. 1 year, 2 months, 5 days. Have a look at a possible solution at these discussions if you want something like this.
How can I format time durations exactly using Moment.js?
How do I use format() on a moment.js duration?
I have a form that uses jQuery validate, but the form is generated dynamically and I am trying to add an additional method for validating whether a date is before another, if that date has been used before.
The HTML is the following (with the names generated dynamically):
<div class="form-group">
<label class="control-label col-md-2">Read Date</label>
<div class="input-group col-md-4 date date-picker" data-date-format="dd/mm/yyyy">
<div class="input-icon right">
<i class="fa"></i>
<input type="text" class="form-control insert-val" readonly="" name="datepicker_16" aria-required="true" aria-invalid="false">
</div>
<span class="help-block">Enter the date of the reading</span>
<span class="input-group-btn">
<button class="btn default" type="button" style="margin-top: -18px;"><i class="fa fa-calendar"></i></button>
</span>
</div>
<input type="hidden" name="prevdate_16" class="form-control prev-date" value="29/05/2015">
With the following jQuery to validate the date field:
$('#readingForm .insert-val').each(function(){
var prevDate = $(this).parents('.form-group').find('.prev-date').val();
var useLTD = true;
if(prevDate !== ''){
$.validator.addMethod("less_than_date", function(value, element) {
var curDate = value;
var curarr = curDate.split('/');
var curDay = curarr[0];
var curMonth = curarr[1];
var curYear = curarr[2];
var ncurDate = new Date();
ncurDate.setFullYear(curYear, curMonth-1, curDay);
var prevarr = prevDate.split('/');
var prevDay = prevarr[0];
var prevMonth = prevarr[1];
var prevYear = prevarr[2];
var nprevDate = new Date();
nprevDate.setFullYear(prevYear, prevMonth-1, prevDay);
return ncurDate <= nprevDate;
}, "The reading date must be greater than the previous reading date.");
} else {
useLTD = false;
}
$(this).rules( "add", {
required: true,
minlength: 10,
dateITA: true,
less_than_date: useLTD
});
});
Before the I added the "add method", it correctly validated the date, but now it does not, and doesnt accept even if the date is greater than the previous date.
Really stumped on this one, any help would be greatly appreciated.
Ok, as soon as I posted this, I realised that the return was the wrong way round.
Should have been:
return nprevDate <= ncurDate;
I have an input field that asks user to pick a date and if the date is less than 30 days form today it will display some other contents. I am using jQueryUI datapicker and knockout.js for data binding and here is what I have so far JSFiddle but it's not working. What am I missing?
$(document).ready(function() {
$("#datepicker").datepicker();
});
$(document).ready(function() {
var viewModel = function() {
var self = this;
self.request_due_date = ko.observable();
self.request_due_date_rush = ko.observable(false);
self.request_due_date_rush_reason = ko.observable();
self.request_due_date.subscribe(function(dd) {
var cur = new Date(),
rush_date = cur.setDate(cur.getDate() + 30);
if (dd < rush_date) {
self.request_due_date_rush(true);
}
});
};
ko.applyBindings(new viewModel());
});
<div>Due Date:
<input id="datepicker" data-bind="text: request_due_date" type="text" />
</div>
<div data-bind="visible: request_due_date_rush">Reason For Rush:
<input data-bind="text: request_due_date_rush_reason" />
</div>
it's because when you create the datepicker object, the underlying input element gets moved around in the DOM, breaking the binding. Consider writing your own binding handler, like seen here:
jQuery UI datepicker change event not caught by KnockoutJS
You need to bind value, not text.
<input id="datepicker" data-bind="value: request_due_date" type="text" />
Also the value dd is a string and must be parsed to date, for example using moment.js
var days = moment().diff(moment(dd, "MM/DD/YYYY"), "days");
See updated fiddle
Thanks to #MaxBrodin for the insight (to bind value, not text) and this post I found the following solution to be working. Here is also the updated Fiddle
$(document).ready(function() {
$("#datepicker").datepicker();
});
$(document).ready(function() {
var viewModel = function() {
var self = this;
self.request_due_date = ko.observable();
self.request_due_date_rush = ko.observable(false);
self.request_due_date_rush_reason = ko.observable();
self.request_due_date.subscribe(function(dd) {
var date1 = new Date(dd);
var date2 = new Date();
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
var days = Math.ceil(timeDiff / (1000 * 3600 * 24));
self.request_due_date_rush(days < 30);
});
};
ko.applyBindings(new viewModel());
});
<div>Due Date:
<input id="datepicker" data-bind="value: request_due_date" type="text" />
</div>
<div data-bind="visible: request_due_date_rush">Reason For Rush:
<input data-bind="text: request_due_date_rush_reason" />
</div>
I am trying to check if selected date is equal to next business date using AngularJS. If selected date is not equal to the next business date, a warning will be shown, like twitter bootstrap's alert-warning, using ng-show angularjs directive.
Here's the current Fiddle for this.
Currently, the next business day is returned by getNextBusinessDay() $scope function. The comparison is triggered by ng-changed="comparisonResult()" which should return true/false based on comparison, but isn't working.
Here my html code:
<body ng-app="angularjs-starter" ng-controller="MainCtrl">
<div class="container">
<section id="datepicker">
<div class="bs-docs-example">
<form class="form-horizontal well">
<div class="control-group input-append">
<label for="inputDatepicker" class="label" style="margin-right:6px;">
Selected Date</label>
<input id="inputDatepicker" class="input-small" type="text"
ng-model="selectedDate" ng-changed="comparisonResult()"
data-date-format="dd/mm/yyyy" bs-datepicker>
<button type="button" class="btn" data-toggle="datepicker">
<i class="icon-calendar"></i></button>
</div>
</form>
</div>
</section>
</div>
</body>
Here's my js code:
var app = angular.module('angularjs-starter', ['$strap.directives']);
app.controller('MainCtrl', function($scope, $window, $location) {
// Datepicker directive
$scope.selectedDate = null;
$scope.getNextBusinessDay = function() {
return $scope.getDeliveryDateObj(1);
}
$scope.getDeliveryDateObj = function(businessDaysLeftForDelivery){
var now = new Date();
var dayOfTheWeek = now.getDay();
var calendarDays = businessDaysLeftForDelivery;
var deliveryDay = dayOfTheWeek + businessDaysLeftForDelivery;
if (deliveryDay >= 6) {
businessDaysLeftForDelivery -= 6 - dayOfTheWeek; // deduct this-week days
calendarDays += 2; // count this coming weekend
deliveryWeeks = Math.floor(businessDaysLeftForDelivery / 5); // how many whole weeks?
calendarDays += deliveryWeeks * 2; // two days per weekend per week
}
now.setTime(now.getTime() + calendarDays * 24 * 60 * 60 * 1000);
now.setUTCHours(0);
now.setUTCMinutes(0);
now.setUTCSeconds(0);
now.setUTCMilliseconds(0);
return now;
}
$scope.getNextBusinessDay();
$scope.comparisonResult = function() {
if($scope.selectedDate == $scope.getNextBusinessDay()) {
return false;
} else {
return true;
}
};
});
Any help or suggestion will be appreciated. Thanks in advance. :)
When comparing dates, use a.getTime() == b.getTime() instead of a == b.
It is 2017 now, if you use Angular >= v1.2 you can use angular.equals(date1, date2)
I am trying to validate date based on date entered in first textbox. If second textbox exceeds one year from the date entered in first textbox, then it should display an alert and blank the second date field textbox. Both the textboxes are readonly and gets the values from calender. I tried the below code but the alert is popping up even if the year is not more than a year. Also ,is it possible to pass 'name3' and 'name4' IDs as parameters. I need to apply this code to 10 rows.
<script>
function fixup()
{
var parts = document.getElementById('name3').value.split("-");
parts[2] = Number(parts[2]) + 1;
var pj = parts.join("-");
var x=document.getElementById('name4').value;
if(x>pj)
{
alert("Expiration date should not be greater than one year from start date");
document.getElementById('name4').value = "";
return false;
}
return true;
}
</script>
</head>
<body>
<form onsubmit="return fixup()">
<table>
<tr>
<td><input type="text" name="soname3" id="name3" size="15" readonly="readonly">
<img src="../Image/cal.gif" id="" style="cursor: pointer;" onclick="javascript:NewCssCal('name3','MMddyyyy','dropdown',false,'12')" /></td>
<td><input type="text" name="soname4" id="name4" size="15" readonly="readonly">
<img src="../Image/cal.gif" id="" style="cursor: pointer;" onclick="javascript:NewCssCal('name4','MMddyyyy','dropdown',false,'12'); " /> </td>
</tr>
</table>
<input type="submit" value="Submit">
</form>
I did Below code after suggestions by dm03514. but validation is not working..
function test()
{
start = document.getElementById('name3').value;
end = document.getElementById('name4').value;
compare(start, end);
}
function compare(sDate, eDate)
{
function parseDate(input) {
var parts = input.match(/(\d+)/g);
return new Date(parts[2], parts[0]-1, parts[1]); //parts[2] is year, parts[0] is month and parts[1] is date.
}
var parse_sDate = parseDate(sDate);
var parse_eDate = parseDate(eDate);
parse_sDate.setDate(parse_sDate.setFullYear(parse_sDate.getMonth() + 12));
if(parse_sDate>parse_eDate)
{
alert("End date should not be greater than one year from start date");
}
}
I would strongly recommend using a library like moment.js for handling dates. It has extensive date formatting and parsing features as well as comparison helpers:
var d1 = moment(document.getElementById('name3').value, 'YYYY-MM-DD');
var d2 = moment(document.getElementById('name4').value, 'YYYY-MM-DD');
var diff = d2.diff(d1, 'years');
if (diff > 0) {
alert("Expiration date should not be greater than one year from start date");
}
See also:Compare two dates in JS