difficulty with approach to allowing user to input time - javascript

Stuck on the thinking of this, a user can enter a time into a field in the formats listed below. The time in the end will be saved and formatted to xx:xx 12 hour. I'm allowing flexibility/laziness on the user's part rather than throw strict errors.
Formats Allowed
1 (1 digit)
11 (2 digits)
11 1(hours and min)
11 10(hours and mins)
1110(hours and mins, no space)
Problems
I need to somehow take the user's entered time
Add prefixed zeros where needed so i get (xx:xx)
Add ":" in between hours and mins
Why do I need specifically ":" inserted? I need to save hour and min into separate variables later but I need to reformat the time behind the scenes so that it's ALWAYS xx:xx, having it in a predictable format means I can use JavaScript to split it by the ":" and do what I need to from there.
I'm not looking for the straight answer so much as suggestions because I'm under the assumption i'll need regex.

http://jsfiddle.net/8dabu7d8/7/
var number = "11 11";
console.log(format(number));
function format(number) {
if (number.length == 1 ) {
return '0' + number + ':00'
}else if (number.length == 2) {
return number + ':00'
} else if (number.length == 3){
return number.substring(0, 2) + ':' + number.substring(2)
} else if (number.length == 4 || number.length == 5){
return number.substring(0, 2) + ':' + number.substring(2).trim()
}
}

Using the replace method, you could do something such as :
var myRegexp = /(\d{1,2})[ ]?(\d{0,2})/i;
var match = myRegexp.exec(yourString);
var result = match[1];
if(match[1].length == 1)
{
result = match[1].concat("0");
}
result = result.concat(":");
if(match[2].length != 2)
{
if(match[2].length == 0){
result = result.concat("00");
}
else{
result = result.concat(match[1].concat("0"));
}
}

My suggestion is to use a time picker which will solve all your overheads and the user experience will also be great.You have a enormous time picker controls available in java script.
here is a simple example
http://jonthornton.github.io/jquery-timepicker/
I feel better to use any of these time picker control.

Related

IE Failing to evaluate second if condition (&&)

So I have this script:
function makeActive() {
var element, name, arr;
element = document.getElementById("liveChat");
name = "active";
arr = element.className.split(" ");
if (arr.indexOf(name) == -1) {
element.className += " " + name;
}
}
var currentTime = new Date();
var currentTimeFormatted = currentTime.toLocaleTimeString();
if(currentTimeFormatted >= '08:00:00' && currentTimeFormatted <= '16:30:00'){
makeActive();
}
Which works perfectly in Chrome, however in IE the class doesn't get added.
If I remove the
&& currentTimeFormatted <= '16:30:00'
IE also adds the class. Why would adding a second condition, break this script within IE?
To make this a tad easier than having to use && and || mix, or if your values are stored somewhere in a static file etc. You could create a kind of pseudo time, by multiply each section.
eg.
const cTime = new Date();
const ptime =
cTime.getHours() * 10000 +
cTime.getMinutes() * 100 +
cTime.getSeconds();
if (ptime >= 80000 && ptime <= 163000) {
console.log("Active");
} else {
console.log("InActive");
}
You are doing string comparisons, which means that the browser and locale dependent output of toLocaleTimeString() screws your code in IE, and possibly also in other browsers or regions, because this function is solely intended for producing a human-readable time representation.
So you should either:
(1) Use a string representation that is standardized, e.g. invoking toISOString(). This will also get rid of time zone problems, because the result will always be in UTC time:
var currentTimeFormatted = new Date().toISOString(); // 2018-11-07T12:28:12.448Z'
currentTimeFormatted = currentTimeFormatted.substr(currentTimeFormatted.indexOf('T') + 1, 8); // 12:27:12
Now the rest of your code will work (assuming you 08:00:00 and 16:30:00 are UTC times).
(2) Extract the hour and minute parts of the new Date() and compare those to integers:
var currentTime = new Date();
if(currentTime.getHours() >= 8
&& // similarly a comparison to < 16:30
) {
makeActive();
}
(3) Use the great solution by Keith (see below), which I think is the best way to go
IE's implementation of date.toLocaleTimeString() adds non-printable characters into the string. The easiest way to deal with them is to trim them from the string;
currentTimeFormatted = currentTime.toLocaleTimeString().replace(/[^ -~]/g,'')
When dealing with localized timezones and timezone comparison, it might be worth trying a library like moment.js which can also deal with comparing values using the isBetween funciton
Edit
As the other solutions have suggested - using toLocaleTimeString() is not a safe method of performing date comparison and should be avoided.

Nested IF statement doesn't work like I want it to

var dayInput = document.querySelector("#day");
var monthInput = document.querySelector("#month");
var yearInput = document.querySelector("#year");
var day = document.querySelector("h2");
var h3 = document.querySelector("h3");
function runCode() {
dayPicked = Number(dayInput.value);
monthPicked = Number(monthInput.value);
yearPicked = Number(yearInput.value);
if (dayPicked <= 31) {
if (monthPicked <= 12) {
if ((monthPicked = 2) && (dayPicked <= 29)) {
day.textContent = (DispDay(dayPicked, monthPicked, yearPicked));
h3.textContent = (DispFullDate(dayPicked, monthPicked,
yearPicked));
} else { day.textContent = "Not Possible Dude!"}
} else { day.textContent = "Not Possible Dude!"}
} else { day.textContent = "Not Possible Dude!"}
}
This is a snippet out of my code where I am trying to limit the search for dates within my input boxes. For example, if February is chosen and the day is the 30th, it should throw out an error. But all that happens with the code you see above is no matter what month I choose, it keeps returning February. I know I am definitely doing something wrong, but I do not know what it is. BTW - I started learning JavaScript 3 weeks ago so I know my code is a mess. Thanks.
var button = document.querySelector("#goButton");
[dayInput, monthInput, yearInput].forEach(function (element) {element.addEventListener("keyup", function (event) {
event.preventDefault();
if (event.keyCode === 13) {
runCode();
}
});
});
I don't know if the EventListener needs to be added here but here it is anyway.
You're setting monthPicked
monthPicked = 2
You meant to use two == to check for equality.
However, the next problem you'll see is that your code will only work if the user selects February.
You probably wanted
if ((monthPicked != 2) || (dayPicked <= 29)) {
That way if they select february, it has to be before 29th. Any other month can be anything. Still incomplete logic as some months should allow 31 others not. But i'll leave that to you. (Also, leap years!)
= is an Assignment Operator. == is an Equal To Operator,compares value of left and side expressions. Change monthPicked = 2 to monthPicked == 2.

Get next occurrence of a weekday if not found in desired week

How can I come up with an algorithm to find out the very next occurrence of a weekday if not found in the desired week. For example following is the screenshot of the calendar. There is no Tuesday in first week of April. I need an idea how can I go for the next Tuesday in the next week if not present in the given week?
Below is my algorithm which is working fine in getting any week's selected weekday. I just want to add two conditions in it to iterate back and forth in the case when weekday is not present in the given week.
for(var ind=0; ind<=between.length; ind++){
if (new Date(between[ind]).getMonthWeek() === baseDtWk && new Date(between[ind]).getDay() === baseDtD) {
datesToBeMarked.push(between[ind]);
console.log(" :Date: " + between[ind] + " :Week: " + new Date(between[ind]).getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}
}
In above code baseDtWk & baseDtD contains the week and day.
Week is an integer from 1 to 5.
Day is an integer from 0 to 6 representing weekday from sun to sat.
for-loop iterates over all the array elements & push the elements into another array which has same week and weekday in a month. So ideally it is fulfilling the purpose in happy scenario, where every time weekday is available. Unlike the above case. Any ideas, guidance will be highly appreciable. Thanks.
By looking at your code it looks like you already have the structure in place just need to know how to utilize it.
I'm going to slightly modify your if condition as shown below.
for(var ind=0; ind<=between.length; ind++){
var thisDt = new Date(between[ind]);
if (thisDt.getMonthWeek() === baseDtWk && thisDt.getDay() === baseDtD) {
datesToBeMarked.push(thisDt);
console.log(" :Date: " + between[ind] + " :Week: " + thisDt.getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}
}
Just by adding a var thisDt = new Date(between[ind]) you can get much cleaner code than before.
1. Now look at your code carefully you are already scanning each date by its week and weekday in your if-condition. And qualified element goes to datesToBeMarked[] array.
2. You need to introduce another if-condition which will walk through the between[] array and will scan every base day (You call it base which is the first element in your between[] array). Now the if-condition will look like as below.
for(var ind=0; ind<=between.length; ind++){
var thisDt = new Date(between[ind]);
if (thisDt.getMonthWeek() === baseDtWk && thisDt.getDay() === baseDtD) {
datesToBeMarked.push(thisDt);
console.log(" :Date: " + between[ind] + " :Week: " + thisDt.getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}else if(thisDt.getDay() === baseDtD && thisDt.getMonth()!==new Date(datesToBeMarked[ind-1]).getMonth()){
//some magic needs to be done here
}
}
3. What is happening above in the else-if? It is checking your already selected Tuesday with the next element. If it is coming in the same month then reject it. Otherwise let it come inside the if-condition to see the magical move. :)
4. Lastly here inside your else-if you need a function to be called which will find you the next occurrence of the Tuesday if it is not in place initially in the first week as shown in your picture above.
5. Function for finding the day will look like as written below. And you are all set hopefully.
Following function needs to be replaced inside your else-if with this comment //some magic needs to be done here.
function nthDay(nth, weekday, month, year) {
var nthDate = new Date(year, month + ((nth <= 0) ? 1 : 0), 1);
var dayofweek = nthDate.getDay();
var offset = weekday - dayofweek;
nthDate = new Date(year, month + ((nth <= 0) ? 1 : 0), nthDate.getDate() + (offset + (nth - (offset >= 0 ? 1 : 0)) * 7));
if (nthDate.getMonth() !== month) {
return false;
} else {
return nthDate;
}
}
6. Happy Coding :)

AngularJS: Get dates with suffix rd, th and st

How to format Date in Angular Java script?
Code
<p id="summaryHeader">Calendar of {{dt}}</p>
I get the value as
2014-06-05T12:38:42.744Z
I tried this
<p id="summaryHeader">Calendar of {{dt|date:'MMMM dd'}}</p>
which gives me
Calendar of June 05
I need it as Calendar of June 05th or July 2nd and so on.. the rear rd,th,st is what I am looking for.
Anuglar Docs are good but don't specify this formatting.
I guess this is what you are looking for - http://www.michaelbromley.co.uk/blog/13/an-ordinal-date-filter-for-angularjs
A custom filter using the logic
app.filter('dateSuffix', function($filter) {
var suffixes = ["th", "st", "nd", "rd"];
return function(input) {
var dtfilter = $filter('date')(input, 'MMMM dd');
var day = parseInt(dtfilter.slice(-2));
var relevantDigits = (day < 30) ? day % 20 : day % 30;
var suffix = (relevantDigits <= 3) ? suffixes[relevantDigits] : suffixes[0];
return dtfilter+suffix;
};
});
And a Demo: http://plnkr.co/edit/HiyQ9uvxQL3FRoj7hKB8?p=preview
I wanted to have the ordinal indicator as a superscript, so used the following:
<div>{{amount}}<sup ng-bind="amount | ordinal"></sup></div>
Using the filter:
app.filter('ordinal', function() {
return function(number){
if (isNaN(number) || number < 1){
return '';
} else if (number % 100 == 11 || number % 100 == 12) {
return 'th';
} else {
var lastDigit = number % 10;
if (lastDigit === 1) {
return 'st';
} else if (lastDigit === 2) {
return 'nd';
} else if (lastDigit === 3) {
return 'rd';
} else if (lastDigit > 3) {
return 'th';
}
}
}
});
Note that this correctly renders 11th, 12th, 111th, 1012th, and not 11st.
You are correct that the date filter does not provide this formatting... I would suggest that you either write your own filter, or just do this:
Calendar of {{dt|date:'MMMM dd'}}{{getOrdinal(dt)}}
if you write your own, I would start with the one from angular as a baseline.
EDIT the idea of writing your own in the answer provided by guru is the approach I would take.
To expand upon the example he created, I would tweak it so that you can use this syntax:
Calendar of {{dt|date2:'MMMM ddoo'}}
Where oo is the ordinal suffix
I updated this representative plnkr to give you maximum flexibility.
For anybody that hits this question there is the project https://github.com/chrisiconolly/angular-all-ordinal-filters (full disclaimer: my own project) that will give you a ordinal number filter for angular.
Its used as so:
{{number | ordinal}} // 1 -> 1st
{{number | ordinalOnly}} // 1 -> st
It's fully tested and running through travis so it will remain stable.
You could wrap your date in a momentjs object like
$scope.dt = moment($scope.dt);
then do
<p id="summaryHeader">Calendar of {{dt.format("ddd Do")}}</p>
Other options may be better unless you already use momentjs elsewhere, just an option.
While not my best work you can start with this as a baseline
http://plnkr.co/edit/v2RuF72A9OPpFj5fvN8A?p=preview

Validate a time string (up to one hour) with javascript

I am looking for a regex pattern to validate a string and see if this is an valid time. It can only be up to one hour. I want to check if a string is a valid time or return false.
It needs to be in mm:ss format
Good = 00:00
Good = 60:00
Bad = 60:01
Bad = 89:09
Bad = 3445
Using regex to validate number ranges is not an optimal solution. You need to create a quite long pattern to evaluate easy conditions. You'd be probably better of checking only if it's a number:number pattern then split it and check if the parts are consistent with your requirements or not:
function checkTime(time) {
if (time.match("^[0-9]{2}:[0-9]{2}$") === null) {
return false;
}
var parts = time.split(':');
if (parts[0] > 60) {
return false;
}
if (parts[0] == 60 && parts[1] > 0) {
return false;
}
return true;
}
That being said you can create a regex for this if you really want:
function checkTime(time) {
return time.match("^(60:00|[0-5][0-9]:[0-5][0-9])$") !== null;
}
It's just much harder to maintain and read this kind of code later on.
My shot at it:
function validate(input){
var split = input.split(':'), // split the input
part1 = +split[0], part2 = +split[1]; // try to parse parts to numbers
if(!part1 || !part2) return false; // didn't get 2 valid numbers
return (part1*60 + part2) < 3600; // check if they're less then 1 hour
}
console.log(validate('55:09')); // true
console.log(validate('61:09')); // false
console.log(validate('6155')); // false
http://jsfiddle.net/LGheT/

Categories