Moment js not adding hours and minutes to a specific time - javascript

I have a start time to which i would like to add an end time to.
for example
startTime=19:09
endTime=00:51 // 0 hours and 51 minutes
i want to add the 51 minutes to the 19:09 to make it 20:00.
I have tried multiple different scenarios as showing bellow but nothing is giving me the correct time
i tried
let [hour, minute] = endTime.split(':').map(Number);
this.endTime = Moment(startTime)).add({ hour: 'hours', minute: 'minutes' }) // also tried .add(hour,'hours').add(minute,'minutes')
which still outputs 19:09. its just ignoring my end time
i tried
Moment(endTime, 'hh:mm').add(Moment.duration(startTime)).format("hh:mm");
which gives me an output of 08:00 when it should be 20:00
What am i doing wrong?
i want to add the end time to a start time.
Keep in mind that my endTime is always changing so sometimes it could be 13:05 etc cause its a user input

There are three major issues with your code:
Creating a moment with a timestamp alone (ie something like moment('19:09') without a date) like you do is deprecated and throws an error. You either have to pass in a fully specified timestamp in RFC2822 or ISO format or explicitely tell the library, what input format you are using.
The object you are passing to the add() function literally is
{
hour: "hours",
minute: "minutes"
}
ie, instead of passing the numerical values for hours and minutes to add to your
moment, you are passing the strings "hours" and "minutes", which obviously
momentsjs can't handle.
The format hh:mm only accepts hours from 0 to 12. If you want a 24-hour clock you have to use HH:mm
Taking these issues into account, the following snippet works as expected:
let start = '2021-01-07 19:09',
duration = '0:51',
starttime = '19:09';
let [hour, minute] = duration.split(":");
//shorthand initialization for the argument
let endtime1 = moment(start).add({hour, minute}).toString();
//explicit definition of property names
let endtime2 = moment(start).add({hours: hour, minutes: minute}).toString();
//add hours and minutes separately
let endtime3 = moment(start).add(hour, "hours").add(minute, "minutes").toString();
//provide a format for the timestamp. momentsjs will take the current date for the date value
let endtime4 = moment(starttime, "HH:mm").add(hour, "hours").add(minute, "minutes").toString();
console.log(endtime1);
console.log(endtime2);
console.log(endtime3);
console.log(endtime4);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Also keep in mind, that for specifiying which part of the timestamp to manipulate, you can either use singular or plural wording. Ie
moment(...).add(4, "hour").add(17, "minute") and moment(...).add({hour: 4, minute: 17})
is equivalent to
moment(...).add(4, "hours").add(17, "minutes") and moment(...).add({hours: 4, minutes: 17})
respectively as can also be seen in the snippet with the creation of endtime1 and endtime2

You need to convert your duration into a single unit as minutes, seconds, days etc...
Then you can use the following snippet to add duration.
you can uses moment methods to convert your duration
const mins = moment.duration(10, "hour").asMinutes();
const someTime = moment('19:09',"HH:mm");
const data = someTime.add('51','minutes').format("HH:mm")
//More clever solution would be
const data2 = someTime.add(1, "hours").add(51, "minutes").format("HH:mm")
console.log(data)
console.log(data2)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Related

How to format JavaScript Date object to not let hours overflow?

Let us consider following example
const date = new Date(0);
date.setSeconds(60*60*24-1);
console.log(date.toISOString().substr(11, 8));
outputs
23:59:59
I am searching for elegant way to have
const date = new Date(0);
date.setSeconds(60*60*24+1);
console.log(date.toISOString().substr(11, 8));
output
24:00:01
instead of
00:00:01
by elegant I mean without implementing my own Date object... Maybe it would be possible to set a custom length of the day? Increase from 24h to 99h?
You can set the hour cycle in the hour cycle option (hc) and the language parameter available in the Intl.DateTimeFormat constructor and toLocaleTimeString, e.g.
console.log(
new Date(2020,7,1,0,5).toLocaleTimeString('en-CA-u-hc-h24')
);
Whether the hour cycle setting "works" or not seems to depend on the language chosen and how it's set, so maybe not that reliable. Test thoroughly in different implementations.
Many thanks to #RobG who understood my question. The hour cycle is what I needed, unfortunately according to the docs it is restricted to values h11, h12, h23, h24 and I would need h99 which is not available.
Eventually I had to make my own ugly solution as it appears such a use case was not predicted in the standard, so here it is
function unfortunatelyWeHadToWriteIt(nbsec) {
// compute numerical values
const nbhours = Math.floor(nbsec/(60*60));
const nbminutes = Math.floor((nbsec - nbhours*60*60)/60)
const nbseconds = Math.floor(nbsec - nbhours*60*60 - nbminutes*60);
// convert them to padded strings
const hours = String(nbhours).padStart(2, '0');
const minutes = String(nbminutes).padStart(2, '0');
const seconds = String(nbseconds).padStart(2, '0');
// format
return `${hours}:${minutes}:${seconds}`;
}
so let's compare it to the Date formatting
// 27 hours, 13 minutes and 6 seconds
const nbsec = 60*60*27+13*60+6;
what Date will give us
const date = new Date(0);
date.setSeconds(nbsec);
console.log(date.toISOString().substr(11, 8));
outputs 03:13:06, it overflows at value of 24 hours. Now let's apply the unfortunatelyWeHadToWriteIt function
console.log(unfortunatelyWeHadToWriteIt(nbsec))
outputs 27:13:06 which does not overflow.
Just to give you guys some context, I am playing games and displaying the playtime. It is more convenient to show number of hours than number of days of gameplay...

How can I combine the output of a date picker and time selector to make a single date.toISOString in JavaScript?

I have a date selector and a time selector, and I'm trying to figure out how I can combine their outputs to make a single ISOString so that I can use with the google calendar API.
Here's what I've tried:
//date = 2022-05-18
//time = 14:22
const apptdate = new Date(date)
const timeSplit = time.split(':')
apptDate.setHours(timeSplit[0])
apptDate.setMinutes(timeSplit[1])
What I notice is when I console.log(apptdate) this is the output I get: 2022-05-17T18:22:00.000Z
I'm not sure why it changes the day from May 18 to May 17, and the time from 14:22 to 18:22.
Does anyone have a solution for this? Or even a completely different way of combining date and time to one string (other than using a datetime-local input format, I want to keep the date and time separate in my database).
"2022-05-18" is parsed as UTC but apptDate.setHours(timeSplit[0]) sets the local hour. So if the host has a negative offset, the local date is 17 May and the time is set to the local hour on 17 May, not UTC hour on 18 May.
Instead use setUTCHours and setUTCMinutes.
let date = '2022-05-18';
let time = '14:22';
let apptDate = new Date(date);
let timeSplit = time.split(':');
apptDate.setUTCHours(timeSplit[0]);
apptDate.setUTCMinutes(timeSplit[1]);
// 2022-05-18T14:22:00.000Z
console.log(apptDate.toISOString());
PS. There was also a typo: let apptdate then later apptDate.

How to work with Moment.js to return time in a 24-hours format when adding to it?

I get hours as strings in my app, e.g. "2230". I would like to be able to add minutes to it, so as to simulate the time that it will be after those minutes have been added to it, e.g.
//"2230" + "60"mins = "23:30"
//"2230" + "180"mins = "02:30"
I read that Moment.js could be a solution to this, but I couldn't figure out:
what the right way to format the hours initially is with moment("2230").format()
how to add minutes to it
how to make it behave like a 24-hour clock when adding to it
Moment is a great tool for doing this. It takes some syntax tricks to get it right, but I think this is what you're looking for:
moment("2230", "HH:mm")
.add(60, "minutes")
.format("HH:mm")
Feel free to play around with it here:
https://codesandbox.io/s/proud-pine-lz0fs?file=/src/index.js
As you can see, as long as your time string is always 4 characters long, moment can extract the HH:mm format, then you can add minutes, and then format the final output to HH:mm again.
Here are 2 great resources:
https://techstream.org/Bits/Javascript/Javascript-Parse-time
https://flaviocopes.com/momentjs/
Hope that helps!
First you have to split this string to get the hours and minutes from it.
const s= "2230"
const hour = s.substring(0,2);
const min = s.substring(2,4);
After that you can easily pass this hours and min to a moment.
const time = moment()
.set({"hour": hour, "minute": min})
.add(60, 'minutes')
.format("HH:mm");
the .set is to set the time (hours minutes)
the .add is to add the minutes you wanted to add
the .format is to format the output as you pleased,
NOTE the capital "HH" means 24/h clock while "hh" means 12/h clock

How to convert time from UTC to say "Pacific/Easter"?

I am getting time from server as "19:30" but it needs to be converted to "Pacific/Easter time zone.
I have tried things like
let t = "19:30:00";
let utc = moment.utc(t);
let z = moment(utc).utcOffset(-300).format('HH:mm');
But I am going wrong somewhere.
I have seen in my dev app version that it is being converted to 14:30 which is like -5:00 hours.
So, how do I get similar result for this?
Here's something else that I tried
let t = "19:30:00";
let tt = moment.tz(t, "UTC");
let nt = tt.clone().tz("Pacific/Easter");
and I am getting nt as "19:30:00" also. so , it's not converting at all
this is the one that seems to be working.
but it's not showing the correct result
let t = "19:30:00";
let utc = moment.utc(t, 'HH:mm:ss');
let z = utc.tz('Pacific/Easter').format('HH:mm');
console.log(z);
it should show the result as 19:30 -5 hours which should be 14:30,
but it shows the result as 13:30. so, anyone knows why this is happening??
You have to use tz() function from moment-timezone.
Since your input (19:30:00) is not in ISO 8601/RFC 2822 recognized format you have to parse it using moment.utc(String, String) passing 'HH:mm:ss' as second parameter.
Then you can convert your moment object to given timezone using tz().
Please note that, even if you are providing only time, you are creating a moment object that includes date. As Default section of the docs states:
You can create a moment object specifying only some of the units, and the rest will be defaulted to the current day, month or year, or 0 for hours, minutes, seconds and milliseconds.
'Pacific/Easter' uses Daylight Saving Time (see full info here) so the conversion depends on date and DST.
If you want to use fixed offset (no DST), you can use utcOffset():
Setting the UTC offset by supplying minutes. Note that once you set an offset, it's fixed and won't change on its own (i.e there are no DST rules).
If the input is less than 16 and greater than -16, it will interpret your input as hours instead.
Here a live sample:
let t = "19:30:00";
let utc = moment.utc(t, 'HH:mm:ss');
let z = utc.tz('Pacific/Easter').format('HH:mm');
console.log(z);
// DST
console.log( moment.utc('2018-09-01 19:30:00').tz('Pacific/Easter').format('HH:mm') );
// No DST
console.log( moment.utc('2018-06-01 19:30:00').tz('Pacific/Easter').format('HH:mm') );
// Fixed offset
console.log( moment.utc('19:30:00', 'HH:mm:ss').utcOffset(-5).format('HH:mm') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.17/moment-timezone-with-data-2012-2022.min.js"></script>
You need moment-timezone to get this working.
var newYork = moment.tz("2014-06-01 12:00", "America/New_York");
var losAngeles = newYork.clone().tz("America/Los_Angeles");

Moment.js how to use fromNow() to return everything in hours?

I've searching the moment.js docs and stackoverflow for a way to use the fromNow() function but returning everything in hours.
What I mean is:
moment([2017, 01, 05]).fromNow(); // a day ago
should be
moment([2017, 01, 05]).fromNow(); // 24 hours ago
I know it's possible to do this using .diff and probably other similar functions and then adding the text, but is it possible to use .fromNow() to do this?
You can use relativeTimeThreshold to customize thresholds for moment relative time.
As the docs says:
duration.humanize has thresholds which define when a unit is considered a minute, an hour and so on. For example, by default more than 45 seconds is considered a minute, more than 22 hours is considered a day and so on. To change those cutoffs use moment.relativeTimeThreshold(unit, limit) where unit is one of s, m, h, d, M.
In your case, you can increase hour thresholds to get relative days as hours. Here a working example showing time as hours from 1 hour to 26 days:
var m1 = moment().subtract(5, 'h');
var m2 = moment().subtract(55, 'h');
var m3 = moment().subtract(1, 'd');
// Default results
console.log(m1.fromNow());
console.log(m2.fromNow());
console.log(m3.fromNow());
// Change relativeTimeThreshold
moment.relativeTimeThreshold('m', 60);
moment.relativeTimeThreshold('h', 24*26);
// Results in hours
console.log(m1.fromNow());
console.log(m2.fromNow());
console.log(m3.fromNow());
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
Note that, if you need, moment lets you customize relative time further with relativeTime (here one of my examples) and relativeTimeRounding method.
If you definitely want to use fromNow(), I don't see any way other than overriding moment's built-in function. For example, you can override it to return the difference in hours as follows:
moment.fn.fromNow = function (a) {
var duration = moment().diff(this, 'hours');
return duration;
}
Then you can check that fromNow() returns the value in hours:
console.log(moment([2017,0,6]).fromNow());
which returns:
19
Note: Tried at 19:00 :)

Categories

Resources