Javascript conditional time range format function - javascript

I am using React for my frontend app.
I have two different time format of data.
One is like this 08-10 and another one is like this 05:00-05:30.
Most of the time format data is like this 08-10, few are like 05:00-05:30.
After getting the time date data, I used map function and pass to my time-format helper function, In my browser I want to display my data like this 05:00-05:30.
My helper function do like this: if the time looks like this 08-10 then the function will split it into two then add : and convert them into 08:00-10:00. As I mentioned I have two different time format data, when the data come like this 05:00-05:30 then my helper function convert them like 0500-0530.
I want to render my function conditionally if the data is like 05:00-05:30 then return as it is, if the data is like this 08-10 then convert them into 08:00-10:00. I don't know how to do that in my helper function.
const toTimeRangeFormat = (range) => {
console.log(range);
const [start, end] = range?.split("-");
const toFourDigitTime = (time) => {
const [hours, minutes] = time.split(":");
return hours.padStart(2, "0") + (minutes ? minutes : ":00");
};
if (start && end) {
return toFourDigitTime(start) + " - " + toFourDigitTime(end);
}
return range;
};
const time = ["08-10", "05:00-05:30"];
time.filter((i) => {
if (typeof i === "string") {
return toTimeRangeFormat(i);
}
});
console.log(toTimeRangeFormat());

Your code seemed to work if you call it correctly
I assume you want this though
const re = /(\d{2}):?(\d{2})?/; // take the (set of) two digits from NN:NN, NNNN or NN - the ? means optional
const toFourDigitTime = time => {
const [hours, minutes] = time.match(re).slice(1); // ignore result[0]
return `${hours.padStart(2, "0")}:${minutes ? minutes : "00"}`;
};
const toTimeRangeFormat = (range) => {
const [start, end] = range ?.split("-");
if (start && end) {
return toFourDigitTime(start) + " - " + toFourDigitTime(end);
}
return range;
};
const time = ["08-10", "05:00-05:30"];
const time1 = time.map(str => toTimeRangeFormat(str));
console.log(time1);

Related

Finding performance feasibility using array strings

Here is the requirement details:
time = ["09-13", "12-14"]
getResult(time) = false
The first performance runs from 9 a.m. to 1 p.m. and the second one starts at 12 p.m. So you won't be able to see each performance in full.
time = ["07-09", "10-12", "15-19"]
getResult(time) = true
but i could not able to get the result. I am finding challange to get it done. any one help me?
here is my try:
const getResult = (time) => {
const nums = [];
let pre = 0;
time.map((item,index) => {
item.split('-').map((v,i) => {
nums.push(+v);//converting as number
});
});
const result = nums.map((v,i) => {
if(!i) return;
console.log(v-pre)//but logically this is not works
pre = v;
})
}
//time = ["09-13", "12-14"]; //false
time = ["07-09", "10-12", "15-19"] //true
getResult(time); //should be false
Thanks in advance.
Your format is already useful for direct >= comparisons, once we split the values on their -'s. So we can simply sort the values, then check that in every case after the first one, that the start portion (before the -) is at least as large as the end portion (after the -) of the previous value. It could look like this:
const feasible = (times) => [... times]
.sort ()
.every ((t, i, a) => i == 0 || t .split ('-') [0] >= a [i - 1] .split ('-') [1])
console .log (feasible (["09-13", "12-14"]))
console .log (feasible (["07-09", "10-12", "15-19"]))
We use the i == 0 || to simply avoid testing the first of the sorted values.
This involves splitting each of the values twice (well, except the first one.) If this inefficiency bothers you, we could solve it (using more memory; there's always a tradeoff!) by splitting them and saving the result:
const feasible = (times) => [... times]
.sort ()
.map (s => s .split ('-'))
.every ((t, i, a) => i == 0 || t [0] >= a [i - 1] [1])
Turn each range into each individual hour within the range, then:
if the hour already exists in the array, return false
else, push to the array
const getResult = (ranges) => {
const filled = [];
for (const range of ranges) {
let [start, end] = range.split('-').map(Number);
while (end !== start) { // Exclusive
if (filled.includes(start)) return false;
filled.push(start);
start++;
}
}
return true;
};
console.log(getResult(["09-13", "12-14"]));
console.log(getResult(["07-09", "10-12", "15-19"]));
Your current approach doesn't look to have any notion of turning the ranges into their individual hours, or of identifying overlaps.
Sort the time slots based on their start time.
Loop over all the time slots in the sorted array and if anytime the start of a slot is less than the end of the previous one, then return false.
If the whole loop is exhausted return true.
function isValid(time) {
const sortedTime = [...time].sort((a, b) => {
const slotA = Number(a.split("-")[0]);
const slotB = Number(b.split("-")[0]);
return slotA - slotB;
});
let last;
for (let t of sortedTime) {
const [start, end] = t.split("-").map(Number);
if (last && start < last) {
return false;
}
last = end;
}
return true;
}
console.log(isValid(["12-14", "09-13"]));
console.log(isValid(["10-12", "07-09", "15-19"]));

Javascript - Regex replace number with HH:MM

I am trying to replace 4 numbers with a time format. For example if user enters 1234 to be replaced with 12:34
I have found that this regex does this job
let myString = "1234";
myString.replace(/\b(\d{2})(\d{2})/g, '$1:$2')
But now I am trying to figure out how to use this with cases like
94 - this should be replaced with 23 then it does same for time after the colon
01:74 - this should be replaced with 01:59
I have found a regex which does that ^([0-1]?[0-9]|2[0-3]):[0-5][0-9], but I am not able to figure out how to combine this with .replace
You will need to match on the first and second pair of digits and then bound them by their max values. Once you have the bounded values, you can pad the numbers and join them with a colon.
const toTimeString = (value) => {
const
[, hours, minutes] = value.match(/^(\d{2})(\d{2})$/),
hour = `${Math.min(+hours, 24)}`.padStart(2, '0'),
minute = `${Math.min(+minutes, 59)}`.padStart(2, '0');
return `${hour}:${minute}`;
};
console.log(toTimeString('0174')); // 01:59
console.log(toTimeString('3412')); // 24:12
Now, here is a replacer example:
const minPad = (value, min) => `${Math.min(value, min)}`.padStart(2, '0');
const toTimeString = (value) =>
value.replace(/\b(\d{2})(\d{2})\b/g, (match, hours, minutes) =>
`${minPad(hours, 24)}:${minPad(minutes, 59)}`);
console.log(toTimeString('0174 3412')); // 01:59 24:12
There is an overload of replace which takes a function which you can use to do any logic you need, such as:
let myString = "1234";
function formatTime(input){
return input.replace(/\b(\d{2})(\d{2})/, (_,hh,mm) => {
return `${Math.min(hh,24)}:${Math.min(mm,59)}`
})
}
console.log(formatTime("1234"));
console.log(formatTime("3412"));
console.log(formatTime("0174"));
I do not see any good reason to use regex in your case.
Just a simple function will do the job.
function transformTextToHHMMTimeFormat(text) {
const firstNumber = Number(text.slice(0, 2))
const secondNumber = Number(text.slice(2, 4))
const hour = Math.min(firstNumber, 24)
const minute = Math.min(secondNumber, 59)
return `${hour}:${minute}`
}

onChange event impacts String length (Sanitizer)

I am currently working on an input label, which formats and fixes an user input to a correct date-time format.
Currently, nothing except digits will be formatted to a date.
For instance: 11302020 => 11 / 30 / 2020
Now I want to set a range the string parts for day, month, year.
If a user exceeds the limit, the number (or part of the string) will be sanitized.
My function chops the input string into chunks, so I can write the values into a new array.
However, at the end my chopped array has a) size of 6 and b) an overall char length with blanks of 15. When I put these conditions in an if-question to save these values in separate parts, it starts saving at a char length of 16, which means, after an user enters the full date and an additional char, which is not what I want with my (b). Can someone help me out?
import React, { useState } from "react";
// export const dateFormatter = (input) => {
// return input;
// };
export default function App() {
const [maskedState, setMaskedState] = useState("");
const dateFormatter = (date) => {
setMaskedState(date.replace(/\D/g, "")
.replace(/(\d{2})(\d)/, " $1 / $2")
.replace(/(\d{2})(\d)/, "$1 / $2")
.replace(/(\d{4})\d+?$/, "$1"));
const maskedStateStr = maskedState.split(" ");
const charLength = 15;
const arrLength = 6;
if ((maskedStateStr.length === arrLength) && (maskedState.length === charLength)){
maskedStateStr.shift();
var day = maskedStateStr[0];
var month = maskedStateStr[2];
var year = maskedStateStr[4];
console.log(day,month,year);
}
//console.log(maskedStateStr, maskedStateStr.length, maskedState, maskedState.length)
}
const handleInput = (date) => {
const inputValue = date.target.value;
dateFormatter(inputValue);
};
return (
<div className="App">
<input onChange={handleInput} value={maskedState} />
</div>
);
}
There are so many issues with that code but I only focus on react part of it.
setMaskedState doesn't update maskedState immediately so maskedState will most likely point to a stale state.
setting value on an input renders it uneditable so you don't even see what you're typing. Use defaultValue.
That said you should operate on the date value and only set the state at the end of your block to reflect the result. Like:
export default function App() {
const [maskedState, setMaskedState] = useState(null);
const dateFormatter = value => {
let formattedDate = value
.replace(/\D/g, "")
.replace(/(\d{2})(\d)/, " $1 / $2")
.replace(/(\d{2})(\d)/, "$1 / $2")
.replace(/(\d{4})\d+?$/, "$1");
const maskedStateStr = formattedDate.split(" ");
const charLength = 15;
const arrLength = 6;
if (
maskedStateStr.length === arrLength &&
formattedDate.length === charLength
) {
maskedStateStr.shift();
let day = maskedStateStr[0];
let month = maskedStateStr[2];
let year = maskedStateStr[4];
setMaskedState(`${day} / ${month} / ${year}`);
} else {
setMaskedState(value);
}
};
const handleInput = date => {
const inputValue = date.target.value;
dateFormatter(inputValue);
};
return (
<div className="App">
<input onChange={handleInput} value={maskedState} />
<pre>
<code>
{maskedState
? JSON.stringify(maskedState, null, 2)
: "Not a valid date yet"}
</code>
</pre>
</div>
);
}
See the demo on StackBlitz

Check If a given time(Only hours:minutes) lies betwenn two other different time?

I have 2 different times:
var shiftStartTime = "05:48";
var shiftEndTime = "14:29";
And i have another time which is selectedDate ="06:20"(this will change according datetimepicker selection), and i want to check if selectedDate should be between (shiftStartTime and shiftEndTime ).
Can anyone help in this?
Updated Code:
i have 6 different timespan like below
var shift1StartTime = "05:48";
var shift1EndTime = "14:18";
var shift2StartTime = "14:30";
var shift2EndTime = "22:29";
va
r shift3StartTime = "22:30";
var shift3EndTime = "05:47";
using all 6 timespan i want to check the if the given time is between (shift1StartTime and shift1EndTime) return shift1
Or
if the given time is between (shift2StartTime and shift2EndTime) return shift2
Or
if the given time is between (shift3StartTime and shift3EndTime) return shift3
Simply compare the strings like
var shiftStartTime = "05:48"; var shiftEndTime = "14:29";
shiftStartTime > shiftEndTime // false
Here is some JS that does this, although better formatted time would make it a lot easier
function findTotalTime(time) {
hours = parseInt(time.substring(0,2))
mins = parseInt(time.substring(3,5))
return (hours*60) + mins
}
startTime = findTotalTime(shiftStartTime)
endTime = findTotalTime(shiftEndTime)
selectedTime = findTotalTime(selectedDate)
if (selectedTime > startTime && selectedTime < endTime) {
// time is inbetween shifts
}
const date = new Date();
const shiftStartTime = '05:48';
const shiftEndTime = '14:29';
const selectedDate = '14:20';
const start = date.setHours(+shiftStartTime.split(':')[0], +shiftStartTime.split(':')[1], 0, 0);
const end = date.setHours(+shiftEndTime.split(':')[0], +shiftEndTime.split(':')[1], 0, 0);
const selected = date.setHours(+selectedDate.split(':')[0], +selectedDate.split(':')[1], 0, 0);
if (start < selected && selected < end) {
console.log(true);
} else {
console.log(false);
}
Alright, so you got three relative times as strings in the format HH:mm. I'm assuming that your times are given as 24h strings / military time, because otherwise, you'd need an A.M. / P.M. specifier.
It is always useful to have the data you are working with in a well-suited machine-readable format, so you could parse them into a simple object holding the hour and minute as numbers.
A function doing this could look like this.
function parseTimeStr(time) {
// The pattern of your input,
// allows spaces around the `:`
// and single-digit inputs like `8:00`
let re = /([0-9][0-9]?)\s*:\s*([0-9][0-9]?)/;
let result = re.exec(time.trim());
if (result === null) {
throw "No match"
}
let hour = parseInt(result[1], 10);
let minute = parseInt(result[2], 10);
/* handle out of range values here */
return { hour, minute };
}
Alright, so you have these objects now. How do you compare them? There's a pattern for that: Have a function returning whether the first argument is greater (1), equal (0), or less (-1) than the second.
Writing this is simple now that the time is an object:
function cmpDate(date1, date2) {
if (date1.hour > date2.hour) {
return 1;
} else if (date1.hour < date2.hour) {
return -1;
} else if (date1.minute > date2.minute) {
return 1;
} else if (date1.minute < date2.minute) {
return -1;
} else {
return 0;
}
}
Alright, now we can have a helper function checking if the first argument is in the closed interval defined by the last two arguments:
function isInShift(time, shiftStart, shiftEnd) {
// time is greater or equal shiftStart
// and less or equal shiftEnd
return cmpDate(time, shiftStart) !== -1 && cmpDate(time, shiftEnd) !== 1;
}
You can then finally make your comparison by calling isInShift(parseTimeStr(selectedTime), parseTimeStr(shiftStartTime), parseTimeStr(shiftEndTime)). This will return a boolean. You can easily extend this infrastructure for multiple shifts.
Be aware that both reality and your users can be more ... screwy than you'd expect.
The above code does not do error handling for invalid time inputs, neither does it account for overnight shifts, but these are details that you can easily work out, you just have to put some effort into thinking of them.

add leading zero to simple timestamp addition JavaScript function

I am trying to write a javascript function to sum up two timestamp strings, like 00:04:02 and 00:05:43
I have this function which works, but returns a value like: 0:9:45, I'm trying to improve it so there is a leading zero for the minutes section so it looks more like: 0:09:45 but im having trouble doing so and was wondering if anyone could help me:
function sum(date1, date2){
date1 = date1.split(":");
date2 = date2.split(":");
const result = [];
date1.reduceRight((carry,num, index) => {
const max = [24,60,60][index];
const add = +date2[index];
result.unshift( (+num+add+carry) % max );
return Math.floor( (+num + add + carry) / max );
},0);
return result.join(":");
}
console.log(sum('00:05:43', '00:04:02'))
Pad each digit?
return result.map(r => String(r).padStart(2, "0")).join(":");
If you use the built-in Date methods, you don't need to parse times or do math yourself.
'use strict';
function sumTimestamps(a, b) {
const [A, B] = [a, b].map((x) => new Date('1970-01-01T' + x + '.000Z'));
return new Date(A.getTime() + B.getTime()).toUTCString().split(' ')[4];
}
const sum = sumTimestamps('00:04:02', '00:05:43');
console.log(sum);
// => 00:09:45

Categories