I've seen a lot of functions to convert dates around but couldn't find anything specific on how to convert Days:Hours:Minutes:Seconds to milliseconds.
So here is a basic function I've made to help you guys out. This is useful if you're coding a stopwatch, clock or anything like that.
Normally I've seen this done inline without using a utility function, but if you're going to create a util let's make it extensible.
I disagree with the arguments Array, it's difficult to remember what represents what. Unless you're only doing day/hour/minute/second, this can get confusing. Additionally, unless you're always using every parameter this becomes cumbersome.
It's incorrect for zero values (passing 0 for any value causes it to be incorrect)
const conversionTable = {
seconds: 1000,
minutes: 60*1000,
hours: 60*60*1000,
days: 24*60*60*1000,
};
const convertTime = (opts) =>
Object.keys(opts).reduce((fin, timeKey) => (
fin + opts[timeKey] * conversionTable[timeKey]
), 0)
console.log(convertTime({
days: 5,
hours: 4,
minutes: 2,
seconds: 19,
}));
console.log(convertTime({seconds: 1}));
function convertDhms(d,h,m,s){
d <= 0 ? d=1 : d=d*24*60*60*1000;
h <= 0 ? h=1 : h=h*60*60*1000;
m <= 0 ? m=1 : m=m*60*1000;
s <= 0 ? s=1 : s=s*1000;
return d + h + m + s;
}
Usage:
var finalDate = convertDhms(5, 4, 2, 19); /* will convert 5 days, 4 hours, 2 minutes and 19 seconds to miliseconds. Keep in mind that the limit to hours is 23, minutes 59 and seconds 59. Days have no limits. */
I suppose a simple solution is to use the Date object's parse method, which gives back the milliseconds of the object. The catch is that it's meant to return the time from the UNIX Epoch time.
// see docs for Date constructor
const baseDate = new Date(0,0,0,0,0,0,0);
const baseMS = Date.parse(baseDate);
// base milliseconds is not zero
// it defaults to a day before Jan 1, 1970 in ms
console.log(baseMS);
function convertToMS(dy,hr,mn,s,ms) {
const date = new Date(0,0,dy,hr,mn,s,ms);
const dateMS = Date.parse(date);
return dateMS - baseMS;
}
// one day in milliseconds
console.log(convertToMS(1,0,0,0,0));
console.log(24 * 60 * 60 * 1000);
P.S. I don't quite understand the logic behind why a new Date object with zero in all parameters returns a large negative value, but we have to account for that in the code.
EDIT: Since there's is a discrepancy between the number of days in each month, and days in each year, it's better to not have year and months in the input of the function convertToMS.
Related
I have date time strings with the following format: YYYY-MM-DD HH:MM:SS.SSSSSS
For example:
const d1 = '2022-07-03 03:45:15.679570'
const d2 = '2022-07-03 03:45:15.679638'
What I'd like to achieve is the ability to subtract these date times, e.g. in the above example the result would be:
console.log(subtractDates(d1, d2)) // -0000-00-00 00-00-00.000068
console.log(subtractDates(d2, d1)) // 0000-00-00 00-00-00.000068
I was looking for different libraries but they all have resolution of 0-999 ms and that's it.
The subtraction of dates becomes ambiguous when months are subtracted. For instance, there are several possibilities on how to represent the difference between 2022-03-31 and 2022-02-28. If this is considered to be a difference of 1 months and 3 days, then what if we add one day to both dates? Is then the difference (of the same number of days) suddenly an exact month?
To avoid this ambiguity, I would suggest to express the difference in a number of days (and smaller units of time) even when that number of days exceeds a month or even a year. Just keep the greatest unit of measure to the day when dealing with durations.
Here is a pair of classes that could easily be extended to provide more functionality. The general idea is to use the numeric system of the native Date type, but to multiply it by 1000.
class MicroDuration {
constructor(us) {
this.us = Math.abs(us); // Don't work with negative durations.
}
toString() { // dddddd hh:mm:ss.ssssss
return (Math.floor(this.us / 86_400_000_000) + " "
+ new Date(Math.floor(this.us / 1000)).toJSON().slice(11, 23)
+ (this.us % 1000 + "").padStart(3, "0")
).padStart(22, "0");
}
}
class MicroDate {
constructor(iso) {
iso = iso.replace(" ", "T").replace(/\d$/, "$&Z");
this.us = Date.parse(iso) * 1000 + parseInt(iso.slice(-4));
}
diff(arg) {
if (!(arg instanceof MicroDate)) arg = new MicroDate(arg);
return new MicroDuration(this.us - arg.us);
}
toString() {
return new Date(Math.floor(this.us / 1000)).toJSON()
.replace("Z", (this.us % 1000 + "").padStart(3, "0"))
.replace("T", " ");
}
}
// Demo
const d1 = '2022-07-03 03:45:15.679570'
const d2 = '2024-08-03 15:45:15.678638'
const diff = new MicroDate(d1).diff(d2).toString();
console.log(diff);
Hobbyist coder here, and this problem is above my pay grade. I'm trying to build a dynamic html / css calendar, where the cells are filled in based on today's date. I get today's date, and then try to add days to fill in another 13 days (looping thru html elements.innerHTML).
If I try to setDate(30 + 2) and then getDate(). The code works fine. Javascript figures out that June ends at the 30th day, and the result is 2 as desired (July 2nd)
But this only works if there's only one call, if I have a loop, or call this code multiple times, then the result is different. Is there some async stuff gumming up the works? Here's code:
If you leave the "result2" call and comment the others, works great, but multiple calls, things break and numbers get repeated. Please help!
const theDate = new Date();
const todaysDate = 30;
theDate.setDate(todaysDate + 1);
let result1 = theDate.getDate();
theDate.setDate(todaysDate + 2);
let result2 = theDate.getDate();
theDate.setDate(todaysDate + 3);
let result3 = theDate.getDate();
theDate.setDate(todaysDate + 4);
let result4 = theDate.getDate();
console.log(result1);
console.log(result2);
console.log(result3);
console.log(result4);
June has 30 days but July has 31 days.
When you set the date to 32 for the first time, you are setting it to the 32nd of June and the dates after June 30 push it to July 2nd. (32-30=2)
When you set to 32 again, it is already July so the dates after July 31 push it to August 1st (32-31=1).
In answer to your question, the setDate() function is behaving so strangely for you because each time you are setting the date you are setting it relative to the previous setting, so incrementing each time by 31, 32, or 33 days instead of by 1, 2, or 3. See the brilliant answer by #Quentin for more information, this finding was entirely his and I just wanted to mention the root cause in my answer as well as my own fix to your problem.
An alternative solution if you just want to generate the dates:
const dayOfMonth = 30;
const date = new Date();
date.setDate(dayOfMonth);
console.log("Date:", date);
let timestamp = Date.parse(date);
for (let i = 1; i <= 14; i++) {
const newTimestamp = timestamp + i * (1000 * 60 * 60 * 24);
const newDate = new Date(newTimestamp);
console.log("New date:", newDate);
}
This method will manipulate the timestamp and generate new dates for each of the timestamps added to the number of milliseconds in a day.
You could use your date logic within the loop to populate the calendar as you mentioned.
If you use the Date() constructor on each iteration, you don't have to worry about the varying days of a particular month.
Details are commented in example
/**
* #desc - return a range of dates starting today (or a given
* date) and a given number of days (including start)
* #param {number} range - The number of days
* #param {string<date>} start - The date to start the range
* if not defined #default is today
* #return {array<date>} An array of dates
*/
function dayRange(range, start) {
// If undefined default is today
let now = start ? new Date(start) : new Date();
// Create an array of empty slots - .length === range
let rng = [...new Array(range)];
/*
.map() through array rng
If it's the first iteration add today's date...
... otherwise get tommorow's date...
and return it in local format
*/
return rng.map((_, i) => {
if (i === 0) {
return now.toLocaleDateString();
}
let day = now.getDate() + 1;
now.setDate(day);
return now.toLocaleDateString();
});
}
console.log("Pass the first parameter if the start day is today");
console.log(JSON.stringify(dayRange(14)));
console.log("Pass a properly formatted date string as the second parameter if you want to start on a date other than today");
console.log(JSON.stringify(dayRange(10, '05/12/2020')));
If I have two values, each representing a date such as YYYYMMDDHHMM (YearMonthDayHourMinute) like:
202012141800
202012141614
What I was trying to convey in the question is that this gives me 186 minutes, but this isn't accurate, however, since the last two digits will never be larger than 59 given 60 minutes in an hour. The 100 in 186 comes from hours 18 (6pm) and 16 (4pm).
How can I subtract these in Javascript to account for the extra 40 minutes tacked on if the two timestamps are more than an hour apart?
I have this, but it's not that efficient since I'd need to know the maximum number of hours two timestamps could be apart:
var end_time = $('#the-agenda li.current time').data('end-time'),
time_now = current_display_number,
timer_duration = end_time - time_now;
if (timer_duration > 200) {
// if more than 2 hours, subtract 80 minutes
timer_duration = timer_duration - 80;
}
else if (timer_duration > 100) {
// if more than 1 hour, subtract 40 minutes
timer_duration = timer_duration - 40;
}
I feel like the answer may somehow be in this question's answer, but I am not sure how to apply that parseInt to this situation.
You wouldn't use parseInt. You would use Date.parse, except that the string has to be in a predefined format. Without using a specialized library, you'll have to parse the parts yourself and then create a new Date with the parts. Fortunately though the incoming strings seem straightforward to parse. Do something like this:
let startTimeStr = '202012141614';
let endTimeStr = '202012141800';
let asDateTime = (d) => new Date(
d.substring(0,4),
d.substring(4,6) - 1,
d.substring(6,8),
d.substring(8,10),
d.substring(10,12)
)
let startTime = asDateTime(startTimeStr);
let endTime = asDateTime(endTimeStr);
let result = (endTime - startTime) / 60000;
console.log(result);
// Different in milliseconds
const difference = (new Date('2020-12-14T18:00:00')) - (new Date('2020-12-14T16:14:00'));
const inMinutes = Math.floor(difference / 60000);
You need to convert the string formats to a date object to get accurate date info.
I'm writing a function that calculates how many days ago a given date was from today. (e.g. yesterday = 1, last week = 7, today = 0, tomorrow = -1 and so on)
Seemed simple enough, and using the JavaScript Date() function I initially wrote this:
let historicalDate = new Date(2017,05,17).getTime(); // example date: last week
let diff = Math.round((new Date().getTime() - historicalDate) / (24*60*60*1000) );
After I got some weird results, I neatened up the code, but still got the same issue, as follows:
/**
* Returns an integer, representing the number of days since a given date
**/
function getNumDaysFromDate(historicalDate){
const day = 24*60*60*1000; // The number of milliseconds in one day
const now = new Date().getTime(); // The time right now
const then = historicalDate.getTime(); // The time comparing to
return Math.round((now - then) / day ); // Find difference in milliseconds, then days
}
// Test1: last week, should return 7
let creationDate1 = new Date(2017,05,17);
console.log("Last week:", getNumDaysFromDate(creationDate1)); // Fail, prints -23
// Test2: yesterday, should return 1
let creationDate2 = new Date(2017,05,23);
console.log("Yesterday:", getNumDaysFromDate(creationDate2)); // Fail, prints -29
// Test3: Today, should return 0
let creationDate3 = new Date();
console.log("Today:", getNumDaysFromDate(creationDate3)); // Pass, prints 0
// Test4: day affer tomrrow, should return -2
let creationDate4 = new Date(2017,05,26);
console.log("Future:", getNumDaysFromDate(creationDate4)); // Fail, prints -32
All the above results appear to be all about 1 month out, (except for 'test 3', today).
I'm sure there is an obvious or simple reason for this, that one of you will spot instantly, but I have spent the last couple of hours mind-blown by it!
Thanks in advance!
Edit: If possible, I'd like to avoid using a library like Moment.js, as this should be possible nativity (?), and is the only date-related calc in my application.
Be careful: the Javascript date API is completely insane (exactly like the Java date API).
Month starts with 0 (January) and goes up to 11 (December). So new Date(2017,5,17) actually means June 17th 2017.
remind the months in JavaScript are zero based (Jan = 0, Feb = 1, ...). So if you need may it's 4 (not 5).
/**
* Returns an integer, representing the number of days since a given date
**/
function getNumDaysFromDate(historicalDate){
const day = 24*60*60*1000; // The number of milliseconds in one day
const now = new Date().getTime(); // The time right now
const then = historicalDate.getTime(); // The time comparing to
var value = Math.round((now - then) / day );
if(value == 0){
return 0
}
else{
return value+30;
}// Find difference in milliseconds, then days
}
// Test1: last week, should return 7
let creationDate1 = new Date(2017,04,17); // 17th of May 2017
console.log("Last week:", getNumDaysFromDate(creationDate1)); // Fail, prints -23
// Test2: yesterday, should return 1
let creationDate2 = new Date(2017,04,23); // 23 of May 2017
console.log("Yesterday:", getNumDaysFromDate(creationDate2)); // Fail, prints -29
// Test3: Today, should return 0
let creationDate3 = new Date();
console.log("Today:", getNumDaysFromDate(creationDate3)); // Pass, prints 0
// Test4: day affer tomrrow, should return -2
let creationDate4 = new Date(2017,04,26); // 26th of May 2017
console.log("Future:", getNumDaysFromDate(creationDate4)); // Fail, prints -32
Okay so what i'm trying to do is get the time values between 2 different dates.
For example:
date1 = 3/2/2014 - 14:12
date2 = 4/2/2014 - 16:22
How would I get the time difference between date1 and date2? (26hrs, 10mins) <- that would be the perfect output for what I want.
I've had a look at the parse method and if I understand it correctly, I think I could make that work by doing something like:
myDate = date1;
myDate.parse(date2);
then convert the output to how I wanted it from there, but I haven't seen any examples where it takes the time of day into consideration.
You just need to subtract the two Date object to get the difference since JavaScript will convert it to the right type automatically:
date1 - date2 //difference in milliseconds
For formatting, you can set up a function similar to this:
Number.prototype.format = function(){
return [
(this/86400|0), "days",
(this/3600|0) % 24 , "hours",
(this/60|0) % 60 , "minutes",
(this|0) % 60 , "seconds"
].join(" ");
};
((date1 - date2)/1000).format(); //Formatted string
Demo: http://jsfiddle.net/DerekL/Prb7j/ (Time formatting also included)
You could use the Date class and then just subtract the 2 dates
var difference = ( new Date(2014, 2, 4, 16, 22, 0).getTime()
- new Date(2014, 2, 3, 14, 12, 0).getTime()
) / 1000
getTime() gives you the time in milliseconds, so you have to divide by 1000 to get the result in seconds.