How to group, sum, and average times in crossfilter.js - crossfilter

I am trying to find average time taken by the name. May i know the best way to find total time across all the name as well as the average time taken. Please find the details below
let data = [{"name":"A","children":"8:17:33"},{"name":"B","children":"9:30:45"},{"name":"C","children":"12:45:56"},{"name":"D","children":"4:20:30"},{"name":"E","children":"7:12:38"},{"name":"F","children":"6:29:45"},{"name":"G","children":"11:34:45"},{"name":"H","children":"10:30:45"},{"name":"I","children":"8:34:45"},{"name":"J","children":"8:34:12"}];
let CFX = crossfilter(data);
let dimName = CFX.dimension( (d)=> d.name);
let grpTime = dimName.group().reduceSum( (d)=> d.children);
console.log( grpTime.all() );
<script src="https://square.github.io/crossfilter/crossfilter.v1.min.js"></script>
EDIT: Here is a custom reduce to do it, but the resulting times come out as strings, and the average values are too large:
let data = [{"name":"A","children":"8:17:33"},{"name":"B","children":"9:30:45"},{"name":"C","children":"12:45:56"},{"name":"D","children":"4:20:30"},{"name":"E","children":"7:12:38"},{"name":"F","children":"6:29:45"},{"name":"G","children":"11:34:45"},{"name":"H","children":"10:30:45"},{"name":"I","children":"8:34:45"},{"name":"J","children":"8:34:12"}];
let CFX = crossfilter(data);
let dimName = CFX.dimension( (d)=> d.name);
let grpTime = dimName.group().reduceSum( (d)=> d.children);
//console.log( grpTime.all() );
let timeGrp = dimName.group().reduce(
function( p , v) {
p.count++;
let time = v.children.split(':');
p.time += time[0] * 60 * 60 + time[1] * 60 + time[2];
p.avg = p.time / p.count;
return p;
},
function( p , v) {
p.count--;
let time = v.children.split(':');
p.time -= time[0] * 60 * 60 + time[1] * 60 + time[2];
p.avg = p.count ? p.time / p.count : 0;
return p;
},
function( ) {
return {
time: 0,
avg: 0,
count : 0
}
}
);
console.log(timeGrp.all());
<script src="https://square.github.io/crossfilter/crossfilter.v1.min.js"></script>

One of the trickier things about JavaScript is that it will silently and happily convert strings to numbers, and vice versa, and it doesn't always do this correctly.
In this case, since your times are strings, and splitting those strings produces more strings, you've got a mix of strings and numbers.
But does JavaScript complain? No. It automatically converts strings to numbers, like
"8" * 60 = 480
But then it also converts numbers to strings, like
90 + "9" = 909
The right thing to do is convert those times to numbers immediately:
let time = v.children.split(':').map(x => +x);
let data = [{"name":"A","children":"8:17:33"},{"name":"B","children":"9:30:45"},{"name":"C","children":"12:45:56"},{"name":"D","children":"4:20:30"},{"name":"E","children":"7:12:38"},{"name":"F","children":"6:29:45"},{"name":"G","children":"11:34:45"},{"name":"H","children":"10:30:45"},{"name":"I","children":"8:34:45"},{"name":"J","children":"8:34:12"}];
let CFX = crossfilter(data);
let dimName = CFX.dimension( (d)=> d.name);
let grpTime = dimName.group().reduceSum( (d)=> d.children);
//console.log( grpTime.all() );
let timeGrp = dimName.group().reduce(
function( p , v) {
p.count++;
let time = v.children.split(':').map(x => +x);
p.time += time[0] * 60 * 60 + time[1] * 60 + time[2];
p.avg = p.time / p.count;
return p;
},
function( p , v) {
p.count--;
let time = v.children.split(':').map(x => +x)
p.time -= time[0] * 60 * 60 + time[1] * 60 + time[2];
p.avg = p.count ? p.time / p.count : 0;
return p;
},
function( ) {
return {
time: 0,
avg: 0,
count : 0
}
}
);
console.log(timeGrp.all());
<script src="https://square.github.io/crossfilter/crossfilter.v1.min.js"></script>

Related

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());
});
})()

Sun's position in Swift

I am trying to implement this solution for calculating the sun's position in Swift3. I then wrap this in another function that simply cycles through a day from midnight stepping every 10 minutes until 23:50.
I do not really understand R and there are some details of the answer I do not fully comprehend, notably what appears to be some sort of if/clamp function with the square brackets. I did my best, comparing with the Python version when I got confused. Otherwise the only differences are due to the use of NSDate, which simplified some of the code at the top.
Some of the values I get back seem correct and I can see the basis of a curve when I plot the results. However, the result from one call, say 7AM, and then the next, 7:10, are wildly different.
I strongly suspect I did something wrong with the clamping, and that minor changes in the inputs get mod/trunced in different ways and swing the output. But I can't spot it. Can anyone who understands this algo help?
Here's a sample of the output I'm getting:
2017-06-21 00:10:00 +0000 -16.0713262209521 31.7135341633943
2017-06-21 00:20:00 +0000 61.9971433936385 129.193513530349
2017-06-21 00:30:00 +0000 22.5263575559266 78.5445189561018
2017-06-21 00:40:00 +0000 29.5973897349096 275.081637736092
2017-06-21 00:50:00 +0000 41.9552795956374 262.989819486864
As you can see, it swings wildly between iterations. The Earth does not turn that way! My code follows, this version simply sends the results to the log:
class func julianDayFromDate(_ date: Date) -> Double {
let ti = date.timeIntervalSince1970
return ((ti / 86400.0) + 2440587)
}
class func sunPath(lat: Double, lon: Double, size: CGSize) -> UIImage {
var utzCal = Calendar(identifier: .gregorian)
utzCal.timeZone = TimeZone(secondsFromGMT: 0)!
let year = utzCal.component(.year, from: Date())
let june = DateComponents(calendar: utzCal, year: year, month: 6, day: 21).date!
// now we loop for every 10 minutes (2 degrees) and plot those points
for time in stride(from:0, to:(24 * 60), by: 10) {
let calcdate = june.addingTimeInterval(Double(time) * 60.0)
let (alt, az) = sun(date: calcdate, lat: lat, lon: lon)
print(calcdate, alt, az)
}
class func sun(date: Date, lat: Double, lon: Double) -> (altitude: Double, azimuth: Double) {
// these come in handy
let twopi = Double.pi * 2
let deg2rad = Double.pi / 180.0
// latitude to radians
let lat_radians = lat * deg2rad
// the Astronomer's Almanac method used here is based on Epoch 2000, so we need to
// convert the date into that format. We start by calculating "n", the number of
// days since 1 January 2000
let n = julianDayFromDate(date) - 2451545.0
// it continues by calculating the position in ecliptic coordinates,
// starting with the mean longitude of the sun in degrees, corrected for aberation
var meanlong_degrees = 280.460 + (0.9856474 * n)
meanlong_degrees = meanlong_degrees.truncatingRemainder(dividingBy: 360.0)
// and the mean anomaly in degrees
var meananomaly_degrees = 357.528 + (0.9856003 * n)
meananomaly_degrees = meananomaly_degrees.truncatingRemainder(dividingBy: 360.0)
let meananomaly_radians = meananomaly_degrees * deg2rad
// and finally, the eliptic longitude in degrees
var elipticlong_degrees = meanlong_degrees + (1.915 * sin(meananomaly_radians)) + (0.020 * sin(2 * meananomaly_radians))
elipticlong_degrees = elipticlong_degrees.truncatingRemainder(dividingBy: 360.0)
let elipticlong_radians = elipticlong_degrees * deg2rad
// now we want to convert that to equatorial coordinates
let obliquity_degrees = 23.439 - (0.0000004 * n)
let obliquity_radians = obliquity_degrees * deg2rad
// right ascention in radians
let num = cos(obliquity_radians) * sin(elipticlong_radians)
let den = cos(elipticlong_radians)
var ra_radians = atan(num / den)
ra_radians = ra_radians.truncatingRemainder(dividingBy: Double.pi)
if den < 0 {
ra_radians = ra_radians + Double.pi
} else if num < 0 {
ra_radians = ra_radians + twopi
}
// declination is simpler...
let dec_radians = asin(sin(obliquity_radians) * sin(elipticlong_radians))
// and from there, to local coordinates
// start with the UTZ sidereal time
let cal = Calendar.current
let h = Double(cal.component(.hour, from: date))
let m = Double(cal.component(.minute, from: date))
let f: Double
if h == 0 && m == 0 {
f = 0.0
} else if h == 0 {
f = 60.0 / m
} else if h == 0 {
f = 24.0 / h
} else {
f = (24.0 / h) + (60.0 / m)
}
var utz_sidereal_time = 6.697375 + 0.0657098242 * n + f
utz_sidereal_time = utz_sidereal_time.truncatingRemainder(dividingBy: 24.0)
// then convert that to local sidereal time
var localtime = utz_sidereal_time + lon / 15.0
localtime = localtime.truncatingRemainder(dividingBy: 24.0)
var localtime_radians = localtime * 15.0 * deg2rad
localtime_radians = localtime.truncatingRemainder(dividingBy: Double.pi)
// hour angle in radians
var hourangle_radians = localtime_radians - ra_radians
hourangle_radians = hourangle_radians.truncatingRemainder(dividingBy: twopi)
// get elevation in degrees
let elevation_radians = (asin(sin(dec_radians) * sin(lat_radians) + cos(dec_radians) * cos(lat_radians) * cos(hourangle_radians)))
let elevation_degrees = elevation_radians / deg2rad
// and azimuth
let azimuth_radians = asin( -cos(dec_radians) * sin(hourangle_radians) / cos(elevation_radians))
// now clamp the output
let azimuth_degrees: Double
if (sin(dec_radians) - sin(elevation_radians) * sin(lat_radians) < 0) {
azimuth_degrees = (Double.pi - azimuth_radians) / deg2rad
} else if (sin(azimuth_radians) < 0) {
azimuth_degrees = (azimuth_radians + twopi) / deg2rad
} else {
azimuth_degrees = azimuth_radians / deg2rad
}
return (elevation_degrees, azimuth_degrees)
}
Ok, after downloading an R interpreter for OSX, finding that it had no debugger, discovering that there are multiple ways to do a print all with their own caveats, etc etc, I found the problem I was looking for. It was indeed clamping one of the values incorrectly. Here is a working Swift3 version that should be easy to convert to any C-like language and easier to read than the originals. You will have to provide your own versions of the first two functions that work with the date format of your target platform. And the truncatingRemainer is someone's ferbile idea that there shouldn't be a % operator on Double, it's a normal MOD.
// convinience method to return a unit-epoch data from a julian date
class func dateFromJulianDay(_ julianDay: Double) -> Date {
let unixTime = (julianDay - 2440587) * 86400.0
return Date(timeIntervalSince1970: unixTime)
}
class func julianDayFromDate(_ date: Date) -> Double {
//==let JD = Integer(365.25 * (Y + 4716)) + Integer(30.6001 * (M +1)) +
let ti = date.timeIntervalSince1970
return ((ti / 86400.0) + 2440587.5)
}
// calculate the elevation and azimuth of the sun for a given date and location
class func sun(date: Date, lat: Double, lon: Double) -> (altitude: Double, azimuth: Double) {
// these come in handy
let twopi = Double.pi * 2
let deg2rad = Double.pi / 180.0
// latitude to radians
let lat_radians = lat * deg2rad
// the Astronomer's Almanac method used here is based on Epoch 2000, so we need to
// convert the date into that format. We start by calculating "n", the number of
// days since 1 January 2000. So if your date format is 1970-based, convert that
// a pure julian date and pass that in. If your date is 2000-based, then
// just let n = date
let n = julianDayFromDate(date) - 2451545.0
// it continues by calculating the position in ecliptic coordinates,
// starting with the mean longitude of the sun in degrees, corrected for aberation
var meanlong_degrees = 280.460 + (0.9856474 * n)
meanlong_degrees = meanlong_degrees.truncatingRemainder(dividingBy: 360.0)
// and the mean anomaly in degrees
var meananomaly_degrees = 357.528 + (0.9856003 * n)
meananomaly_degrees = meananomaly_degrees.truncatingRemainder(dividingBy: 360.0)
let meananomaly_radians = meananomaly_degrees * deg2rad
// and finally, the eliptic longitude in degrees
var elipticlong_degrees = meanlong_degrees + (1.915 * sin(meananomaly_radians)) + (0.020 * sin(2 * meananomaly_radians))
elipticlong_degrees = elipticlong_degrees.truncatingRemainder(dividingBy: 360.0)
let elipticlong_radians = elipticlong_degrees * deg2rad
// now we want to convert that to equatorial coordinates
let obliquity_degrees = 23.439 - (0.0000004 * n)
let obliquity_radians = obliquity_degrees * deg2rad
// right ascention in radians
let num = cos(obliquity_radians) * sin(elipticlong_radians)
let den = cos(elipticlong_radians)
var ra_radians = atan(num / den)
ra_radians = ra_radians.truncatingRemainder(dividingBy: Double.pi)
if den < 0 {
ra_radians = ra_radians + Double.pi
} else if num < 0 {
ra_radians = ra_radians + twopi
}
// declination is simpler...
let dec_radians = asin(sin(obliquity_radians) * sin(elipticlong_radians))
// and from there, to local coordinates
// start with the UTZ sidereal time, which is probably a lot easier in non-Swift languages
var utzCal = Calendar(identifier: .gregorian)
utzCal.timeZone = TimeZone(secondsFromGMT: 0)!
let h = Double(utzCal.component(.hour, from: date))
let m = Double(utzCal.component(.minute, from: date))
let f: Double // universal time in hours and decimals (not days!)
if h == 0 && m == 0 {
f = 0.0
} else if h == 0 {
f = m / 60.0
} else if m == 0 {
f = h
} else {
f = h + (m / 60.0)
}
var utz_sidereal_time = 6.697375 + 0.0657098242 * n + f
utz_sidereal_time = utz_sidereal_time.truncatingRemainder(dividingBy: 24.0)
// then convert that to local sidereal time
var localtime = utz_sidereal_time + lon / 15.0
localtime = localtime.truncatingRemainder(dividingBy: 24.0)
let localtime_radians = localtime * 15.0 * deg2rad
// hour angle in radians
var hourangle_radians = localtime_radians - ra_radians
hourangle_radians = hourangle_radians.truncatingRemainder(dividingBy: twopi)
// get elevation in degrees
let elevation_radians = (asin(sin(dec_radians) * sin(lat_radians) + cos(dec_radians) * cos(lat_radians) * cos(hourangle_radians)))
let elevation_degrees = elevation_radians / deg2rad
// and azimuth
let azimuth_radians = asin( -cos(dec_radians) * sin(hourangle_radians) / cos(elevation_radians))
// now clamp the output
let azimuth_degrees: Double
if (sin(dec_radians) - sin(elevation_radians) * sin(lat_radians) < 0) {
azimuth_degrees = (Double.pi - azimuth_radians) / deg2rad
} else if (sin(azimuth_radians) < 0) {
azimuth_degrees = (azimuth_radians + twopi) / deg2rad
} else {
azimuth_degrees = azimuth_radians / deg2rad
}
// all done!
return (elevation_degrees, azimuth_degrees)
}

javascript fraction to percent

When I tried to convert fraction in Javascript, I am facing a problem.
I need to make a fraction value to percent value.
a = 0.0175
It should be displayed as 1.75%. I tried to multiply by 100. But I am getting some extra fractions added to the right - 1.7500000000000002 . I just need 1.75, not any more zeroes added to the end.
Thanks in advance.
Try this
var a = 0.0175
var num = a * 100;
var n = num.toFixed(2)
multiply, round and divide:
// rounding to set precision or default precision = 3
function roundToPrecision ( value, precision ) {
precision = ( typeof precision !== 'undefined' ) ? precision : 3;
var mult = Math.pow( 10, precision );
return Math.round( mult * value ) / mult;
}
usage:
var zzz = roundToPrecision( 123.1231232546 ); // 123.123
var aaa = roundToPrecision( 123.1231232546, 1 ); // 123.1
Try this:
function formatNum(n) {
return Math.round(n * 1e4) / 1e2;
}
var a = 0.0175;
var n = formatNum(a); // 1.75
var b = 0.21;
var m = formatNum(b); // 21
It simply multiplies by 100*100, rounds the result and divides again by 100. The result is still a number and not a string as with the toFixed-approach.

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

Calculate timespan in JavaScript

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

Resources