Time validations (Javascript) - javascript

I have a form (Using JavaScript) in which users are supposed to enter information like their work start time, break start time, break end time and work end time. I have 4 textboxes for this purpose. Time entered into the textbox is in hhmm format (24-hour only).
Requirements:
1. The break times (start and end) must be within the work start and end time.
2. Break start must be before break end time.
3. Users can take up work shifts during the day or even overnight.
4. Work time(excluding breaks) should be less than 8 hours and greater than 4 hours.
So some typical valid entries would be:
User1-
Start time: 0900
Break start time:1300
Break end time:1400
End time:1600
User2-
Start time:2200
Break start time:2300
Break end time:2330
End time:0400
Some invalid entries would be:
Case1 - Break start before break end
Start time:2200
Break start time: 2330
Break end time: 2300
End time:0400
Case 2 -Breaks outside work time
Start time:2200
Break start time:1830
Break end time: 1900
End time:0400
I'm having trouble writing the validation code (JavaScript) for requirements 1,2 & 3. Please help me out.
Here's what I've got so far. (Please note: I cannot use DATE objects.)
var wrkSt = getElement('TB1').value;
var wrkSt_hr = parseFloat(wrkSt.substr(0,2));
var wrkSt_mn= parseFloat(wrkEd.substr(2,2));
var brkSt = getElement('TB2').value;
var brkSt_hr = parseFloat(brkSt.substr(0,2));
var brkSt_mn= parseFloat(brkEd.substr(2,2));
var brkEd = getElement('TB3').value;
var brkEd_hr = parseFloat(brkSt.substr(0,2));
var brkEd_mn= parseFloat(brkEd.substr(2,2));
var wrkEd = getElement('TB4').value;
var wrkEd_hr = parseFloat(wrkEd.substr(0,2));
var wrkEd_mn= parseFloat(wrkEd.substr(2,2));
var msg='';
if ((wrkSt_hr > wrkEd_hr) || ((wrkSt_hr == wrkEd_hr) && (wrkSt_mn >= wrkEd_mn)) )
{
msg+='shift overnight selected';
}
if (wrkEd_hr>12){wrkEd_hr-=12;}
if (wrkSt_hr >12){wrkSt_hr -=12;}
if (brkSt_hr>12){brkSt_hr-=12;}
if (brkEd_hr>12){brkEd_hr-=12;}
var Breakdiff = ((brkEd_hr - brkSt_hr)*60) + (brkEd_mn - brkSt_mn);
var Workdiff_tot = ((wrkEd_hr- wrkSt_hr)*60) + (wrkEd_mn -wrkSt_mn);
var Shiftdiff = Workdiff_tot - Breakdiff;
if (Shiftdiff > 480) //8hours = 8*60 = 480 min
{
msg+='Time greater than 8 hrs';
}
if (Shiftdiff < 240) //4 hours = 4*60 = 240 min
{
msg+='Time less than 4 hrs';
}
Please help me with the logic for checking breaks and work time. Thx for any help in advance!

function validate(start, breakStart, breakEnd, end) {
var minutes = [];
for (var i = 0; i < 4; ++i) {
var time = arguments[i];
if (!/^(?:[01]\d|2[0-3])[0-5]\d$/.test(time)) {
throw new Error("Invalid time " + time);
}
var minute = minutes[i] = time.substring(0, 2) * 60 + +time.substring(2);
if (i && minute < minutes[i - 1]) { // Take into account times that cross midnight.
minutes[i] = (minute += 24*60);
}
if (i && minute <= minutes[i - 1]) {
throw new Error("Out of order " + arguments[i - 1] + " and " + time);
}
}
if (minutes[3] - minutes[0] > 8*60) { throw new Error("Shift too long"); }
if (minutes[3] - minutes[0] > 4*60) { throw new Error("Shift too short"); }
}

Related

For loop where each value is distributed correctly

I have a for loop where I want to distribute a certain number of words with the same length across a timeline.
I have variables that give me the duration for each text, the start of where the words will spawn, and the end.
var wordArray = [];
for (t = 0; t < words.length; t++) {
//This generates the textbox
wordArray[wordArray.length] = currentComp.layers.addText(words[t]);
if (t == 0) {
//This makes the first textbox appear in the start
wordArray[wordArray.length - 1].inPoint = start;
//This makes the first textbox have the length with the value that divides it by the number of words
wordArray[wordArray.length - 1].outPoint = wordArray[wordArray.length - 1].inPoint + textTime;
//Here I am trying to make them all evenly distributed by multiplying the divided duration for the number of words that are already existing
} else if (t < words.length - 2) {
wordArray[wordArray.length - 1].inPoint = start + textTime * (wordArray.length - 1);
wordArray[wordArray.length - 1].outPoint = end - textTime * (wordArray.length - 1);
} else {
//This is here to make the last word stop at the end of the text duration.
wordArray[wordArray.length - 1].inPoint = start + textTime * (wordArray.length - 1);
wordArray[wordArray.length - 1].outPoint = wordArray[wordArray.length - 1].inPoint + textTime;
}
}
The error comes in the end, as seen in the image.The word in the end (highlighted in white) has less length than the previous, and the second to last word has more length than all the other words.
I'm aware this isn't a syntax issue, rather a maths issue that I can't seem to figure out. Thanks in advance
EDIT: Found the answer and updated the syntax to match it.
I updated the syntax to match the correct code.
Turns out that The issue was that the gap for each word wasn't being calculated correctly.
I got it to work by calculating the start and the end of each section by doing this :
var startDurationString = timeCalc[0].split(":");
var finalStartDurationString = startDurationString[1] + ":" + startDurationString[2] + ":" + startDurationString[3];
var startDuration = currentFormatToTime(finalStartDurationString, currentComp.frameRate);
var endDurationString = timeCalc[1].split(":");
var finalEndDurationString = endDurationString[1] + ":" + endDurationString[2] + ":" + endDurationString[3];
var endDuration = currentFormatToTime(finalEndDurationString, currentComp.frameRate);
Then, I used the difference of the start and the end and divided by the length of the words.
durationForEachText = (endDuration-startDuration) / numberOfWords.length;
Hope it helps anyone out there.

Milliseconds in Lap Time Average dropping the Zero in Tenths place

I am using code I found on this site to average lap times in MM:SS.mmm (Averaging Times using Javascript)
It works great until the result has a zero in the tenths place. For example, the result should be 01:00.096 however, the zero is dropped and the answer is 01:00.96
I have simplified the input of 'times' to highlight the problem.
I have looked at different formatting issues, tried converting the strings to numbers and I've looked at the offsetify function thinking it was somehow interpreting the milliseconds incorrectly.
I am a novice at JavaScript with no formal training but enjoy hobby-programming. I have learned a lot from the examples on this site for use in my own little apps.
var times = ['01:00.096'];
var date = 0
var result = '';
function offsetify(t)
{
return t < 10 ? '0' + t : t;
}
for(var x = 0; x < times.length; x++ ) {
var tarr = times[x].split(':');
date += new Date(0, 0, 0, 0, tarr[0], tarr[1].split('.')[0], tarr[1].split('.')[1]).getTime();
}
var avg = new Date(date/times.length);
result = offsetify(avg.getMinutes()) + ':' + offsetify(avg.getSeconds()) + '.' + offsetify(avg.getMilliseconds());
The reason you see the 0 dropping is because in the offsetify function you have
return t < 10 ? '0' + t : t;
and you are passing it the value 96, which is not less than 10, so the function returns 96.
If you are able to find a datetime-formatting library like date-fns or moment, and you should use one, then great! Let the library do the work for you.
If you would like the practice, which is great for learning, use
s.padStart(3, '0')
for milliseconds, and
s.padStart(2, '0')
for minutes. For example, for your milliseconds:
> "5".padStart(3, "0")
'005'
> "55".padStart(3, "0")
'055'
> "383".padStart(3, "0")
'383'
Your function offsetify(t) appends a 0 in case your minutes/seconds is only single-digit - however milliseconds should be 3 digits!
You could create a new function that appends 0 if it is already 2 digits (less than 100), and 00 if it is only single-digit (less than 10) and just returns the result if it is already 3 digits.
function offsetifyMilliseconds(t)
{
return t < 10 ? '00' + t : t < 100 ? '0' + t : t;
}
and then do
result = offsetify(avg.getMinutes()) + ':' + offsetify(avg.getSeconds()) + '.' + offsetifyMilliseconds(avg.getMilliseconds());
However recent versions of Javascript (from ES2017) has access to the .padStart() function on any string:
The padStart() method pads the current string with another string (multiple times, if needed) until the resulting string reaches the given length. The padding is applied from the start (left) of the current string.
-- String.prototype.padStart() - MDN
Using this would make your code much more readable (although you'd have to convert the numeric result to a string first). You could even change your offsetify function to use this method, and prevent code duplication!
In the example below I have defined 2 as the default padding length for the method, but you can pass an additional parameter to the function when you want to use it for milliseconds:
var times = ['01:00.096'];
var date = 0
var result = '';
function offsetify(t, len = 2)
{
return t.toString().padStart(len, '0');
}
for(var x = 0; x < times.length; x++ ) {
var tarr = times[x].split(':');
date += new Date(0, 0, 0, 0, tarr[0], tarr[1].split('.')[0], tarr[1].split('.')[1]).getTime();
}
var avg = new Date(date/times.length);
var minutes = offsetify(avg.getMinutes());
var seconds = offsetify(avg.getSeconds());
var milliseconds = offsetify(avg.getMilliseconds(), 3);
result = minutes + ':' + seconds + ':' + milliseconds;
console.log(result);

Determining time remaining until bus departs

For our digital signage system, I'd like to show how long until the next bus departs. I've built the array that holds all the times and successfully (maybe not elegantly or efficiently) gotten it to change all that to show how much time is remaining (positive or negative) until each listed departure.
I need a nudge in the right direction as to how to determine which bus is next based on the current time. If there is a bus in 7 minutes, I only need to display that one, not the next one that leaves in 20 minutes.
I was thinking perhaps a for loop that looks at the array of remaining times and stops the first time it gets to a positive value. I'm concerned that may cause issues that I'm not considering.
Any assistance would be greatly appreciated.
UPDATE: Unfortunately, all the solutions provided were throwing errors on our signage system. I suspect it is running some limited version of Javascript, but thats beyond me. However, the different solutions were extremely helpful just in getting me to think of another approach. I think I've finally come on one, as this seems to be working. I'm going to let it run over the holiday and check it on Monday. Thanks again!
var shuttleOrange = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47", "12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49", "15:25", "15:51", "16:17", "16:57", "17:37", "18:17"];
var hFirst = shuttleOrange[0].slice(0,2);
var mFirst = shuttleOrange[0].slice(3,5);
var hLast = shuttleOrange[shuttleOrange.length-1].slice(0,2);
var mLast = shuttleOrange[shuttleOrange.length-1].slice(3,5);
var theTime = new Date();
var runFirst = new Date();
var runLast = new Date();
runFirst.setHours(hFirst,mFirst,0);
runLast.setHours(hLast,mLast,0);
if ((runFirst - theTime) >= (30*60*1000)) {
return "The first Orange Shuttle will depart PCN at " + shuttleOrange[0] + "."
} else if (theTime >= runLast) {
return "Orange Shuttle Service has ended for the day."
} else {
for(var i=0, l=shuttleOrange.length; i<l; i++)
{
var h = shuttleOrange[i].slice(0,2);
var m = shuttleOrange[i].slice(3,5);
var departPCN = new Date();
departPCN.setHours(h,m,0);
shuttleOrange[i] = departPCN;
}
for(var i=shuttleOrange.length-1; i--;)
{
//var theTime = new Date();
if (shuttleOrange[i] < theTime) shuttleOrange.splice(i,1)
}
var timeRem = Math.floor((shuttleOrange[0] - theTime)/1000/60);
if (timeRem >= 2) {
return "Departing in " + timeRem + " minutes."
} else if (timeRem > 0 && timeRem < 2) {
return "Departing in " + timeRem + " minute."
} else {
return "Departing now."
}
}
You only need to search once to find the index of the next scheduled time. Then as each time elapses, increment the index to get the next time. Once you're at the end of the array, start again.
A sample is below, most code is setup and helpers. It creates a dummy schedule for every two minutes from 5 minutes ago, then updates the message. Of course you can get a lot more sophisticated, e.g. show a warning when it's in the last few minutes, etc. But this shows the general idea.
window.addEventListener('DOMContentLoaded', function() {
// Return time formatted as HH:mm
function getHHmm(d) {
return `${('0'+d.getHours()).slice(-2)}:${('0'+d.getMinutes()).slice(-2)}`;
}
var sched = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47",
"12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49",
"15:25", "15:51", "16:17", "16:57", "17:37", "18:17","21:09"];
var msg = '';
var msgEl = document.getElementById('alertInfo');
var time = getHHmm(new Date());
var index = 0;
// Set index to next scheduled time, stop if reach end of schedule
while (time.localeCompare(sched[index]) > 0 && index < sched.length) {
++index;
}
function showNextBus(){
var time = getHHmm(new Date());
var schedTime;
// If run out of times, next scheduled time must be the first one tomorrow
if (index == sched.length && time.localeCompare(sched[index - 1]) > 0) {
msg = `Current time: ${time} - Next bus: ${sched[0]} tomorrow`;
// Otherwise, show next scheduled time today
} else {
// Fix index if rolled over a day
index = index % sched.length;
schedTime = sched[index];
msg = `Current time: ${time} - Next bus: ${schedTime}`;
if (schedTime == time) msg += ' DEPARTING!!';
// Increment index if gone past this scheduled time
index += time.localeCompare(schedTime) > 0? 1 : 0;
}
msgEl.textContent = msg;
// Update message each second
// The could be smarter, using setInterval to schedule running at say 95%
// of the time to the next sched time, but never more than twice a second
setInterval(showNextBus, 1000);
}
showNextBus();
}, false);
<div id="alertInfo"></div>
Edit
You're right, I didn't allow for the case where the current time is after all the scheduled times on the first running. Fixed. I also changed all the string comparisons to use localeCompare, which I think is more robust. Hopefully the comments are sufficient.
I have used filter for all shuttle left after the right time and calculated how much time left for the first one.
var shuttleOrange = ["09:01", "09:37", "10:03", "10:29", "10:55", "11:21", "11:47", "12:13", "12:39", "13:05", "13:31", "13:57", "14:23", "14:49", "15:25", "15:51", "16:17", "16:57", "17:37", "18:17"];
var d = new Date();
var h = d.getHours();
var m = d.getMinutes();
var remainShuttle = shuttleOrange.filter(bus => bus.substring(0,2) > h || (bus.substring(0,2) == h && bus.substring(3,5) > m));
var leftMinutes = (parseInt(remainShuttle[0].substring(0,2))*60 + parseInt(remainShuttle[0].substring(3,5)) - (parseInt(h) *60 + parseInt(m)));
console.log(parseInt(leftMinutes / 60) + " hours and " + leftMinutes % 60 +" minutes left for next shuttle");

Five Consecutive days excluding weekends

I have written a code that raises a flag when number of leaves taken by a person exceeds 5 business days. However, it doesn't raise the flag when we have weekend in middle. Say, someone takes leave on 23,24 and then on 27,28 and 29. As 25 and 26 are weekends, tool doesn't count it. Can someone help me on how i must check the weekend dates here and push the value as "Yes" that includes weekend dates ?
function PrepareReport(reportData) {
var vacationData = [];
var dayValuesStr = '';
var dayValuesArray = [];
if ($("#ddlfromYear").val() == $("#ddltoYear").val()) {
count = parseInt($("#ddltoMonth").val()) - parseInt($("#ddlfromMonth").val());
}
else {
count = 12 - parseInt($("#ddlfromMonth").val()) + parseInt($("#ddltoMonth").val());
}
//val.ResourceID FullName EnterpriseID WorkOrder Domain Totalhours
vacationData.push(reportData.FullName);
vacationData.push(reportData.EnterpriseID);
vacationData.push(reportData.WorkOrder);
vacationData.push(reportData.Domain);
if (reportData.IsOffshore == 1) {
vacationData.push('Offshore');
}
else {
vacationData.push('Onshore');
}
vacationData.push(reportData.TOTALHOURS);
var counter = 0;
FlagCounterLastVal = 0;
vacationData.push("No");
for (var monthNum = 0; monthNum <= count; monthNum++) {
dayValuesStr = reportData['MONTH' + monthNum];
if (dayValuesStr) {
dayValuesArray = dayValuesStr.split(',');
var countArray = dayValuesArray.length - 1;
$.each(dayValuesArray, function (key, val) {
if (val.endsWith('.00'))//round off values
{
if (parseInt(val) == 0) {
vacationData.push('-');
counter = 0; // resetting counter to 0 for non-consecutive days
}
else {
if (FlagCounterLastVal > 0) {
counter = FlagCounterLastVal;
}
counter++;
vacationData.push(parseInt(val));
****if (counter >= 5 && FlagCounterLastVal == 0) {
var index = vacationData.indexOf("No");
vacationData[index] = "Yes";
}****
if (key == (countArray) && count > 0) { // vacation taken at the month ends
FlagCounterLastVal = counter;
}
}
}
else {
vacationData.push(val);
}
});
}
}
return vacationData;
}
You can use getDay for that.
var day = yourDateObject.getDay();
var isWeekend = (day === 6) || (day === 0);
6 = Saturday, 0 = Sunday
I won't be sharing code here as it's Data Structure and would like you to think a little bit, and try yourself first. If still you won't be able to code it then I will help you out in your code.
What I would do is have 2 arrays, both will be sorted this will help in search.
1. Having all weekends dates. // weekendArr
2. Leave dates taken by employee. //leaveArr
Steps
1. delete all the weekendArr dates from leaveArr.
2. Check if leaveArr have continues dates more then 5 or what ever you want it to be.
3. If it is greater then 5 then raise a flag for that employee.
Now you need to decide what data structure you will use to maintain employee leaves, employeeID, and leave flag.
Hope this will be enough to figure out code now.

How do I get daily step count in a gear fit 2 pro web based watchface?

I am building a html/js powered watchface for the gear fit 2 pro and I'm having trouble accomplishing what seems like a simple task: getting the daily step count.
I have poured over the documentation, but it only describes how to count either steps since the watchface has started, or steps since the device has been booted. Other watchfaces immediately detect the system-wide step count and display it, but I don't see how this is possible!
Does anyone have an example of how to do this? I suspect the stepdifference or readrecorderdata functions might be involved, but the first is impossible to use due to inadequate documentation and the second does not seem to actually be present in the device.
You can setAccumulativePedometerListener() for the time period sensor data required. In you case you can reset the listener at end of the day. I've written a pseudo_code for you to show daily step count.
var sensor_data = document.getElementById("sensor-data");
var step_count=0,
offset=0, // to reduce yesterday's data
currentDailyStep=0;
function updateTime() {
var datetime = tizen.time.getCurrentDateTime(),
hour = datetime.getHours(),
minute = datetime.getMinutes(),
second = datetime.getSeconds();
if(hour === 23 && minute === 59 && second === 59){ // at the end of the day
tizen.humanactivitymonitor.unsetAccumulativePedometerListener();
tizen.humanactivitymonitor.stop("PEDOMETER");
offset = step_count; // store today's count
pedometer_init(); //reset
}
/*
* Other Codes
* ............
* .........
*/
}
function onchangedCB(pedometerInfo) {
step_count = pedometerInfo.accumulativeTotalStepCount;
currentDailyStep = step_count - offset; // totl count - total count till yesterday
sensor_data.innerHTML = currentDailyStep;
}
function pedometer_init(){
tizen.humanactivitymonitor.start("PEDOMETER");
tizen.humanactivitymonitor.setAccumulativePedometerListener(onchangedCB);
}
function init(){
pedometer_init();
}
window.onload = init();
You need to reduce offset manually as stop() function don't reset the count. Store the daily step data If you are interested to show statistics.
In addition, In Tizen Developers API References there's a Code Sample using HumanActivityRecorder to record Step count daily, Please Check If it helps:
function onerror(error){
console.log(error.name + ": " + error.message);
}
function onread(data){
for (var idx = 0; idx < data.length; ++idx)
{
console.log("*** " + idx);
console.log('totalStepCount: ' + data[idx].totalStepCount);
}
}
var type = 'PEDOMETER';
var now = new Date();
var startTime = now.setDate(now.getDate() - 7);
var anchorTime = (new Date(2000, 1, 2, 6)).getTime();
var query ={
startTime: startTime / 1000,
anchorTime: anchorTime / 1000,
interval: 1440 /* 1 day */
};
try{
tizen.humanactivitymonitor.readRecorderData(type, query, onread, onerror);
}
catch (err){
console.log(err.name + ': ' + err.message);
}

Categories

Resources