Calculating time elapsed javascript wrong output - javascript

I am currently using a script to calculate the time passed in years, months, days etc in Javascript.
$(document).ready(function(){
var birth_date = new Date('March, 25, 2022');
var years,months,days, hours, minutes, seconds;
var ageCount = document.getElementById('counter');
setInterval(function(){
var current_date = new Date();
var YearDiff = (current_date.getYear() - birth_date.getYear());
var monthDiff = (current_date.getMonth() - birth_date.getMonth());
var daysDiff = (current_date.getDate() - birth_date.getDate());
var hoursDiff = (current_date.getHours() - birth_date.getHours());
var minDiff = (current_date.getMinutes() - birth_date.getMinutes());
var secDiff = (current_date.getSeconds() - birth_date.getSeconds());
ageCount.innerHTML=YearDiff+' Years '+monthDiff+' Months '+daysDiff+' Days '+hoursDiff+
' Hours '+minDiff+' Minutes '+secDiff+' Seconds';
},500);
});`
This seems to output the right months, days and hours when the set date day is lower than the current date (so April 21 when it is now April 22).
0 Years 1 Months 2 Days 8 Hours 14 Minutes 2 Seconds`
When the date day number is higher, it changes it to a certain number of months minus a number of days. Like this (1 month - 4 days, when it should just be 0 months and 27 days).
0 Years 1 Months -4 Days 8 Hours 14 Minutes 38 Seconds
An example of the script is viewable here: https://jsfiddle.net/j2k7n4zp/
Does anyone have a clue what goes wrong or what I need to fix to make it calculate the right amount of days without using minus?
Thanks in advance!

What's going wrong with your code is that assume every part of a later date is higher than every part of an earlier one ... e.g. ... 23 April 2022 to 1 May 2022 - the Date is lower, but the Month is higher - whereas your code naively the Date portion of 1 May is Higher than 23 April just because May is later than April - but that's not how dates work
Here's something I literally whipped up now, see if it helps
const dateDiff = (from, to) => {
// so we don't mutate passed in dates
let start = new Date(from);
let end = new Date(to);
if (+start > +end) {
[start, end] = [end, start];
}
const loop = (prop) => {
const set = `set${prop}`;
const get = `get${prop}`;
let ret = 0;
while (1) {
start[set](start[get]() + 1);
if (start < end) {
ret++;
} else {
start[set](start[get]() -1);
break;
}
}
return ret;
}
const years = loop('FullYear');
const months = loop('Month');
const days = loop('Date');
const hours = loop('Hours');
const minutes = loop('Minutes');
const seconds = loop('Seconds');
const milliseconds = loop('Milliseconds');
return {years, months, days, hours, minutes, seconds, milliseconds}
}
const ageCount = document.getElementById('counter');
setInterval(() => {
const r = dateDiff(new Date(), new Date('2022-03-25'));
ageCount.innerHTML = `${r.years} Years, ${r.months} Months, ${r.days} Days, ${r.hours} Hours, ${r.minutes} Minutes, ${r.seconds} Seconds`;
}, 500);
<div id="counter">
</div>

Related

remaining minutes and seconds to date are always 59 with moment

I have two functions in my app, one where I get the instance of the next weekday I choose (get me next mindayfor example), then I have a function which calculates remianing days,hours,minutes and seconds.
Days and hours remaining are calculated correctly but minutes and seconds are always 59
I think this is because when I calculate next instance of monday the resulting timestamp doesn't appear to have a HOUR:MINUTE format, and I want it to be 00:00, so exactly start of the day
nextMonday "2022-03-21T15:11:48.580Z"
LOG Days: 1.999999745370371
LOG Hours: 7
LOG Minutes: 59
LOG Seconds: 59
HOW CAN I ADD HOURS AND MINUTES (00:00) to the moment timestamp I get, I think that would be the problem!
let nextThursday = getNextThursday();
getCountdown();
const getNextDay = () =>
{
const dayINeed = 7; // for monday
const today = moment().isoWeekday();
// if we haven't yet passed the day of the week that I need:
if (today <= dayINeed) {
// then just give me this week's instance of that day
return moment().isoWeekday(dayINeed);
} else {
// otherwise, give me *next week's* instance of that same day
return moment().add(1, 'weeks').isoWeekday(dayINeed);
}
};
const getCountdown = (ending) => {
var now = moment();
var end = moment(ending); // another date
var duration = moment.duration(end.diff(now));
//Get Days and subtract from duration
var days = duration.days();
duration.subtract(days, 'days');
//Get hours and subtract from duration
var hours = duration.hours();
duration.subtract(hours, 'hours');
//Get Minutes and subtract from duration
var minutes = duration.minutes();
duration.subtract(minutes, 'minutes');
//Get seconds
var seconds = duration.seconds();
console.log("Days: ", days);
console.log("Hours: ", hours);
console.log("Minutes: ", minutes);
console.log("Seconds: ", seconds);
};

Issue getting remaining days,hours/minutes.. to date with moment

I have two functions in my app, one where I get the instance of the next weekday I choose (get me next thursday for example), then I have a function which calculates remianing days,hours,minutes and seconds.
So far I can get remaining days, but hours, minutes and seconds show as 0. This is because when the date I get for next thursday doesnt have the required timestamp format:
nextThursday "2022-03-24T15:11:48.580Z"
LOG Days: 5.999999745370371
LOG Hours: 0
LOG Minutes: 0
LOG Seconds: 0
HOW CAN I ADD HOURS AND MINUTES (00:00) to the moment timestamp I get, I think that would be the problem!
let nextThursday = getNextThursday();
getCountdown();
const getNextThursday = () =>
{
const dayINeed = 4; // for Thursday
const today = moment().isoWeekday();
// if we haven't yet passed the day of the week that I need:
if (today <= dayINeed) {
// then just give me this week's instance of that day
return moment().isoWeekday(dayINeed);
} else {
// otherwise, give me *next week's* instance of that same day
return moment().add(1, 'weeks').isoWeekday(dayINeed);
}
};
const getCountdown = (ending) =>
{
var now = moment();
var end = moment(ending); // another date
var duration = moment.duration(end.diff(now));
//Get Days and subtract from duration
var days = duration.asDays();
duration.subtract(moment.duration(days,'days'));
//Get hours and subtract from duration
var hours = duration.hours();
duration.subtract(moment.duration(hours,'hours'));
//Get Minutes and subtract from duration
var minutes = duration.minutes();
duration.subtract(moment.duration(minutes,'minutes'));
//Get seconds
var seconds = duration.seconds();
console.log("Days: ",days);
console.log("Hours: ",hours);
console.log("Minutes: ",minutes);
console.log("Seconds: ",seconds);
};
Your problem is you're using asDays() which converts your duration to a decimal number (including hours, minutes, and seconds in decimal part)
And you don't need to call moment.duration(x,'x') in every subtraction
The fix should be
const getCountdown = (ending) => {
var now = moment();
var end = moment(ending); // another date
var duration = moment.duration(end.diff(now));
//Get Days and subtract from duration
var days = duration.days();
duration.subtract(days, 'days');
//Get hours and subtract from duration
var hours = duration.hours();
duration.subtract(hours, 'hours');
//Get Minutes and subtract from duration
var minutes = duration.minutes();
duration.subtract(minutes, 'minutes');
//Get seconds
var seconds = duration.seconds();
console.log("Days: ", days);
console.log("Hours: ", hours);
console.log("Minutes: ", minutes);
console.log("Seconds: ", seconds);
};

javascript calculate the difference between two hours

There is a question that is tricky. Make a function that takes a string argument like 2:00 p.m. or 5:50 a.m.
You must not use momentjs or any other third-party library.
We have three static hours to determine the difference between them and this argument.
7:00 a.m. for breakfast.
12:00 p.m. for lunch.
7:00 p.m. for dinner.
The function should return an array with the first and second elements representing hours and minutes, like below:
eat("2:00 a.m.") // [5, 0];
eat("5:50 p.m.") // [1, 10];
You can start by creating a minutesSinceMidnight() function to get the time since midnight in minutes for a given input string.
We'll then create the timeToEat() function, which will start by finding the next meal time.
Once this is found, we'll get the time to the next meal in minutes, and convert to hours and minutes using
a minutesToHoursAndMinutes() function.
function minutesSinceMidnight(timeStr) {
let rg = /(\d{1,2})\:(\d{1,2})\s+([ap])\.?m/
let [,hour, minute, am] = rg.exec(timeStr);
hour = Number(hour);
if (am === 'a' && hour === 12) hour -= 12;
if (am === 'p' && hour < 12) hour += 12;
return hour * 60 + Number(minute);
}
function minutesToHoursAndMinutes(totalMinutes) {
let hours = Math.floor(totalMinutes / 60);
let minutes = totalMinutes % 60;
return [ hours, minutes]
}
function timeToEat(timeStr) {
let currentTime = minutesSinceMidnight(timeStr);
let mealTimes = ['7:00 a.m', '12:00 p.m.', '7:00 p.m.'].map(minutesSinceMidnight);
let nextMealTime = mealTimes.find(mealTime => mealTime >= currentTime);
// No meal found...
if (nextMealTime === undefined) {
return nextMealTime;
}
let timeToNextMealMinutes = nextMealTime - currentTime;
return minutesToHoursAndMinutes(timeToNextMealMinutes);
}
console.log(timeToEat("2:00 a.m."));
console.log(timeToEat("5:50 p.m."));
console.log(timeToEat("6:30 p.m."));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You need some basic functions to convert the time to some common unit that can be compared with some other time. In this case, minutes will do but seconds or milliseconds could also be used.
You also may need to allow for the case where the time is after the last meal, so the time will be the time to the first meal tomorrow.
The following is a simple implementation with some tests. Ideally the data would not be embedded in the timeToNextMeal function so that it's more easily maintained.
// Convert timestamp in h:mm ap format to minutes,
// E.g. 2:30 p.m. is 870 minutes
function timeToMins(time) {
// Get parts of time
let [h, m, ap] = time.split(/\W/);
// Set hours based on value and am/pm
h = h%12 + (/^a/i.test(ap)? 0 : 12);
// Return minutes
return h*60 + m*1;
}
// Convert minutes to array [hours, minutes]
function minsToHM(mins) {
return [mins/60 | 0, mins % 60];
}
function timeToNextMeal(date = new Date()) {
let data = {
'lunch' : '12:00 p.m.',
'breakfast': '7:00 a.m.',
'dinner' : '7:00 p.m.'
};
let minsToMeal = 0;
// Get meal names, ensure sorted by time
let meals = Object.keys(data).sort((a,b) =>
timeToMins(data[a]) - timeToMins(data[b])
);
// Convert time to minutes
let mins = date.getHours() * 60 + date.getMinutes();
// Get next mealtime
let nextMeal = meals.find(meal => timeToMins(data[meal]) > mins);
// If undefined, next meal is first meal tomorrow
if (!nextMeal) {
minsToMeal += 1440 - mins;
mins = 0;
nextMeal = meals[0];
}
// Get minutes to next meal
minsToMeal += timeToMins(data[nextMeal]) - mins;
// Convert minutes to array [H,m]
return minsToHM(minsToMeal);
}
// Examples
[new Date(2022,0,6, 4), // 4 am
new Date(2022,0,6, 5,58), // 5:58 am
new Date(2022,0,6, 9,30), // 9:30 am
new Date(2022,0,6,17,30), // 5:30 pm
new Date(2022,0,6,20, 0), // 8:00 pm
].forEach(d => console.log(
`${d.toLocaleTimeString('en-NZ')} ${timeToNextMeal(d)}`
));

Moment js format with over24 hours fails [duplicate]

This question already has answers here:
Get the time difference between two datetimes
(22 answers)
Closed 3 years ago.
AM trying to format momentjs to hh:mm:ss in over 24 hours but i only get 1 hour so i have tried
const start = moment('2019-02-27 00:00');
const end = moment('2019-03-01 01:00');
var diff =end.diff(start, 'seconds', true)
let ff = moment.utc((diff) * 1000).format('HH:mm:ss')
console.log(ff)
In the above i expected to get
49:00:00
as its two days and 1 hour so 24*2 since each day has 24 hours plus the one hour from 00:0 to 01:00
WHere am i going wrong as it shows 01:00:00 instead of 49:00:00
Also run into the same problem, heres my code snippet if that would help you.
let start = moment('2019-03-01 00:00:00');
let stop = moment();
const formatTimespan = (start, stop) => {
const diff = stop.diff(start, "hours", true);
const hours = Math.floor(diff);
const step = 60 * (diff - hours)
let mins = Math.floor(step)
let secs = Math.floor(60 * (step - mins));
mins = mins.toString().padStart(2, "0");
secs = secs.toString().padStart(2, "0");
return `${hours}:${mins}:${secs}`;
}
console.log(formatTimespan(start, stop));

How to calculate rounded up months and days until a target date ignoring timezones and DST?

I want to create a timer that displays rounded up months and days left before a local target date, ignoring timezones and daylight savings.
To clarify, with a target date 2018-12-10:
At 2018-10-08 23:01 it should result in 2 months 2 days
At 2018-10-09 00:01 it should result in 2 months 1 days
At 2018-10-09 02:01 it should result in 2 months 1 days
At 2018-12-09 23:59 it should result in 0 months 1 days
As apparent, days should always start and end at 00:00 local time, independent if the target date is after a DST change in the local timezone or not.
With the naive approach, the DST change throws it off, and it's also not counting less-than-full days:
const target = moment('2018-12-10')
const t1 = moment('2018-10-08 23:01')
const t2 = moment('2018-10-09 00:01')
const t3 = moment('2018-10-09 02:01')
const t4 = moment('2018-12-09 23:59')
const d1 = moment.duration(target.diff(t1))
const d2 = moment.duration(target.diff(t2))
const d3 = moment.duration(target.diff(t3))
const d4 = moment.duration(target.diff(t4))
// render() ...
{d1.months()} months {d1.days()} days
{d2.months()} months {d2.days()} days
{d3.months()} months {d3.days()} days
{d4.months()} months {d4.days()} days
results in:
2 months 1 days
2 months 1 days
2 months 0 days
0 months 0 days
What would be the correct approach to calculate the days without being influenced by DST changes during the duration?
You can use startOf() to round the date down first.
So if you do something like this:
const target = moment('2018-12-10')
const t1 = moment('2018-10-08 23:01').startOf('day');
const t2 = moment('2018-10-09 00:01').startOf('day');
const t3 = moment('2018-12-09 23:59').startOf('day');
const d1 = moment.duration(target.diff(t1))
const d2 = moment.duration(target.diff(t2))
const d3 = moment.duration(target.diff(t3))
console.log(d1.months() + " months " + d1.days() + " days");
console.log(d2.months() + " months " + d2.days() + " days");
console.log(d3.months() + " months " + d3.days() + " days");
The result will be:
2 months 2 days
2 months 1 days
0 months 1 days
You can also use isDST() to calculate if DST is observed. If it is, you would subtract an hour first. Usage might look something like this:
let t1 = moment('2018-10-08 00:01');
t1 = t1.isDST() ? t1.subtract(1, 'hours').startOf('day') : t1.startOf('day');

Categories

Resources