Comparison of between hours using JavaScript - javascript

In my application I want to determine if a hour:minute is bigger than 21:00h and other hour:minute is lesser than 08:00.
I am using the 24-hour format for this.
var one = "21:30";
var two = "09:51";
To get just hour from hour and minutes I use split():
var h_1 = one.split(":"); //21
var h_2 = two.split(":"); //08
if (h_1 > "21" && h_2 < "08") {
// Do something
}
The real story for the application is:
A shop has an option to deliver outside of working time (working hours start at "08:00" - "21:00").
If a customer wants to buy out of hours, do something.
So why does my approach not work properly? What is the best approach to compare the hours and minutes between two variables of h:m type?

Have you tried comparing the strings?
if (two < "08:00" && one > "21:00")
//magic
As long as your strings are always formatted with a leading zero for one-digit hours, then it woks fine.

The split() method return an array, so to get just hours (first column in your case) you should specify index 0:
var h_1 = one.split(":")[0]; //21
var h_2 = two.split(":")[0]; // 08
i want to determine if hour:minute one is biger than 21:00h and hour:minute two is lesser than 08:00
Use greater than or equal to operator >= and less than or equal to <= to exclude hours 21 and 08:
if(h_1 >= "21" && h_2 <= "08") {
// do somthing
}
Hope this helps.

Related

Momentjs / Angularjs - Checking if 2 dates are in the same period - TimeSheet project

I am working on a simple Timesheet app, I am trying to implement an auto calculator that will sum up your hours for each day (Sunday, Monday, Tuesday, etc ...). A problem I noticed is that in some cases, users will enter activities that will be within the same date time periods.
For example:
$scope.Example = [
{Description:"Example activity",Start:"2018-06-24 8:00",End:"2018-06-24 10:00",Total:2},
{Description:"Example activity2",Start:"2018-06-24 9:00",End:"2018-06-24 10:00",Total:1},
{Description:"Example activity3",Start:"2018-06-24 10:00",End:"2018-06-24 11:00",Total:1}];
$scope.Calculate_all_entries = function(){
$scope.Total.Sunday = 0;
if($scope.Example){
angular.forEach($scope.Example, function(element){
if(moment(element.Start).format("dddd") === "Sunday"){
$scope.Total.Sunday = $scope.Total.Sunday + element.Total;
}
})
}
}
In this case the total should be 3 hours and not 4 hours as we dont charge for work within the same hours. I'm need to implement a system that would check if the dates are within the same period and provide the appropriate total.
I found this in the documentation on momentjs that seemed to be close to what i need but only takes one value:
moment('2010-10-19 11:00').isBetween('2010-10-19 10:00', '2010-10-25 00:00'); // true
Would anyone know of any other methods to check wether or not the start and end time are in the same period as other entries in the same day?
Sure, you can use momentjs's unix() function to convert those date times to an integer which then can easily be used to check whether the timestamp is in between two other timestamps.
Here is an example:
var timeToCheck = moment('2010-10-19 11:00').unix();
var startTime = moment('2010-10-19 10:00').unix();
var endTime = moment('2010-10-25 00:00').unix();
console.log(timeToCheck >= startTime && timeToCheck <= endTime); // true

javascript: evaluate if given hour is between two hours

So there's plenty of examples on how to calculate the time between two dates.
But in my case, I have a date X. Let's say it's today.
X has a time associate to it, e.g. 08:00 (Or what I get back from .getHours())
I need to know if the hours of X are between a start hour (say "07:00") and an end hour (say "12:00")
X will be always retrieved via getHours()
The start and end hour of the range have a fixed format (e.g. "07:00" and "12:00")
Performance is an issue, so whatever performs better is preferred (e.g. if it implies using moment, that's fine, but if a custom function would perform better, we want that)
My first approach would be, as the formats are fixed, to transform the .getHours() to a number, likewise for the range hours, and then calculate...I feel this approach my have trouble with some special cases I may not be aware of?
You could use moment-range
From docs:
You can also create a range from an ISO 8601 time interval string:
var timeInterval = "2015-01-17T09:50:04+00:00/2015-04-17T08:29:55+00:00";
var range = moment.range(timeInterval);
range.contains(X); // true if between interval
If you want to check part hours, consider converting the hours to minutes, something like the following. How will you deal with ranges that go over midnight? e.g. 23:30 to 01:30.
/* Determine if the current time is between two provided hours
** #param {string} h0 - time in format h:mm
** #param {string} h1 - time in format h:mm
** #returns {boolean} true if the current time is between or equal to h0 and h1
*/
function betweenHours(h0, h1) {
var now = new Date();
var mins = now.getHours()*60 + now.getMinutes();
return toMins(h0) <= mins && mins <= toMins(h1);
}
/* Convert hours to minutes
** #param {string} h - time in format h:mm
** #returns {number} time converted to minutes
*/
function toMins(h) {
var b = h.split(':')
return b[0]*60 + +b[1];
}
<form>
Start time (h:mm)<input name="startHours">
<br>
End time (h:mm)<input name="endHours">
<br>
<button type="button" onclick="
this.form.inRange.value = betweenHours(this.form.startHours.value, this.form.endHours.value);
">Check range</button>
<br>
Currently in range? <input name="inRange" readonly>
</form>
Are you dealing with military tine? (From 0:00 to 24:00)
getHours() returns an Integer, and if you are only interested in hours and not minutes, you can use parseInt() to turn the start and end hours into integers as well. For example, parseInt('07:00', 10) will return 7. So if you wanted to create a function to test if the current time is between two hours, it might look something like this:
function isBetweenHours(startHour, endHour)
{
var now = new Date().getHours();
return now >= parseInt(startHour, 10) && now <= parseInt(endHour, 10);
}
Then you would use it like this:
if( isBetweenHours('07:00', '12:00') ) { //some code here }

Calculate difference between dates in javascript

I am aware that this question was asked multiple times before but the suggested solutions were always something like
var diff = date1 - date2;
My problem is that I want to get the difference in years, months, day, ... ,seconds.
So for example 5y 3m 39d 12h 39i 32s
But simply dividing the difference is too inaccurate for my purpose.
So I can't assume that every month has 30.4375*24*60*60*1000 milliseconds.
I need the exact difference!
So if date1 is the 1st of february and date2 is the 1st of march, it should display 1m not 28d (or 29d in leap years)!
Thank you.
First you need to find out which date is bigger, subtract the dates, and if they turn out to be negative borrow from the larger digit (similar to elementary multi-digit subtraction).
function DateDiff(a,b){
if(b>a){ // We want a-b to be positive
var c=b;
b=a;
a=c;
}
var s=a.getSeconds()-b.getSeconds();
var mi=a.getMinutes()-b.getMinutes();
var h=a.getHours()-b.getHours();
var d=a.getDate()-b.getDate(); // Subtract days
var m=a.getMonth()-b.getMonth(); // Subtract months
var y=a.getYear()-b.getYear(); // Subtract years
if(s<0){
mi--;
s+=60;
}
if(mi<0){
h--;
mi+=60;
}
if(h<0){
d--;
h+=24;
}
if(d<0){ // Need to borrow from months
m--;
d+=new Date(1900+b.getYear(),1+b.getMonth(),0).getDate();
}if(m<0){ // Need to borrow from years
y--;
m+=12;
}
return [y,m,d,h,mi,s];
}
console.log('Mar 1 - Feb 2 (Leap Year):', DateDiff(new Date(2016,1,2),new Date(2016,2,1)));
console.log('Mar 1 - Feb 2 (Reg Year): ',DateDiff(new Date(2015,1,2),new Date(2015,2,1)));
console.log('Feb 1, 2017 - Feb 2, 2016: ',DateDiff(new Date(2017,1,1),new Date(2016,1,2)));
console.log('5:00 - 4:59: ', DateDiff(new Date(2015,7,1,17), new Date(2015,7,1,16,59)));
You can use moment.js to achieve this: ( MomentJS Doc )
var start = moment(date1);
var end = moment(date2);
var diff = end.diff(start)
If you want specific things like difference in days, you can do:
var diff = end.diff(start, 'days')
For what you are describing, you will want to hold the year/month/day in three different variables and directly compare the years using
var yeardiff = date1.GetFullYear() - date2.GetFullYear();
var monthdiff = date1.GetMonth() - date2.GetMonth();
var daydiff = date1.GetDate() - date2.GetDate();
However, you are going to have to do a lot of checking in this. For example, 8/2/2012 - 7/20/2012 is going to give you a 1 month and -18 days, then you have to convert that into days based on the number of days in July. Because of these issues, the other conversion in the OP is actually easier.
Not using any library you could do
function mydiff(aa,bb){var a,b;
if(aa<bb) a=aa,b=bb;
else a=bb,b=aa;
var am=a.getMonth(),ay=a.getFullYear();
var dd=b.getDate()-a.getDate();
var dm=b.getMonth()-am-(dd<0?1:0);
return b.getFullYear()-ay-(dm<0?1:0)+'y, '
+ ((12+dm)%12)+'m, '
+((dd<0?new Date(ay, am+1, 0).getDate():0)+dd)+'d';
}
dd contains the difference 'b minus a in days of month' which can be negative. In that case the month-difference dm has to be reduced by 1 and the (negative) day-difference must be increased by the number of days of the preceding month of date b. I got the formula for "number of days in a particular month" from here. Similar action has to take place with the month- and year-differences dm and dm.
A few samples:
mydiff(new Date(2014,1,2),new Date(2014,2,1)) // "0y, 0m, 27d"
mydiff(new Date(2012,1,1),new Date(2012,2,1)) // "0y, 1m, 0d" (leap year)
mydiff(new Date(2012,1,2),new Date(2012,2,1)) // "0y, 0m, 28d" (leap year)
mydiff(new Date(2014,11,31),new Date(2015,0,1)) // "0y, 0m, 1d" (different years)
mydiff(new Date(2012,10,30),new Date(2013,1,28)) // "0y, 2m, 28d" (different years)
The last example shows that this kind of "calculation" has its limits: compared to "normal" months 28 days are not a full month. On the other hand, compared to the current month February 28 days is a full month. So it could also be argued that a correct response should be "0y, 3m, 0d".

Clever time formatting with JavaScript

I need help writing a little Regular Expression to replace integers into a time format string in a text input field.
In my form: I have a text input field where I'm supposed to write numbers. And when I write a number: I want a piece of JavaScript to convert it to a human-friendly, readable time when the input field loses focus. The thing that makes this "Clever" is that I want to be able to write as little as absolutely possible: And have it transform to the most appropriate time corresponding to my number.
Let me give you a few examples. If I write:
7 it would resolve to 07:00
15 it would resolve to 15:00
93 it would resolve to 09:30
1945 it would resolve to 19:45
143 it would resolve to 14:30
... And so on ...
I want it to do this replacement after the input field loses focus (onblur-event)
Also. I want to have a 0 prefix for night hours. Like this:
015 = 00:15
03 = 00:30
012 = 00:12
... And so on ...
I begun writing if statements to do this, but I stopped dead in my tracks because I realized it would take so many if statements, and would not be very reliable. I feel like Regular Expressions would be much smarter since it compacts my script and makes loading time quicker. I grasp the basics of Regular Expressions, but I don't know how to write a clever one for this purpose.
This is what my code got to before I decided to drop it:
var elem = document.getElementById("incidentHourStart-" + row);
if (elem.value.length === 1) {
// Must be a whole hour (0-9)
} else if (elem.value.length === 2) {
// Can be either two digits hour (10-23) or hour + whole minute (73: 07:30)
if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
// Two digits, whole hour (10-23)
} else {
// First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)
}
} else if (elem.value.length === 3) {
// First digit must be an hour value, middle digit is also hour if it is lower than 23, last digit is then always whole minutes
if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
// Two digits, whole hour (10-23)
} else {
// First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)
}
} else if (elem.value.length === 4) {
// First two digits must be an hour value, last digits is then fine selected minutes
}
As you can see: It looks very ugly!
UPDATE:
As stated in the comments: People have found my rules a little confusing. So here is the pseudo code of rules I want it to follow. If this can be put into a Regex in a clever way: Then awesome! If not: I will write out the if/else blocks, or split the Regex up into parts as suggested.
If text-length is equal to 1
Resolve as whole hour between 0-9
Examples:
2 = 02:00
8 = 08:00
5 = 05:00
If text-length is equal to 2 AND number is between 10 and 23
Resolve as whole hour between 10-23
Examples:
15 = 15:00
11 = 11:00
22 = 22:00
If text-length is equal to 2 AND number is NOT between 10 and 23
Resolve as whole hour and minutes incremented by 10's (10, 20, 30, 40, 50)
Examples:
73 = 07:30
24 = 02:40
95 = 09:50
If text-length is equal to 3 AND first two numbers are between 10 and 23
Resolve two first digits as hours and last digit as minutes incremented by 10's (10, 20, 30, 40, 50)
Examples:
133 = 13:30
195 = 19:50
111 = 11:10
162 = 16:20
If text-length is equal to 3 AND first two numbers are NOT between 10 and 23
Resolve first digit as whole hour, and last two as minutes.
Examples:
225 = 02:25
922 = 09:22
557 = 05:57
451 = 04:51
If text-length is equal to 1 AND first digit is equal to 0
Resolve as mid-night
Example:
0 = 00:00
If text-length is equal to 2 AND first digit is equal to 0
Resolve as mid-night + minutes incremented by 10's (10, 20, 30, 40, 50)
Examples:
02 = 00:20
05 = 00:50
03 = 00:30
If text-length is equal to 3 AND first digit is equal to 0
Resolve as mid-night + full minutes.
Examples:
024 = 00:24
011 = 00:11
056 = 00:56
If text-length is equal to 4
Resolve as regular minutes and hours without the colon (:)
Examples:
1524 = 15:24
2211 = 22:11
Don't make it harder on yourself than you need. Simply put; don't do this in one regular expression. Also don't forget to trim your input before using RegEx.
First of all check the zero-prefixed one, something like:
^0(\d+)$
Then if that doesn't match, do the check for the normal numbering and split it with the capture groups however you want:
^([^0]\d{1,3})$ // Can do negative lookbehind here, but I left it simple in this case
Regular expressions are often misused to solve a bigger problem in one pattern. It's much better to split logic if the situation asks for it. Don't overcomplicate code. It will break whoever needs to read it later's brain.
I have found a solution and had it deployed for about 1.5 months now. And so far: It works great. My co-workers love this functionality, and really saves up a lot of time! So far: No faults have been reported to me.
So here is what I did:
I bascially re-wrote my pseudo-code into actual JavaScript code using if/else blocks as suggested in the question's comments. I stuck it all into a function that I call from an onblur event on the input fields. Like this:
<input type="text" id="incidentHourStart-1" onblur="resolveTimeField(1);">
So the formatting occurs as soon as the input field loses focus.
Here is what my function looks like:
function resolveTimeField(row) {
var elem = document.getElementById("incidentHourStart-" + row);
if (elem.value.length === 1) {
// Must be a whole hour (0-9)
elem.value = "0" + elem.value + ":00";
} else if (elem.value.length === 2) {
// Can be either two digits hour (10-23) or hour + whole minute (73: 07:30)
if (parseInt(elem.value) >= 10 && parseInt(elem.value) <= 23) {
// Two digits, whole hour (10-23)
elem.value = elem.value + ":00";
} else {
// First digit is hour, and last one is whole minute (10, 20, 30, 40, 50)
var hours = elem.value.substring(0, 1);
var minutes = elem.value.substring(1, 2);
elem.value = "0" + hours + ":" + minutes + "0";
}
} else if (elem.value.length === 3) {
// First digit must be an hour value, middle digit is also hour if it is lower than 23, last digit is then always whole minutes
var firstDigits = elem.value.substring(0, 2);
if (parseInt(firstDigits) >= 10 && parseInt(firstDigits) <= 23) {
// 3 digits, first two are hours, and last digit is minutes incremented by 10's
var hours = elem.value.substring(0, 2);
var minutes = elem.value.substring(2, 3);
elem.value = hours + ":" + minutes + "0";
} else {
// First digit is hour, and last two is full minutes
var hours = elem.value.substring(0, 1);
var minutes = elem.value.substring(1, 3);
elem.value = "0" + hours + ":" + minutes;
}
} else if (elem.value.length === 4) {
// First two digits must be an hour value, last digits is then fine selected minutes
var hours = elem.value.substring(0, 2);
var minutes = elem.value.substring(2, 4);
elem.value = hours + ":" + minutes;
}
}
Here is a JSFiddle if you want to test out the code for yourself
My function takes one parameter referenced as row. This is because the fields I am working with lays within a dynamic table that lets my co-workers register more data in one go.
Currently it does not have any forms of input validation that checks if the inserted value is valid. So you could write something like 999 into the field and have it resolve to 09:99. This is not a critical feature for our environment, but I can imagine it would be fairly easy to implement shall it be required. I will update this post if I ever implement such a validation feature in the future.

Convert milliseconds to years

I have a validator that checks if an user is at least 18 years old.
This is the check:
var res = /^([1-2]\d{3})\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])\-([0-9]{4})$/.exec(str);
var todays_date = new Date();
var birth_date = null;
if (res != null) {
birth_date = new Date(res[1], res[2], res[3]);
if (todays_date - birth_date > 565633905872) {
565633905872 is 18 years in milliseconds but how do I convert it to years before so I can just do:
if (todays_date - birth_date => 18) {
The number you have quoted is not the number of milliseconds in 18 years. It's too small even if you pretend there are no leap years.
The simplest way to test if somebody is at least 18 years old is to initialise a date object to their birthday, then use .getFullYear() and .setFullYear() to directly set the year 18 years forward. Then compare that with the current date.
Note also that in JS dates the month is zero-based, so you probably want to use res[2] - 1 when creating the date object.
birth_date = new Date(res[1], res[2] - 1, res[3]);
birth_date.setFullYear(birth_date.getFullYear() + 18);
if (birth_date <= new Date()) {
Or given you are constructing the birth_date from individual year, month and day you could just do:
birthPlus18 = new Date(+res[1] + 18, res[2] - 1, res[3]);
if (birthPlus18 <= new Date()) {
(The leading + in +res[1] + 18 is not a typo, it converts the string extracted by your regex into a number so that you can add 18 to it. You don't need to do the same thing for res[2] - 1 because - automatically converts both operands.)
Note also that your regex will happily allow dates that specify a day that is too high for the month, e.g., Feb 30 or Jun 31.
There are better ways of checking this (see the answer of "nnnnnn"). But your question wasn't about a better way but, how you could convert to years.
You could write a function that does that, example:
function convertmili( mSeconds )
{
return mSeconds / 31536000000;
}
The output of this function is still far from ideal, because your example would output: 17.9361334941654
So we could clean it up a bit:
function convertmili( mSeconds )
{
var checkYear = Math.floor(mSeconds / 31536000000);
return checkYear;
}
With this function, your example would output 17 and then you can check it the way you wanted.
Divide your millisecond value by 31536000000 you get number of years
http://www.convertunits.com/from/milliseconds/to/year

Categories

Resources