My translation from Ruby to JavaScript gives different results - javascript

I'm writing a function that accepts a future date and returns a string in the form "X weeks, Y days, Z hours" representing the countdown to that date. My approach is:
Get the number of seconds separating the two dates by subtracting the future date's epoch time from today's epoch time.
Divide the number of seconds by 604800 (the number of seconds in a week). Store the result as weeks, and redefine seconds as the remainder (which is what Ruby's divmod does).
Do the same thing for days, hours, and minutes.
First I wrote it in Ruby, which works:
def time_countdown(*date_string)
seconds = Time.new(*date_string).to_i - Time.now.to_i
weeks, seconds = seconds.divmod 604800
days, seconds = seconds.divmod 86400
hours, seconds = seconds.divmod 3600
minutes, seconds = seconds.divmod 60
return "#{weeks} weeks, #{days} days, #{hours} hours."
end
I translated this to JavaScript with the same approach except for the following:
Since JavaScript lacks divmod, I did that manually, first setting the weeks/days/hours and then setting seconds to the remainder.
I need to use Math.floor because JavaScript exclusively uses floats.
I divide the epoch times by 1,000 since JS uses milliseconds for its epoch timestamps unlike Ruby.
My JS function expects to receive an epochTime integer since I haven't learnt how to pass around arbitrary-length argument lists in JS.
The code is:
function timeCountdown(epochTime) {
var seconds = epochTime/1000 - new Date().getTime() / 1000;
var weeks = Math.floor(seconds / 604800);
seconds = seconds % 604800;
var days = Math.floor(seconds / 86400);
seconds = seconds % 86400;
var hours = Math.floor(seconds / 3600);
seconds = seconds % 3600;
return weeks + " weeks, " + days + " days, " + hours + " hours.";
}
For the date 2015,6,19, as of June 1st, JS gives "6 weeks, 5 days, 21 hours" and Ruby gives "2 weeks, 3 days, 6 hours". I can't figure out where this difference arises. Could someone point out my mistake?

Yet if I feed the date 2015,6,19 to both functions, it being June 1st as I write this, JS tells me 6 weeks, 5 days, 21 hours and Ruby tells me 2 wweeks, 3 days, 6 hours.
You haven't shown how you're doing that, but my guess is you're doing:
timeCountdown(new Date(2015, 6, 19));
...but in JavaScript, month numbers start with 0, not 1, so June is month 5, not 6:
timeCountdown(new Date(2015, 5, 19));
// --------------------------^
Example:
function timeCountdown(epochTime) {
var seconds = epochTime/1000 - new Date().getTime() / 1000;
var weeks = Math.floor(seconds / 604800);
seconds = seconds % 604800;
var days = Math.floor(seconds / 86400);
seconds = seconds % 86400;
var hours = Math.floor(seconds / 3600);
seconds = seconds % 3600;
return weeks + " weeks, " + days + " days, " + hours + " hours.";
}
snippet.log("July 19th: " + timeCountdown(new Date(2015, 6, 19)));
snippet.log("June 19th: " + timeCountdown(new Date(2015, 5, 19)));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Related

Convert milliseconds to hours or minute or hour or day in javascript

I am trying to convert milliseconds to ...(sec/min/hours/day) ago,
I have tried like the below code but I am not getting the expected result, the output is showing that 19143.4 Days. It should be 2 or 3 days.
function msToTime(ms) {
let seconds = (ms / 1000).toFixed(1);
let minutes = (ms / (1000 * 60)).toFixed(1);
let hours = (ms / (1000 * 60 * 60)).toFixed(1);
let days = (ms / (1000 * 60 * 60 * 24)).toFixed(1);
if (seconds < 60) return seconds + " Sec";
else if (minutes < 60) return minutes + " Min";
else if (hours < 24) return hours + " Hrs";
else return days + " Days"
}
console.log(msToTime(1653991056493))
In fact here your code seems to work fine.
Reading the Date documentation :
JavaScript Date objects represent a single moment in time in a platform-independent format. Date objects contain a Number that represents milliseconds since 1 January 1970 UTC.
So when you're doing new Date(1653991056493) it's 1653991056493ms after Jan 1st 1970 which is 19143.4 days.
If you want the ms between a date and the current date, you can just substract the current date with the timestamp
new Date() - 1653991056493
function msToTime(ms) {
let seconds = (ms / 1000).toFixed(1);
let minutes = (ms / (1000 * 60)).toFixed(1);
let hours = (ms / (1000 * 60 * 60)).toFixed(1);
let days = (ms / (1000 * 60 * 60 * 24)).toFixed(1);
if (seconds < 60) return seconds + " Sec";
else if (minutes < 60) return minutes + " Min";
else if (hours < 24) return hours + " Hrs";
else return days + " Days"
}
console.log(msToTime(new Date() - 1653991056493))
I interpretted the question slightly differently to the accepted answer and am posting this as it might help people seeking to do what I though was being asked:
namely to reduce an elapsed period of milliseconds to either (rounded) days OR (rounded) hours OR (rounded) minutes OR (rounded) seconds - dependent on which fits the scale of the elapsed duration (as one might want to do where, for example, a page is to report "comment made 2 days ago" or "comment made 10 seconds ago" etc. - just like SO does when reporting when answers or comments were made.
As with the accepted answer, the elapsed time has to first be calculated by subtracting the passed ms value from a new date value (and, since units smaller than seconds will never be needed, the elapsed value converted to seconds by dividing by 1000):
const now = new Date();
const secondsPast = Math.round((now-pastMs)/1000);
This value is then filtered down a series of if checks, each containing a conditional return statement if the relevant time unit has been reached. Thus, if the 'scale' is seconds (i.e the elapsed duration is less than a minute), the function returns the seconds value and exits immeadiately:
if (secondsPast<60) {return `${secondsPast} seconds`} // terminates here if true;
If the seconds value is greater than 60, minutes are checked and a return made if they are less than sixty. The process repeats until larger values are eventually returned as days if no other unit was appropriate. Note the use of Math.floor to only return whole numbers for the relevant unit.
(this is, I think, what the original question was trying to achieve).
function elapsedTime(pastMs) {
const now = new Date();
const secondsPast = Math.round((now-pastMs)/1000);
if (secondsPast<60) {return `${secondsPast} seconds`} // terminates here if true;
const minutesPast = Math.floor(secondsPast/60);
if (minutesPast<60) {return `${minutesPast} minutes`} // terminates here if true;
const hoursPast = Math.floor(minutesPast/60);
if (hoursPast<24) {return `${hoursPast} hours`} // terminates here if true;
return `${Math.floor(hoursPast/24)} days`;
} // end function elapsedTime;
console.log(elapsedTime(1653991056493))

How to get 24:XX time from datetime?

Is there a DateTime Format that allows representation of the 24-hour clock to roll over where 24:XX is valid time?
For example
const secondsToTimeOfDay = (totalSeconds: number): string => {
return new Date(totalSeconds * 1000).toISOString().substr(11, 8);
};
var x = secondsToTimeOfDay(86399)
console.log(x)
Returns
23:59:59
But when seconds are greater than 86400 (The number of seconds in one day) it starts on the next day?
Example
var x = secondsToTimeOfDay(87000)
console.log(x)
Returns
00:10:00
Is there a date format that will return in a 24:xx format?
Example (I know this works but I want to know if it can be done using some kind of built-in Date Object)
const SomeNewFunction = (totalSeconds: number): string => {
var duration = 1000*totalSeconds
var milliseconds = parseInt((duration % 1000) / 100),
seconds = Math.floor((duration / 1000) % 60),
minutes = Math.floor((duration / (1000 * 60)) % 60),
hours = Math.floor((duration / (1000 * 60 * 60)));
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + ":" + minutes + ":" + seconds;
}
var x = SomeNewFunction(87000)
var y = SomeNewFunction(97000)
console.log(x)
console.log(y)
Returns
24:10:00
26:56:40
Where the SomeNewFuntion uses some kind of DateTimeObject rather than math?
The JavaScript Date object represents a single instant in the history of the world, both date and time. While you can ignore the date part in display, it is always there - new Date(300000) doesn't represent "00:05:00 on any day", it represents "00:05:00 on January 1st 1970, according to UTC".
Since January 1st 1970 didn't have a 25th and 26th hour, the format you're asking for wouldn't make sense. Put a different way, "Feb 2nd 02:00" and "Feb 1st 26:00" are the same instant in time, but (if I understand your problem correctly) you want to be able to represent them distinctly.
There are time-related objects where "the 26th hour" would make sense:
A "duration", representing an absolute amount of time, independent of when it happens.
An "interval", representing the span of time between two specific instants.
A "time of day", in certain specialised cases, where you want to consider the "day" to last more than 24 hours for planning purposes.
JavaScript doesn't currently have any of those built-in, although there are libraries that do, and a proposal for adding them natively.
It's likely that most "time of day" implementations would not allow for more than 24 hours in the day, but you could represent it using a "duration" or "interval". The end result might look something like this:
var timetableEntry = {
"date": Temporal.PlainDate.from({year: 2006, month: 8, day: 24}),
"startOffsetFromMidnight": Temporal.Duration.from({ hours: 23, minutes: 30 }),
"endOffsetFromMidnight": Temporal.Duration.from({ hours: 26, minutes: 30 })
}
var journeyDuration = timetableEntry.endOffsetFromMidnight.subtract( timetableEntry.startOffsetFromMidnight );
var startDateTime = timetableEntry.date.add( timetableEntry.startOffsetFromMidnight );
var endDateTime = timetableEntry.date.add( timetableEntry.endOffsetFromMidnight);

How to countdown and divide the time into segments?

I wish to do a countdown to a specific date and hour (January 10, 2018, 19:30). Which in large part I am able to do. Below code shows the remaining days, hours, minutes and seconds.
The tricky bit is to get certain periods of time. The countdown should respond to the following:
1. on the deadline day and hour show the message 'Now going live'. Which is 10 January 2018 19:30.
2. That same day but BEFORE 19:30 it should say 'Going live tonight'
3. The complete day before the deadline day (from 00:00 to 23:59) it should say 'last day'
4. The complete days before that it should say 'many days to go'
Step 1 and 2 I managed, but I'm having trouble getting the complete day before the deadline day and the complete days before that. That's because I'm not able to define the complete day before the deadline day (and the days before that). Because it counts '1 day' as 1 day before 10 January 19:30 (so it also takes those hours/minutes of 19:30 into account).
Step 1 and 2 I managed in the if-loop, but I can't figure out how to do step 3 and 4. Step 3 should say something like 'count one day, but before 10 January 2018 00:00. So it should subtract that 19:30 to get to 9 januari 2018 00:00-23:59. And the same for step 4. Can someone fix my code?
// Get todays date and time
var now = new Date().getTime();
// Set the date we're counting down to
var countDownDate = new Date("Januari 10, 2018 19:30").getTime();
// Find the distance between now an the count down date
var distance = countDownDate - now;
// Time calculations for days, hours, minutes and seconds
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Display the result
this.timeleft.text = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
// countdown day 19:30
if ((days == 0) && (hours == 0) && (minutes == 0)) {
this.countdown.text = "NOW GOING LIVE!";
// countday day 00:00 - 19.30
} else if ((days == 0) && (hours <= 19) && (minutes <= 30)) {
this.countdown.text = "GOING LIVE TONIGHT!";
// 9 January 00:00 - 23:59
} else if ((days <= 1) && (hours >= 19) && (minutes >= 30)) {
this.countdown.text = "LAST DAY";
// days before 10 January
} else if (days >= 1) {
this.countdown.text = "MANY DAYS TO GO";
}
Since the "deadline" is hard-coded, you can hard-code everything and end up with something very simple:
var now = new Date().getTime();
var lastDayThreshold = new Date("January 9, 2018 00:00").getTime();
var liveTonightThreshold = new Date("January 10, 2018 00:00").getTime();
var countDownDate = new Date("January 10, 2018 19:30").getTime();
if (now < lastDayThreshold) this.countdown.text = "MANY DAYS TO GO";
else if(now < liveTonightThreshold) this.countdown.text = "LAST DAY";
else if(now < countDownDate) this.countdown.text = "LIVE TONIGHT";
else this.countdown.text = "NOW GOING LIVE";
Alex's answer was indeed what I was after. Those 'treshhold times' did the trick. Was thinking about improving it though as now I have to hard-code three dates/times. Preferably I would like to only specify the countDownDate date/time. And then let both Threshold dates calculate themselves. I tried to do that in a way, but ran into a problem. I know how to specify one day (1000 * 60 * 60 * 24), so I could subtract this 'oneday' value to get to the day before. But I wasn't able to calculate the milliseconds for the specified time 19:30. In order to read the miilliseconds since the beginning of January 10 until January 10 19:30. If I were able to do that it would look something like this (though I know this is incorrect, but you'll get the idea):
var oneday = 1000 * 60 * 60 * 24;
var countDownDate = new Date("January 10, 2018 19:30").getTime();
var lastDayThreshold = new Date(countDownDate - oneday "00:00").getTime();
var liveTonightThreshold = new Date(countDownDate "00:00").getTime();
You'll see my problem: for lastDayTreshold I could subtract one day of the countdowndate but then it would consider that 19:30 the previous day, not 00:00. And for liveTonightThreshold I also couldn't specify that I mean 00:00 of the countdowndate.
Would there be a way of doing that? Then I would just have to specify the countdown day and time and the rest would figure them out themselves.

Is there a method to convert miliseconds to years,months,days,minutes,seconds in JavaScript?

I am trying to compare 2 dates and represent the difference( converted to miliseconds) via years,months,days,minutes and seconds.I am new in JS,I looked up for a ready method to convert miliseconds to years,months,days, minutes, seconds but didn't find.Tell me please is there such method? If not how can I do that? Simply by dividing the difference and using reminder?Thank you in advance for help.
Without having a calendar and knowing the input dates, the best you can do is be approximate.
Here is a script that shows the time elapsed since midnight last night.
var diff = Date.now() - Date.parse("July 13, 2016");
var seconds = Math.floor(diff / 1000),
minutes = Math.floor(seconds / 60),
hours = Math.floor(minutes / 60),
days = Math.floor(hours / 24),
months = Math.floor(days / 30),
years = Math.floor(days / 365);
seconds %= 60;
minutes %= 60;
hours %= 24;
days %= 30;
months %= 12;
console.log("Years:", years);
console.log("Months:", months);
console.log("Days:", days);
console.log("Hours:", hours);
console.log("Minutes:", minutes);
console.log("Seconds:", seconds);
There is no inbuilt method to convert given millisecond to equivalent seconds, minutes, hours, days, months or years.
You will have to use math. Although you will only be able to convert accurately up to days. Months and years will vary as months are either 28, 29, 30 or 31 and there are leap years.
Consider having a look at http://momentjs.com/ before you write anything on your own, as you can do a lot more with this library like adding and subtracting days or hours etc

JavaScript difference between two Date()'s in months [duplicate]

This question already has answers here:
Difference between two dates in years, months, days in JavaScript
(34 answers)
Closed 8 years ago.
I am trying to make a website that tells you (in years, months, weeks, hours, minutes and seconds) how old you are. I have got all of them working apart from months and years. Once I get the months I will be able to get the years (hopefully), however I'm having trouble thinking of a way to get the months. For the others it was easy (once I had the seconds between the birth date and the current date I could just convert seconds to minutes, to hours, to days etc.), however for months I'm going to need to take into account the fact they are all different lengths, AND leap years (which currently does not affect the days either).
Hope this helps you out
// Set the unit values in milliseconds.
var msecPerMinute = 1000 * 60;
var msecPerHour = msecPerMinute * 60;
var msecPerDay = msecPerHour * 24;
// Set a date and get the milliseconds
var date = new Date('6/15/1990');
var dateMsec = date.getTime();
// Set the date to January 1, at midnight, of the specified year.
date.setMonth(0);
date.setDate(1);
date.setHours(0, 0, 0, 0);
// Get the difference in milliseconds.
var interval = dateMsec - date.getTime();
// Calculate how many days the interval contains. Subtract that
// many days from the interval to determine the remainder.
var days = Math.floor(interval / msecPerDay );
interval = interval - (days * msecPerDay );
// Calculate the hours, minutes, and seconds.
var hours = Math.floor(interval / msecPerHour );
interval = interval - (hours * msecPerHour );
var minutes = Math.floor(interval / msecPerMinute );
interval = interval - (minutes * msecPerMinute );
var seconds = Math.floor(interval / 1000 );
// Display the result.
document.write(days + " days, " + hours + " hours, " + minutes + " minutes, " + seconds + " seconds.");
//Output: 164 days, 23 hours, 0 minutes, 0 seconds.
Would you consider an external library? Check out http://momentjs.com/
You can easily do something like
date1.diff(date2, 'months')

Categories

Resources