Calculate timespan in JavaScript - asp.net

I have a .net 2.0 ascx control with a start time and end time textboxes. The data is as follows:
txtStart.Text = 09/19/2008 07:00:00
txtEnd.Text = 09/19/2008 05:00:00
I would like to calculate the total time (hours and minutes) in JavaScript then display it in a textbox on the page.

function stringToDate(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2}) (\d{2,2}):(\d{2,2}):(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3], matches[4], matches[5], matches[6]);
} else {
return null;
};
}
function getTimeSpan(ticks) {
var d = new Date(ticks);
return {
hour: d.getUTCHours(),
minute: d.getMinutes(),
second: d.getSeconds()
}
}
var beginDate = stringToDate('2008-09-19 07:14:00');
var endDate = stringToDate('2008-09-19 17:35:00');
var sp = getTimeSpan(endDate - beginDate);
alert("timeuse:" + sp.hour + " hour " + sp.minute + " minute " + sp.second + " second ");
you can use getUTCHours() instead Math.floor(n / 3600000);

Once your textbox date formats are known in advance, you can use Matt Kruse's Date functions in Javascript to convert the two to a timestamp, subtract and then write to the resulting text box.
Equally the JQuery Date Input code for stringToDate could be adapted for your purposes - the below takes a string in the format "YYYY-MM-DD" and converts it to a date object. The timestamp (getTime()) of these objects could be used for your calculations.
stringToDate: function(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3]);
} else {
return null;
};
}

I took what #PConroy did and added to it by doing the calculations for you. I also added the regex to make sure the time is part of the string to create the date object.
<html>
<head>
<script type="text/javascript">
function stringToDate(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2}) (\d{2,2}):(\d{2,2}):(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3], matches[4], matches[5], matches[6]);
} else {
return null;
};
}
//Convert duration from milliseconds to 0000:00:00.00 format
function MillisecondsToDuration(n) {
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var h = "000" + Math.floor(n / 3600000);
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = h.substr(h.length-4) + ":" + m.substr(m.length-2) + ":";
hms += s.substr(s.length-2) + "." + cs.substr(cs.length-2);
return hms;
}
var beginDate = stringToDate('2008-09-19 07:14:00');
var endDate = stringToDate('2008-09-19 17:35:00');
var n = endDate.getTime() - beginDate.getTime();
alert(MillisecondsToDuration(n));
</script>
</head>
<body>
</body>
</html>
This is pretty rough, since I coded it up pretty fast, but it works. I tested it out. The alert box will display 0010:21:00.00 (HHHH:MM:SS.SS). Basically all you need to do is get the values from your text boxes.

The answers above all assume string manipulation. Here's a solution that works with pure date objects:
var start = new Date().getTime();
window.setTimeout(function(){
var diff = new Date(new Date().getTime() - start);
// this will log 0 hours, 0 minutes, 1 second
console.log(diff.getHours(), diff.getMinutes(),diff.getSeconds());
},1000);

I googled for calculating a timespan in javascript and found this question on SO; unfortunately the question text and actual question (only needing hours and minutes) are not the same... so I think I arrived here in error.
I did write an answer to the question title, however - so if anyone else wants something that prints out something like "1 year, and 15 minutes", then this is for you:
function formatTimespan(from, to) {
var text = '',
span = { y: 0, m: 0, d: 0, h: 0, n: 0 };
function calcSpan(n, fnMod) {
while (from < to) {
// Modify the date, and check if the from now exceeds the to:
from = from[fnMod](1);
if (from <= to) {
span[n] += 1;
} else {
from = from[fnMod](-1);
return;
}
}
}
function appendText(n, unit) {
if (n > 0) {
text += ((text.length > 0) ? ', ' : '') +
n.toString(10) + ' ' + unit + ((n === 1) ? '' : 's');
}
}
calcSpan('y', 'addYears');
calcSpan('m', 'addMonths');
calcSpan('d', 'addDays');
calcSpan('h', 'addHours');
calcSpan('n', 'addMinutes');
appendText(span.y, 'year');
appendText(span.m, 'month');
appendText(span.d, 'day');
appendText(span.h, 'hour');
appendText(span.n, 'minute');
if (text.lastIndexOf(',') < 0) {
return text;
}
return text.substring(0, text.lastIndexOf(',')) + ', and' + text.substring(text.lastIndexOf(',') + 1);
}

Use Math.floor(n / 3600000) instead of getUTCHours() or else you would lose the number of hours greater than 24.
For example, if you have 126980000 milliseconds, this should translate to 0035:16:20.00
If you use getUTCHours() you get an incorrect string 0011:16:20.00
Better instead, use this (modifications denoted by KK-MOD):
function MillisecondsToDuration(n) {
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var d = Math.floor(n / 3600000 / 24); // KK-MOD
var h = "0" + (Math.floor(n / 3600000) - (d * 24)); // KK-MOD
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = (d > 0 ? d + "T" : "") + h.substr(h.length - 2) + ":" + m.substr(m.length - 2) + ":"; // KK-MOD
hms += s.substr(s.length - 2) + "." + cs.substr(cs.length - 2);
return hms; }
So now, 192680000 gets displayed as 1T11:16:20.00 which is 1 day 11 hours 16 minutes and 20 seconds

I like the K3 + KK-MOD approach, but I needed to show negative timespans, so I made the following modifications:
function MillisecondsToDuration(milliseconds) {
var n = Math.abs(milliseconds);
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var d = Math.floor(n / 3600000 / 24); // KK-MOD
var h = "0" + (Math.floor(n / 3600000) - (d * 24)); // KK-MOD
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = (milliseconds < 0 ? " - " : "");
hms += (d > 0 ? d + "." : "") + h.substr(h.length - 2) + ":" + m.substr(m.length - 2) + ":"; // KK-MOD
hms += s.substr(s.length - 2) + "." + cs.substr(cs.length - 2);
return hms; }
I also changed the 'T' separator to a '.' for my own formatting purposes.
Now a negative value passed in, say -360000 (negative six minutes) will produce the following output:
- 00:06:00

Related

Speed up webcrawler

I wrote this script, which works perfectly, except it is taking about 5 minutes (give a few) to run. What would be the best way to speed this up?
Kind regards, Rob
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
int divnumber = 17476;
HtmlAgilityPack.HtmlWeb web = new HtmlAgilityPack.HtmlWeb();
while (divnumber < 18500)
{
string DivUrl = "https://www.hattrick.org/nl/World/Series/?LeagueLevelUnitID=" + divnumber;
HtmlAgilityPack.HtmlDocument doc = web.Load(DivUrl);
var ClassShy = doc.DocumentNode.SelectNodes("//a[#class='shy']");
if (ClassShy != null)
{
ClassShy.ToList();
int i = 0;
foreach (var item in ClassShy)
{
i++;
}
int divForList = divnumber - 17475;
if (i > 4)
{
Console.WriteLine("VI." + divForList + " - " + i);
}
}
divnumber++;
}
sw.Stop();
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("\nDone in " + elapsedTime);
sw.Reset();

How to get a duration in format-"hh:mm" from minutes-integer with moments.js?

I have an integer value that's a count of minutes. I'm trying to use moments.js to display the minutes in hours and minutes even if the minutes exceed a day:
500 would yield "08:20"
1600 would yield "26:40"
This is what I have thus far:
function getDuration(value){
return moment.utc().startOf('day').add(value, 'minutes').format('hh:mm')
}
The above code works the only problem is when the minute value exceeds 20 hours it starts from zero again.
Thanks in advance!
If you can settle for a plain javascript implementation here is something for you:
function getDuration(n) {
var hours = Math.floor(n / 60);
var minutes = n % 60;
return pad(hours) + ':' + pad(minutes);
}
function pad(s) {
s = s + '';
return s.length < 2 ? ('00' + s).substr(s.length, 2) : s;
}
document.write('see: ' + getDuration(1600));
document.write(', see: ' + getDuration(500));
document.write(', see: ' + getDuration(481));
document.write(', see: ' + getDuration(11600));

How to create different iterations of 6 digit integer that is also 6 digits?

I am using an algorithm to create a 6 digit pin from a string of letters(I already have it). I also need to make different iterations of this 6 digit pin that would all lead back to the origin pin which can be used to generate the string of letters.
input "FEFOEISUDFRORI"
output 523923
some algorithm...
first iteration: 123203
then to authenticate
iteration: 1 ; pin: 123203
output: 'FEFOEISUDFRORI' // same as original string
Any idea how to do this?
The easiest way to solve this mathematical problem is probably with a rotation. Essentially performing an addition then a modulus, rotation will result in a one-to-one function with a range equal to it's domain.
The example I've shown will rotate the entire 6 digit number or the individual digits of the number.
function rRot(x, rot, max) {
if (rot < 0) return lRot(x,-rot,max);
rot = rot % max;
return (x + rot) % max;
}
function lRot(x, rot, max) {
if (rot < 0) return rRot(x,-rot,max);
rot = rot % max;
return rRot(x,max-rot,max);
}
function rotDigits(x, r) {
var pwr = 1, y = 0;
while (x > 0) {
var digit = x % 10;
y += rRot(digit, r, 10) * pwr;
x = Math.floor(x / 10);
pwr *= 10;
}
return y;
}
var samples = [675821, 126421, 678321, 100001, 580127, 999999];
(function () {
console.log("Rotate individual digits");
samples.forEach(v => {
var r = rotDigits(v, 7);
var vr = rotDigits(r, 10-7);
console.log(v.toString() + " => " + r.toString() + " => " + vr.toString());
});
console.log("Rotate whole number");
samples.forEach(v => {
var r = rRot(v, 65537, 1000000);
var vr = lRot(r, 65537, 1000000);
console.log(v.toString() + " => " + r.toString() + " => " + vr.toString());
});
})()

Subtracting a Timecode from another Timecode using javascript/jquery

In my project I needed to add a timecode(offset) with another timecode(original), to show it in a custom html5 video player.
00:00:17.16 --->(original timecode) +
07:49:42.08 --->(offset timecode)
-----------
07:49:59:24 sincle framerate is 23, this time code is rounded to
07:49:60:01 (7 hrs : 49 mins :60 secs and 1 frame) which is equal to
07:50:00:01 ------>(Resultant timecode)
===========
It is easy and I wrote som code for that in javascript.
function AddTimeCodeWithOffset(Offset, Original, framerate) {
var newTime = Original;
var framerate = parseFloat(framerate);
if (Offset != '00:00:00:00') {
var arOff = Offset.split(':');
var arOrg = Original.split(':');
var hour = parseInt(arOff[0]) + parseInt(arOrg[0]);
var minute = parseInt(arOff[1]) + parseInt(arOrg[1]);
var second = parseInt(arOff[2]) + parseInt(arOrg[2]);
var frame = parseInt(arOff[3]) + parseInt(arOrg[3]);
if (frame >= framerate) {
frame = Math.round(frame - framerate);
second = second + 1;
}
if (second >= 60) {
second = second - 60;
minute = minute + 1;
}
if (minute >= 60) {
minute = minute - 60;
hour = hour + 1;
}
if (frame < 10) { frame = '0' + frame.toString(); }
if (second < 10) { second = '0' + second.toString(); }
if (minute < 10) { minute = '0' + minute.toString(); }
if (hour < 10) { hour = '0' + hour.toString(); }
newTime = hour + ':' + minute + ':' + second + ':' + frame;
}
return newTime;
}
But how to do the reverse process. To get the original time code from the resultant time code by subtracting the offset time code

Full humanized durations in moment.js

I tried this in moment.js
moment.duration(375,'days').humanize()
and get "a year" as answer, but I would expect "a year and 10 days". Is there a way in moment.js to get the full humanized value?
Moment.js is providing the fromNow function to get time durations in human readable fromat, see http://momentjs.com/docs/#/displaying/fromnow/
Example:
moment([2007, 0, 29]).fromNow(); // 4 years ago
moment().subtract(375, 'days').fromNow(); // a year ago
You need to use third party lib as suggested by #Fluffy
I found this small lib, that only display duration (if you don't really need all the features of moment.js)
https://github.com/EvanHahn/HumanizeDuration.js
Try this plugin:
https://github.com/jsmreese/moment-duration-format
moment.duration(123, "minutes").format("h [hrs], m [min]");
// "2 hrs, 3 min"
I was looking at the same issue and seems like there is no plan on supporting this in the future...
Although one workaround proposed is to make an language definition that overrides default implementation of humanized messages:
https://github.com/timrwood/moment/issues/348
Kind of an overkill if you ask me...
Use moment.relativeTimeThreshold('y', 365) to set the rounding.
moment.relativeTimeThreshold('s', 60);
moment.relativeTimeThreshold('m', 60);
moment.relativeTimeThreshold('h', 24);
moment.relativeTimeThreshold('d', 31);
moment.relativeTimeThreshold('M', 12);
moment.relativeTimeThreshold('y', 365);
I made a function to solve this exact problem.
function formatDuration(period) {
let parts = [];
const duration = moment.duration(period);
// return nothing when the duration is falsy or not correctly parsed (P0D)
if(!duration || duration.toISOString() === "P0D") return;
if(duration.years() >= 1) {
const years = Math.floor(duration.years());
parts.push(years+" "+(years > 1 ? "years" : "year"));
}
if(duration.months() >= 1) {
const months = Math.floor(duration.months());
parts.push(months+" "+(months > 1 ? "months" : "month"));
}
if(duration.days() >= 1) {
const days = Math.floor(duration.days());
parts.push(days+" "+(days > 1 ? "days" : "day"));
}
if(duration.hours() >= 1) {
const hours = Math.floor(duration.hours());
parts.push(hours+" "+(hours > 1 ? "hours" : "hour"));
}
if(duration.minutes() >= 1) {
const minutes = Math.floor(duration.minutes());
parts.push(minutes+" "+(minutes > 1 ? "minutes" : "minute"));
}
if(duration.seconds() >= 1) {
const seconds = Math.floor(duration.seconds());
parts.push(seconds+" "+(seconds > 1 ? "seconds" : "second"));
}
return "in "+parts.join(", ");
}
This function takes a period string (ISO 8601), parses it with Moment (>2.3.0) and then, for every unit of time, pushes a string in the parts array. Then everything inside the parts array gets joined together with ", " as separation string.
You can test it here: https://jsfiddle.net/mvcha2xp/6/
I'm using it as a Vue filter to humanize durations correctly.
This issue on Github contains a lot of discussion about exactly that. Many are asking for a more precise humanized option.
Chime in with why you need it, use cases, etc.
https://github.com/moment/moment/issues/348
i have written this javascript code to humanize the duration,
function humanizeDuration(timeInMillisecond) {
var result = "";
if (timeInMillisecond) {
if ((result = Math.round(timeInMillisecond / (1000 * 60 * 60 * 24 * 30 * 12))) > 0) {//year
result = result === 1 ? result + " Year" : result + " Years";
} else if ((result = Math.round(timeInMillisecond / (1000 * 60 * 60 * 24 * 30))) > 0) {//months
result = result === 1 ? result + " Month" : result + " Months";
} else if ((result = Math.round(timeInMillisecond / (1000 * 60 * 60 * 24))) > 0) {//days
result = result === 1 ? result + " Day" : result + " Days";
} else if ((result = Math.round(timeInMillisecond / (1000 * 60 * 60))) > 0) {//Hours
result = result === 1 ? result + " Hours" : result + " Hours";
} else if ((result = Math.round(timeInMillisecond / (1000 * 60))) > 0) {//minute
result = result === 1 ? result + " Minute" : result + " Minutes";
} else if ((result = Math.round(timeInMillisecond / 1000)) > 0) {//second
result = result === 1 ? result + " Second" : result + " Seconds";
} else {
result = timeInMillisecond + " Millisec";
}
}
return result;
}
One of the solutions:
function getCountdown() {
// diff in seconds, comes through function's params
const diff = 60*60*24*4 + 60*60*22 + 60*35 + 5;
const MINUTE = 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const days = Math.floor(diff / DAY);
const hDiff = diff % DAY;
const hours = Math.floor(hDiff / HOUR);
const mDiff = hDiff % HOUR;
const minutes = Math.floor(mDiff / MINUTE);
const seconds = mDiff % MINUTE;
return [days, hours, minutes, seconds]
.map(v => (''+v)[1] ? ''+v : '0'+v)
}
output: ["04", "22", "35", "05"]
I needed it up to days only, but can be easily extended to weeks.
Doesn't make sense with months since diff says nothing about start date.
Having a period split to parts, adding "days"/"hours"/... is obvious.
Moment.js provides:
var y = moment.duration(375,'days').years(); // returns 1
var d = moment.duration(375,'days').days(); // returns 9
var data = y + 'y ' + d + 'd';
console.log(data);
This could be used with a bit of extra logic
This is my solution on CoffeeScript:
humanizeDuration = (eventDuration)->
eventMDuration = Moment.duration(eventDuration, 'seconds');
eventDurationString = ""
if (eventMDuration.days() > 0)
eventDurationString += " " + Moment.duration(eventMDuration.days(), 'days').humanize()
if (eventMDuration.hours() > 0)
eventDurationString += " " + Moment.duration(eventMDuration.hours(), 'hours').humanize()
if (eventMDuration.minutes() > 0)
eventDurationString += " " + Moment.duration(eventMDuration.minutes(), 'minutes').humanize()
eventDurationString.trim()
This is my solution, I like it better than the others here:
val moment1 = moment();
val moment2 = mement();
console.log(moment.duration(moment1.diff(moment2)).humanize());
Based on Ihor Kaslashnikov's solution, I modified the function to be even more accurate using vanilla Javascript.
function momentHumanize(eventDuration, unit) {
var eventMDuration = moment.duration(eventDuration, unit);
var eventDurationArray = [];
if (eventMDuration.years() > 0) {
eventDurationArray.push(eventMDuration.years() + ' years');
eventMDuration.subtract(eventMDuration.years(), 'years')
}
if (eventMDuration.months() > 0) {
eventDurationArray.push(eventMDuration.months() + ' months');
eventMDuration.subtract(eventMDuration.months(), 'months')
}
if (eventMDuration.weeks() > 0) {
eventDurationArray.push(eventMDuration.weeks() + ' weeks');
eventMDuration.subtract(eventMDuration.weeks(), 'weeks')
}
if (eventMDuration.days() > 0) {
eventDurationArray.push(eventMDuration.days() + ' days');
eventMDuration.subtract(eventMDuration.days(), 'days')
}
if (eventMDuration.hours() > 0) {
eventDurationArray.push(eventMDuration.hours() + ' hours');
eventMDuration.subtract(eventMDuration.hours(), 'hours')
}
if (eventMDuration.minutes() > 0) {
eventDurationArray.push(eventMDuration.minutes() + ' minutes');
}
return eventDurationArray.length === 1 ? eventDurationArray[0] :
eventDurationArray.join(' and ')
}
This will remove any amount from the moment instance once it humanizes it.
I did this because Ihor's solution was inaccurate, given that moment's humanize function rounds the value. For example, if I had 2.8 hours, it should've been 2 hours and an hour.
My solution removes the 2 hours, from the instance, leaving only 0.8 hours, and doesn't use moment's humanize function to avoid rounding.
Examples:
momentHumanize(45, 'minutes') // 45 minutes
momentHumanize(4514, 'minutes') // 3 days and 3 hours and 14 minutes
momentHumanize(45145587, 'minutes') // 85 years and 10 months and 1 days and 2 hours and 27 minutes
var s=moment([2020, 03, 29]).subtract(3, 'days').fromNow();
document.write(s)
enter link description here

Resources