Starting time in the program is not working properly - javascript

I have a function returnTimesInBetween. It's taking two values (start, end) as parameters and returns the time array by splitting in the 30 minutes of the time frame. the problem is when the start time is ending with 30 minutes like "12:30,11:30,15:30" it's not taking that value in the time frame and when the start time is like 11:00, 12:00, etc it's working fine.
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
if (startM == 30)
startH++;
for (var i = startH ; i < endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00")
timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30");
}
if (endM == 00)
timesInBetween.push(endH + ":30");
if (endM == 30)
timesInBetween.push(endH + ":30")
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));
console output are
[]0: "12:00"
1: "12:30"
2: "13:00"
3: "13:30"
4: "14:00"
5: "14:30"
6: "15:30"
length: 7[[Prototype]]: Array(0)
[]0: "18:00"
1: "18:30"
2: "19:00"
3: "19:30"
4: "20:00"
5: "20:30"
6: "21:30"
length: 7[[Prototype]]: Array(0)
How can i add the starting time even if it's ending with 30 minute hand.

You need a condition just for the first iteration, when starM is not 30.
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end) {
var timesInBetween = [];
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
for (var i = startH; i < endH; i++) {
// Add a condition here for the first iteration only
if (i === startH && startM !== 30) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
}
timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30");
}
if (endM == 0) timesInBetween.push(endH + ":30");
if (endM == 30) timesInBetween.push(endH + ":30");
return timesInBetween; // Was missing ;)
}
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));

Another approach I like when working with time, instead of working with hour, minute (and second) separately, crunch them into a single number (in this case minutes) and do all calculation with the number. Only convert back to human-readable format when finish computing. This way you avoid making mistake when changing one component and forget the other. This applies to other non-base 10 system as well.
function returnTimesInBetween(start, end)
{
let result = [];
const s = start.split(":").reduce((a,c) => a * 60 + Number(c));
const e = end.split(":").reduce((a,c) => a * 60 + Number(c));
const mod = (s % 30);
for(let i = s + (mod ? 30 - mod : 0) ; i <= e; i += 30)
{
const h = Math.floor(i/60);
const m = i % 60;
result.push(`0${h}`.slice(-2) + ":" + `0${m}`.slice(-2) );
}
return result;
}
console.log(returnTimesInBetween("11:00","15:29"));
console.log(returnTimesInBetween("11:00","15:30"));
console.log(returnTimesInBetween("11:29","15:30"));
console.log(returnTimesInBetween("11:30","15:30"));
console.log(returnTimesInBetween("11:31","15:30"));

Just for fun I wanted to see if I could produce a compact method to achieve this. This method uses a lot of shorthand syntax and could be difficult to follow. However, the premise is to convert the times into decimals, ie: 11:30 becomes 11.5, 21:00 becomes 21. The + preceding the h and m, in the reduce function, is shorthand to convert the string to a number.
We can then define an array of a given size by deducting the endtime-decimal from our starttime-decimal and multiplying by 2. Then we fill the array with incrementing 0.5 decimal numbers ie. 11.5, 12, 12.5, 13...
Finally map the array to convert back to a time-string format. Again this uses techniques like the bit operator | which return a whole number and the modulo operator (also called remainder) % which returns a remainder, in this case 0 or 0.5.
let splitTime = (start, end) => {
let shm = start.split(":").reduce((h,m) => +h + (+m/60)) - 0.5,
ehm = end.split(":").reduce((h,m) => +h + (+m/60));
return Array((ehm - shm) * 2).fill().map(_ => shm+=0.5)
.map(hm => (hm | 0) + ':' + (hm % 1 ? "30" : "00"));
}
console.log(splitTime("11:30", "15:30"));
console.log(splitTime("18:00", "21:00"));
console.log(splitTime("9:00", "23:30"));
console.log(splitTime("10:30", "14:00"));

Your condition on the for loop should be i <= endH; and you can use th if condition according to your need of the output.
for (var i = startH ; i <= endH; i++) {
From what i understand your expected output is:
("11:30", "15:30") => ["11:00","11:30","12:00","12:30","13:00","13:30","14:00","14:30","15:00","15:30"]
("18:00", "21:30") => [ "18:00","18:30","19:00","19:30","20:00","20:30","21:00","21:30" ]
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
for (var i = startH ; i <= endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
(i == endH && endM == 30) ? timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30") : '';
}
return timesInBetween;
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:00"));
console.log(returnTimesInBetween("11:30", "15:30"));
console.log(returnTimesInBetween("18:00", "21:30"));
Or
if you are expecting somthing like this, just add the if condition:
["11:30","12:00","12:30","13:00","13:30","14:00","14:30","15:00","15:30"]
["18:00","18:30","19:00","19:30","20:00","20:30","21:00","21:30"]
//DIVIDING THE TIME FRAME IN 30 MINUTES OF THE TIME FRAME.
function returnTimesInBetween(start, end)
{
var timesInBetween = ([]);
console.log(timesInBetween);
var startH = parseInt(start.split(":")[0]);
var startM = parseInt(start.split(":")[1]);
var endH = parseInt(end.split(":")[0]);
var endM = parseInt(end.split(":")[1]);
if (startM == 30) {
timesInBetween.push(startH < 10 ? "0" + startH + ":30" : startH + ":30");
startH++;
}
for (var i = startH ; i <= endH; i++) {
timesInBetween.push(i < 10 ? "0" + i + ":00" : i + ":00");
(i == endH && endM == 30) ? timesInBetween.push(i < 10 ? "0" + i + ":30" : i + ":30") : '';
}
return timesInBetween;
}
console.log('time range:-')
console.log(returnTimesInBetween("11:30", "15:00"));
console.log(returnTimesInBetween("18:00", "21:30"));

Related

Calculate the nearest value on a circular variable

I have an problem where i have 3 times of the 24 hour day. To keep it simple i can use the decimal representation:
a) 23:45 (23.75)
b) 11:30 (11.50)
c) 00:15 (00.25)
I'd like to know , for each time, which other time is closest.
var closestTime = 24
var closestActualTime = 0;
for (var i = 0; i < times.length; i++) {
if (times[i].time == this.time) continue;
var temp = Math.abs(this.time - times[i].time)
if (temp < closestTime) {
closestTime = temp;
closestActualTime = times[i].time;
}
}
My issue is that 23:45 and 00:25 are actually really close but i don't know how process a variable with a modulo type
I suggest to build a list with the pairs and then calculate the difference.
The difference is the third element in the pairs array.
Basically you need to check the delta and if it greater than 12 hours, take the difference from 24 and delta.
delta = Math.abs(aa - bb);
if (delta > 12) {
delta = 24 - delta;
}
function combination(array, size) {
function c(part, start) {
var i, l, p;
for (i = start, l = array.length + part.length + 1 - size; i < l; i++) {
p = part.slice();
p.push(array[i]);
p.length < size ? c(p, i + 1) : result.push(p);
}
}
var result = [];
c([], 0);
return result;
}
function timeDelta(a, b) {
function decimalTime(s) {
var p = s.split(':');
return +p[0] + p[1] / 60;
}
function padZero(v) {
return (v < 10) ? '0' + v : String(v);
}
var aa = decimalTime(a),
bb = decimalTime(b),
delta = Math.abs(aa - bb);
if (delta > 12) {
delta = 24 - delta;
}
return padZero(Math.floor(delta)) + ':' + padZero(Math.round(60 * (delta - Math.floor(delta))));
}
var times = ['23:45', '11:30', '00:15'],
pairs = combination(times, 2);
pairs.forEach(function (a, i, aa) {
aa[i][2] = timeDelta(a[0], a[1]);
});
console.log(pairs);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop over times.
Try combinations of delta time, offset by 24 hours.
Pick smallest delta time.
var times = [23.75, 11.50, 3, 6, 7];
/**
* timeClosestTo
*
* #param {number} time
* #returns {number}
*/
function timeClosestTo(time) {
//Distance variable to compare against
var distance = 100;
//Hours in a day
var day = 24;
//Current best
var best = null;
//Test against all times
for (var i = 0; i < times.length; i++) {
//Find best score based upon day
var d = Math.min(Math.abs((times[i]) - (time)), Math.abs((times[i] + day) - time), Math.abs((times[i]) - (time + day)), Math.abs((times[i] + day) - (time + day)));
//If best found distance yet, set best to current
if (d < distance) {
best = times[i];
distance = d;
}
}
//Return best
return best;
}
console.log("times to deal with:",times.join(", "));
console.log("closest to 1:", timeClosestTo(1), "closest to 11:", timeClosestTo(11), "closest to 5:", timeClosestTo(5));
Quite functionally i would do this job as follows
var times = [23.75,11.50,0.25],
diffs = times.reduce((d,t1,i,a) => a[i+1] ? d.concat(a.slice(i+1)
.map(t2 => [t1,t2,[Math.min(Math.abs(t1-t2),24-Math.abs(t1-t2))]
.map(n => ~~n + ":" + (n%1)*60)[0]]))
: d,[]);
console.log(diffs);

How to integrate loops with arrays?

I'm prompting the user to enter a number between 50 and 100.
(Default value for the prompt is 100.)
The input, minus one, is then displayed on the screen followed by spaces.
Fore example, if user enters 60, this is what I want to be displayed:
01 02 03 04
05 06 07 08
...
53 54 55 56
57 58 59
So far I'v done the following, but I can't figure out the problem or what to do next:
num = Number(prompt("Please enter a number between 50 and 100"));
var arr= new Array(parseInt(arrayLength));
for (var i = 0; i < array.length; i++) {
document.getElementById("myDiv").innerHTML = arr[i];
}
You can just parseInt on the return value from the "prompt", and then you can create an array that is mappable. Once that is done, you can just join the entire array with a space, which will give you 1 2 3 ... etc.
If you are looking for the most basic format where there are no line-breaks, this is a simple version:
var num = parseInt(prompt('Please enter a number between 50 and 100')) || 100;
var arr = Array.apply(null, Array(num - 1))
.map(function(x, i) {
return i + 1;
});
document.getElementById("myDiv").innerHTML = arr.join(' ');
<div id="myDiv"></div>
Otherwise, if you are looking for the more complex formatting and with the line breaks, here is the same concept modified a little bit:
var num = parseInt(prompt('Please enter a number between 50 and 100')) || 100;
var arr = Array.apply(null, Array(num - 1))
.map(function(x, i) {
var actual = i + 1;
if (actual < 10) {
actual = '0' + actual;
}
if (i % 4 === 3) {
actual += '<br>';
}
return actual;
});
document.getElementById("myDiv").innerHTML = arr.join(' ');
<div id="myDiv"></div>
You can concatenate a string with the numbers and then set the innerHtml of your div to that string:
num = Number(prompt("Please enter a number between 50 and 100"));
var result = "";
for (var i = 1; i < num; i++) {
result += i + " ";
}
document.getElementById("myDiv").innerHTML = result;
If you want the numbers 1-9 to be displayed like 01 02 03... you can do so with this version:
num = Number(prompt("Please enter a number between 50 and 100"));
var result = "";
for (var i = 1; i < num; i++) {
if(i < 10){
result += "0" + i + " ";
}else{
result += i + " ";
}
}
document.getElementById("myDiv").innerHTML = result;
See this Fiddle as reference.
This is how I would do it. I don't know why you need the array?
Just loop from start to end and add spaces after each number (while padding it) and add line breaks after every 4th number.
var num = Number(prompt("Please enter a number between 50 and 100")) || 100;
document.getElementById("myDiv").innerHTML = generateText(num, 4);
function generateText(n, cols) {
var result = '';
for (var i = 1; i < n; i++) {
result += pad(i, 2, '0') + ' ';
if (i % cols === 0) {
result += '<br />';
}
}
return result;
}
function pad(val, n, ch) {
val = '' + val;
while (val.length < n) {
val = ch + val;
}
return val;
}
<div id="myDiv"></div>
Since we are going for brevity here. /s
Here is some "code golf" to scratch your itch :)
var num = Number(prompt("Please enter a number between 50 and 100")) || 100;
num = num < 50 ? 50 : (num > 100 ? 100 : num);
document.getElementById('myDiv').innerHTML = Array
.apply(null, Array(num - 1))
.map(function(x, i) { return (i < 9 ? '0' : '') + (i + 1); })
.reduce(function(s, x, i) { return s + x + (i % 4 === 3 ? '<br />' : ' '); }, '');
<div id="myDiv"></div>

Converting Youtube Data API V3 video duration format to seconds in JavaScript/Node.js

I'm trying to convert ISO 8601 string to seconds in JS/Node. The best I could come up with was:
function convert_time(duration) {
var a = duration.match(/\d+/g)
var duration = 0
if(a.length == 3) {
duration = duration + parseInt(a[0]) * 3600;
duration = duration + parseInt(a[1]) * 60;
duration = duration + parseInt(a[2]);
}
if(a.length == 2) {
duration = duration + parseInt(a[0]) * 60;
duration = duration + parseInt(a[1]);
}
if(a.length == 1) {
duration = duration + parseInt(a[0]);
}
return duration
}
It works when I input strings such as "PT48S", "PT3M20S" or "PT3H2M31S", but fails miserably if the string is "PT1H11S". Does anyone have a better idea?
If you're using moment.js you can simply call...
moment.duration('PT15M33S').asMilliseconds();
= 933000 ms
EDIT 2021: While this works, and still gets upvotes, I wouldn't advise including moment.js just for this. I'd recommend using a regex answer like #redgetan's
function YTDurationToSeconds(duration) {
var match = duration.match(/PT(\d+H)?(\d+M)?(\d+S)?/);
match = match.slice(1).map(function(x) {
if (x != null) {
return x.replace(/\D/, '');
}
});
var hours = (parseInt(match[0]) || 0);
var minutes = (parseInt(match[1]) || 0);
var seconds = (parseInt(match[2]) || 0);
return hours * 3600 + minutes * 60 + seconds;
}
works for these cases:
PT1H
PT23M
PT45S
PT1H23M
PT1H45S
PT23M45S
PT1H23M45S
I suggest this little hack to prevent your problematic case:
function convert_time(duration) {
var a = duration.match(/\d+/g);
if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) {
a = [0, a[0], 0];
}
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) {
a = [a[0], 0, a[1]];
}
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) {
a = [a[0], 0, 0];
}
duration = 0;
if (a.length == 3) {
duration = duration + parseInt(a[0]) * 3600;
duration = duration + parseInt(a[1]) * 60;
duration = duration + parseInt(a[2]);
}
if (a.length == 2) {
duration = duration + parseInt(a[0]) * 60;
duration = duration + parseInt(a[1]);
}
if (a.length == 1) {
duration = duration + parseInt(a[0]);
}
return duration
}
Fiddle
Here's my solution:
function parseDuration(duration) {
var matches = duration.match(/[0-9]+[HMS]/g);
var seconds = 0;
matches.forEach(function (part) {
var unit = part.charAt(part.length-1);
var amount = parseInt(part.slice(0,-1));
switch (unit) {
case 'H':
seconds += amount*60*60;
break;
case 'M':
seconds += amount*60;
break;
case 'S':
seconds += amount;
break;
default:
// noop
}
});
return seconds;
}
My solution:
function convert_time(duration) {
var total = 0;
var hours = duration.match(/(\d+)H/);
var minutes = duration.match(/(\d+)M/);
var seconds = duration.match(/(\d+)S/);
if (hours) total += parseInt(hours[1]) * 3600;
if (minutes) total += parseInt(minutes[1]) * 60;
if (seconds) total += parseInt(seconds[1]);
return total;
}
Fiddle
You can find a very simple PHP solution here - How To Convert Youtube API Time (ISO 8601 String Video Duration) to Seconds In PHP - Code
This function convert_time() takes one parameter as input - the Youtube API Time (Video Duration) which is in ISO 8601 string format and returns its duration in seconds.
function convert_time($str)
{
$n = strlen($str);
$ans = 0;
$curr = 0;
for($i=0; $i<$n; $i++)
{
if($str[$i] == 'P' || $str[$i] == 'T')
{
}
else if($str[$i] == 'H')
{
$ans = $ans + 3600*$curr;
$curr = 0;
}
else if($str[$i] == 'M')
{
$ans = $ans + 60*$curr;
$curr = 0;
}
else if($str[$i] == 'S')
{
$ans = $ans + $curr;
$curr = 0;
}
else
{
$curr = 10*$curr + $str[$i];
}
}
return($ans);
}
Testing Some Inputs:
"PT2M23S" => 143
"PT2M" => 120
"PT28S" => 28
"PT5H22M31S" => 19351
"PT3H" => 10800
"PT1H6M" => 3660
"PT1H6S" => 3606
Here's #redgetan 's solution in ES6.
I also fixed it for years, weeks and days.
https://www.digi.com/resources/documentation/digidocs/90001437-13/reference/r_iso_8601_duration_format.htm
// Copied from:
// https://stackoverflow.com/questions/22148885/converting-youtube-data-api-v3-video-duration-format-to-seconds-in-javascript-no
function parseISO8601Duration(duration) {
const match = duration.match(/P(\d+Y)?(\d+W)?(\d+D)?T(\d+H)?(\d+M)?(\d+S)?/)
// An invalid case won't crash the app.
if (!match) {
console.error(`Invalid YouTube video duration: ${duration}`)
return 0
}
const [
years,
weeks,
days,
hours,
minutes,
seconds
] = match.slice(1).map(_ => _ ? parseInt(_.replace(/\D/, '')) : 0)
return (((years * 365 + weeks * 7 + days) * 24 + hours) * 60 + minutes) * 60 + seconds
}
if (parseISO8601Duration('PT1H') !== 3600) {
throw new Error()
}
if (parseISO8601Duration('PT23M') !== 1380) {
throw new Error()
}
if (parseISO8601Duration('PT45S') !== 45) {
throw new Error()
}
if (parseISO8601Duration('PT1H23M') !== 4980) {
throw new Error()
}
if (parseISO8601Duration('PT1H45S') !== 3645) {
throw new Error()
}
if (parseISO8601Duration('PT1H23M45S') !== 5025) {
throw new Error()
}
if (parseISO8601Duration('P43W5DT5M54S') !== 26438754) {
throw new Error()
}
if (parseISO8601Duration('P1Y43W5DT5M54S') !== 57974754) {
throw new Error()
}
I've written a CoffeeScript variation (you can easily compile it at coffeescript.org when desired)
DIFFERENCE: the returning duration comes in a human readable format (e.g. 04:20, 01:05:48)
String.prototype.parseDuration = ->
m = #.match /[0-9]+[HMS]/g
res = ""
fS = fM = !1
for part in m
unit = part.slice -1
val = part.slice 0, part.length - 1
switch unit
when "H" then res += val.zeros( 2 ) + ":"
when "M"
fM = 1
res += val.zeros( 2 ) + ":"
when "S"
fS = 1
res += if fM then val.zeros 2 else "00:" + val.zeros 2
if !fS then res += "00"
res
I've also implemented this helper function to fill < 10 values with a leading zero:
String.prototype.zeros = ( x ) ->
len = #length
if !x or len >= x then return #
zeros = ""
zeros += "0" for [0..(x-len-1)]
zeros + #
3nj0y!!!
I realize eval is unpopular, but here's the easiest and fastest approach I can imagine. Enjoy.
function formatDuration(x) {
return eval(x.replace('PT','').replace('H','*3600+').replace('M','*60+').replace('S', '+').slice(0, -1));
}
I think using moment.js will be an easier solution. But if someone is looking for a custom solution, here is a simple regex one for you:
var regex = /PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/;
var regex_result = regex.exec("PT1H11S"); //Can be anything like PT2M23S / PT2M / PT28S / PT5H22M31S / PT3H/ PT1H6M /PT1H6S
var hours = parseInt(regex_result[1] || 0);
var minutes = parseInt(regex_result[2] || 0);
var seconds = parseInt(regex_result[3] || 0);
var total_seconds = hours * 60 * 60 + minutes * 60 + seconds;
I ran into issues with the above solution. I decided to write it as obtuse as possible. I also use my own "getIntValue" in place of parseInt for extra sanity.
Just thought other searching might appreciate the update.
Fiddle
function convertYouTubeTimeFormatToSeconds(timeFormat) {
if ( timeFormat === null || timeFormat.indexOf("PT") !== 0 ) {
return 0;
}
// match the digits into an array
// each set of digits into an item
var digitArray = timeFormat.match(/\d+/g);
var totalSeconds = 0;
// only 1 value in array
if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') == -1) {
totalSeconds += getIntValue(digitArray[0]) * 60 * 60;
}
else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') == -1) {
totalSeconds += getIntValue(digitArray[0]) * 60;
}
else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') > -1) {
totalSeconds += getIntValue(digitArray[0]);
}
// 2 values in array
else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') == -1) {
totalSeconds += getIntValue(digitArray[0]) * 60 * 60;
totalSeconds += getIntValue(digitArray[1]) * 60;
}
else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') == -1 && timeFormat.indexOf('S') > -1) {
totalSeconds += getIntValue(digitArray[0]) * 60 * 60;
totalSeconds += getIntValue(digitArray[1]);
}
else if (timeFormat.indexOf('H') == -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') > -1) {
totalSeconds += getIntValue(digitArray[0]) * 60;
totalSeconds += getIntValue(digitArray[1]);
}
// all 3 values
else if (timeFormat.indexOf('H') > -1 && timeFormat.indexOf('M') > -1 && timeFormat.indexOf('S') > -1) {
totalSeconds += getIntValue(digitArray[0]) * 60 * 60;
totalSeconds += getIntValue(digitArray[1]) * 60;
totalSeconds += getIntValue(digitArray[2]);
}
// console.log(timeFormat, totalSeconds);
return totalSeconds;
}
function getIntValue(value) {
if (value === null) {
return 0;
}
else {
var intValue = 0;
try {
intValue = parseInt(value);
if (isNaN(intValue)) {
intValue = 0;
}
} catch (ex) { }
return Math.floor(intValue);
}
}
Python
It works by parsing the input string 1 character at a time, if the character is numerical it simply adds it (string add, not mathematical add) to the current value being parsed.
If it is one of 'wdhms' the current value is assigned to the appropriate variable (week, day, hour, minute, second), and value is then reset ready to take the next value.
Finally it sum the number of seconds from the 5 parsed values.
def ytDurationToSeconds(duration): #eg P1W2DT6H21M32S
week = 0
day = 0
hour = 0
min = 0
sec = 0
duration = duration.lower()
value = ''
for c in duration:
if c.isdigit():
value += c
continue
elif c == 'p':
pass
elif c == 't':
pass
elif c == 'w':
week = int(value) * 604800
elif c == 'd':
day = int(value) * 86400
elif c == 'h':
hour = int(value) * 3600
elif c == 'm':
min = int(value) * 60
elif c == 's':
sec = int(value)
value = ''
return week + day + hour + min + sec
This is not java specific, but i would like to add JAVA snippet as that may helpful to other users
String duration = "PT1H23M45S";
Pattern pattern = Pattern.compile("PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?");
Matcher matcher = pattern.matcher(duration);
long sec = 0;
long min = 0;
long hour = 0;
if (matcher.find())
{
if(matcher.group(1)!=null)
hour = NumberUtils.toInt(matcher.group(1));
if(matcher.group(2)!=null)
min = NumberUtils.toInt(matcher.group(2));
if(matcher.group(3)!=null)
sec = NumberUtils.toInt(matcher.group(3));
}
long totalSec = (hour*3600)+(min*60)+sec;
System.out.println(totalSec);
Assuming the input is valid, we can use the regex exec method to iterate on the string and extract the group sequentially:
const YOUTUBE_TIME_RE = /(\d+)([HMS])/g;
const YOUTUBE_TIME_UNITS = {
'H': 3600,
'M': 60,
'S': 1
}
/**
* Returns the # of seconds in a youtube time string
*/
function parseYoutubeDate(date: string): number {
let ret = 0;
let match: RegExpExecArray;
while (match = YOUTUBE_TIME_RE.exec(date)) {
ret += (YOUTUBE_TIME_UNITS[match[2]]) * Number(match[1]);
}
return ret;
}
ES6:
const durationToSec = formatted =>
formatted
.match(/PT(?:(\d*)H)?(?:(\d*)M)?(?:(\d*)S)?/)
.slice(1)
.map(v => (!v ? 0 : v))
.reverse()
.reduce((acc, v, k) => (acc += v * 60 ** k), 0);
Kotlin version:
private val youtubeDurationPattern: Pattern =
Pattern.compile("PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?")
fun String.parseDuration(): Int {
val matcher: Matcher = youtubeDurationPattern.matcher(this)
if (!matcher.find()) {
throw IllegalStateException("Cannot parse $this.")
}
val hour = matcher.group(1)?.toInt() ?: 0
val min = matcher.group(2)?.toInt() ?: 0
val sec = matcher.group(3)?.toInt() ?: 0
return hour * 3600 + min * 60 + sec
}
and test:
#Test
fun testParseDuration() {
assertEquals(10 * 60, "PT10M".parseDuration())
assertEquals(10 * 60 + 30, "PT10M30S".parseDuration())
assertEquals(30, "PT30S".parseDuration())
assertEquals(2 * 3600 + 3 * 60 + 16, "PT2H3M16S".parseDuration())
}

Add two timestamps of format "HH+:MM:SS"

So basically i have two strings of timestamps which i want to add:
a = "00:10:12";
aParts = a.split(/:/);
b = "00:30:34";
bParts = b.split(/:/);
time1 = 3600000 * parseInt(aParts[0]) + 60000 * parseInt(aParts[1]) + 1000 * parseInt(aParts[2]);
time2 = 3600000 * parseInt(bParts[0]) + 60000 * parseInt(bParts[1]) + 1000 * parseInt(bParts[2]);
dateTime = time1 + time2;
hours = parseInt(dateTime/3600000);
dateTime = parseInt(dateTime%3600000);
minutes = parseInt(dateTime/60000);
dateTime = parseInt(dateTime%60000);
seconds = parseInt(dateTime/1000);
newTime = addLeadingZeros(hours,2) + ':' + addLeadingZeros(minutes,2) + ':' + addLeadingZeros(seconds,2);
// returns correct "00:40:46"
function addLeadingZeros (n, length){
var str = (n > 0 ? n : -n) + "";
var zeros = "";
for (var i = length - str.length; i > 0; i--)
zeros += "0";
zeros += str;
return n >= 0 ? zeros : "-" + zeros;
}
While writing this question i managed to come up with the above code :-) that works somehow - is that a proper way of adding two string timestamps or is there a better approach?
Forgot to mention - i did try converting the two strings into Date objects and using .getTime() adding the two datetimes - but that gives me a wrong time in the date.
There is nothing notably wrong with your code, but be sure to set the radix when using parseInt
radix
An integer that represents the radix of the value to parse. Always
specify this parameter to eliminate reader confusion
and to guarantee predictable behavior. Different implementations
produce different results when a radix is not specified.
There is no standard method for performing the task that you have described.
Here is an example that I have used in the past.
Javascript
/*jslint maxerr: 50, indent: 4, browser: true, devel: true */
(function () {
"use strict";
function zeroPad(num) {
var str = num.toString();
if (num < 2) {
str = "0" + str;
}
return str;
}
function addTimes() {
if (!arguments.length) {
throw new SyntaxError("No arguments provided.");
}
var total = {
hours: 0,
minutes: 0,
seconds: 0
},
argIndex,
argLength,
time,
parts,
part,
partIndex,
temp;
for (argIndex = 0, argLength = arguments.length; argIndex < argLength; argIndex += 1) {
time = arguments[argIndex];
if (typeof time !== "string") {
throw new TypeError("Argument must be a string.");
}
parts = time.split(":");
if (parts.length !== 3) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
for (partIndex = 0; partIndex < 3; partIndex += 1) {
part = parts[partIndex];
if (partIndex < 2) {
if (part === "" || !/^\d*$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseInt(part, 10);
} else {
if (part === "" || !/^\d*\.?\d+$/.test(part)) {
throw new SyntaxError("Argument is incorrectly formatted.");
}
parts[partIndex] = parseFloat(part);
}
}
temp = (parts[2] + total.seconds);
total.seconds = temp % 60;
temp = (parts[1] + total.minutes) + (temp - total.seconds) / 60;
total.minutes = temp % 60;
total.hours = (parts[0] + total.hours) + (temp - total.minutes) / 60;
}
return zeroPad(total.hours) + ":" + zeroPad(total.minutes) + ":" + zeroPad(total.seconds);
}
var a = "00:10:12",
b = "00:30:34",
c = "10:40:40";
console.log(addTimes(a, b, c));
}());
Output
11:21:26
On jsfiddle

less than 10 add 0 to number [duplicate]

This question already has answers here:
How can I pad a value with leading zeros?
(76 answers)
Closed 4 years ago.
How can I modify this code to add a 0 before any digits lower than 10
$('#detect').html( toGeo(apX, screenX) + latT +', '+ toGeo(apY, screenY) + lonT );
function toGeo(d, max) {
var c = '';
var r = d/max * 180;
var deg = Math.floor(r);
c += deg + "° ";
r = (r - deg) * 60;
var min = Math.floor(r);
c += min + "′ ";
r = (r - min) * 60;
var sec = Math.floor(r);
c += sec + "″";
return c;
}
So the outpout would change from
4° 7′ 34″W, 168° 1′ 23″N
to
04° 07′ 34″W, 168° 01′ 23″N
Thanks for your time
You can always do
('0' + deg).slice(-2)
See slice():
You can also use negative numbers to select from the end of an array
Hence
('0' + 11).slice(-2) // '11'
('0' + 4).slice(-2) // '04'
For ease of access, you could of course extract it to a function, or even extend Number with it:
Number.prototype.pad = function(n) {
return new Array(n).join('0').slice((n || 2) * -1) + this;
}
Which will allow you to write:
c += deg.pad() + '° '; // "04° "
The above function pad accepts an argument specifying the length of the desired string. If no such argument is used, it defaults to 2. You could write:
deg.pad(4) // "0045"
Note the obvious drawback that the value of n cannot be higher than 11, as the string of 0's is currently just 10 characters long. This could of course be given a technical solution, but I did not want to introduce complexity in such a simple function. (Should you elect to, see alex's answer for an excellent approach to that).
Note also that you would not be able to write 2.pad(). It only works with variables. But then, if it's not a variable, you'll always know beforehand how many digits the number consists of.
Make a function that you can reuse:
function minTwoDigits(n) {
return (n < 10 ? '0' : '') + n;
}
Then use it in each part of the coordinates:
c += minTwoDigits(deg) + "° ";
and so on.
if(myNumber.toString().length < 2)
myNumber= "0"+myNumber;
or:
return (myNumber.toString().length < 2) ? "0"+myNumber : myNumber;
You can always do
('0' + deg).slice(-2)
If you use it very often, you may extend the object Number
Number.prototype.pad = function(n) {
if (n==undefined)
n = 2;
return (new Array(n).join('0') + this).slice(-n);
}
deg.pad(4) // "0045"
where you can set any pad size or leave the default 2.
You can write a generic function to do this...
var numberFormat = function(number, width) {
return new Array(+width + 1 - (number + '').length).join('0') + number;
}
jsFiddle.
That way, it's not a problem to deal with any arbitrarily width.
Hope, this help:
Number.prototype.zeroFill= function (n) {
var isNegative = this < 0;
var number = isNegative ? -1 * this : this;
for (var i = number.toString().length; i < n; i++) {
number = '0' + number;
}
return (isNegative ? '-' : '') + number;
}
Here is Genaric function for add any number of leading zeros for making any size of numeric string.
function add_zero(your_number, length) {
var num = '' + your_number;
while (num.length < length) {
num = '0' + num;
}
return num;
}
I was bored and playing around JSPerf trying to beat the currently selected answer prepending a zero no matter what and using slice(-2). It's a clever approach but the performance gets a lot worse as the string gets longer.
For numbers zero to ten (one and two character strings) I was able to beat by about ten percent, and the fastest approach was much better when dealing with longer strings by using charAt so it doesn't have to traverse the whole string.
This follow is not quit as simple as slice(-2) but is 86%-89% faster when used across mostly 3 digit numbers (3 character strings).
var prepended = ( 1 === string.length && string.charAt( 0 ) !== "0" ) ? '0' + string : string;
$('#detect').html( toGeo(apX, screenX) + latT +', '+ toGeo(apY, screenY) + lonT );
function toGeo(d, max) {
var c = '';
var r = d/max * 180;
var deg = Math.floor(r);
if(deg < 10) deg = '0' + deg;
c += deg + "° ";
r = (r - deg) * 60;
var min = Math.floor(r);
if(min < 10) min = '0' + min;
c += min + "′ ";
r = (r - min) * 60;
var sec = Math.floor(r);
if(sec < 10) sec = '0' + sec;
c += sec + "″";
return c;
}
A single regular expression replace should do it:
var stringWithSmallIntegers = "4° 7′ 34″W, 168° 1′ 23″N";
var paddedString = stringWithSmallIntegers.replace(
/\d+/g,
function pad(digits) {
return digits.length === 1 ? '0' + digits : digits;
});
alert(paddedString);
shows the expected output.

Categories

Resources