Javascript parsing Times without Date - javascript

I need to parse and manipulate Times without Dates in my code. For example i might get the string "15:00" from a timepicker. I want to turn this into a Time object of some kind - I normally work in Python which has distinct Date, Time, and Datetime objects.
However all the solutions i've seen focus on using the Date object. This cannot parse a string like "15:00" since it requires day information. I don't want to add arbitrary Date information to Times - especially since Date appears to make assumptions about things like daylight saving depending on the day and the locale, and there appears to be a risk of it automatically attempting to translate the time into a given locale. Furthermore I want to be able to add times, e.g. "15:00 + 1 hour"
What is the recommended solution to parse and handle "raw" times not associated to dates?

Here's a moment.js solution for 12 or 24 hour times:
moment('7:00 am', ['h:m a', 'H:m']); // Wed Dec 30 2015 07:00:00 GMT-0600 (CST)
moment('17:00', ['h:m a', 'H:m']); // Wed Dec 30 2015 17:00:00 GMT-0600 (CST)
moment('17:00 am', ['h:m a', 'H:m']);// Wed Dec 30 2015 17:00:00 GMT-0600 (CST)
moment('17:00 pm', ['h:m a', 'H:m']);// Wed Dec 30 2015 17:00:00 GMT-0600 (CST)
http://momentjs.com/docs/#/parsing/string-formats/

Unfortunately, there's not a great solution. JavaScript only has a Date object, which is probably misnamed since it is really a date+time.
One thing you might want to think about deeper - you say you want to work with only time, but do you mean a time-of-day or do you mean a duration of time? These are two related, but slightly different concepts.
For example, you said you might want an operation like "15:00 + 1 hour". Well that would clearly be 16:00 either way. But what about "15:00 + 10 hours"? It would be 25:00 if you are talking about a duration, but it might be 01:00 if you are talking about time-of-day.
Actually, it might not be 01:00, since not all days have 24 hours in them. Some days have 23, 23.5, 24.5, or 25 hours, depending on what time zone and whether DST is starting or stopping on that day. So in the time-of-day context, you probably do want to include a particular date and zone in your calculation. Of course, if you are talking about straight 24-hours days, then this point is irrelevant.
If you are talking about durations - you might want to look again at moment.js, but not at the moment object. There is another object there, moment.duration. The reference is here.
And finally, you might want to consider just using plain javascript to parse out hours and minutes from the time string as numbers. Manipulate the numbers as necessary, and then output a string again. But your question seems like you're looking for something more managed.

I ended up using the following since I was already using moment in my app:
var str = '15:16:33';
var d = new moment(str, 'HH:mm:ss');
See Moment String+Format docs for other format strings you can use.

And I know I am over 8 years late to this party, but it is worth noting that moment.js is no longer being developed and is on a pacemaker for maintenance. They actually do NOT recommend using moment.js for new apps.
More details are found here: https://momentjs.com/docs/

I had to do this recently for a project but didnt really need to include moment.js, the method I used was to manually parse the time like this:
function parseTime(time) {
let timeInt = parseInt(time);
let minutes = time.substring(3,5);
// you could then add or subtract time here as needed
if(time > '12:00') {
return `${timeInt - 12}:${minutes} PM`;
} else {
return `${timeInt}:${minutes} AM`;
}
}
Use this as an alternative starter if you don't want to use moment. Note this example uses es6 syntax.

Okay, so I know I'm way late to the party. Like 6 years late but this was something I needed to figure out and have it formatted HH:mm:ss (24 hours).
moment().format(moment.HTML5_FMT.TIME_SECONDS); // 17:44:56
You can also pass in a parameter like, 2019-11-08T17:44:56.144.
moment('2019-11-08T17:44:56.144').format(moment.HTML5_FMT.TIME_SECONDS); // 17:44:56
https://momentjs.com/docs/#/parsing/special-formats/

I know I am writing this 8 years later but it's no longer advisable to use the moment.js library nowadays since it's no longer supported, luxo.js is the preferred(like the evolution of moments.js) one you can find more here: https://moment.github.io/luxon/api-docs/index.html

We know that the Date class in JavaScript must always contain a date, and entering time alone is not enough.
But when asked, I do not need to enter a date. This could mean:
You intend to compare two dates with each other.
The two dates are shared on the same day.
If so, then as a trick, you can add a specific date(any date) to your time as string. (E.g. 0000-01-01 )
For example, this code is incorrect:
var d1 = '00:53:57.123';
var d2 = '00:53:58.124';
console.log(new Date(d2).getTime() - new Date(d1).getTime());
//result: NaN
But this way you can get the right result:
var d1 = '00:53:57.123';
var d2 = '00:53:58.124';
d1 = '0000-01-01 ' + d1;
d2 = '0000-01-01 ' + d2;
console.log(new Date(d2).getTime() - new Date(d1).getTime());
//result: 1001

Related

JavaScript date.setMilliseconds strange behavior?

Why does this happen -
var date = new Date('2015-10-24T23:31:04.181Z');
date.toISOString(); // "2015-10-24T23:31:04.181Z"
date.setMilliseconds(date.getMilliseconds() + 1);
date.toISOString(); // "2015-10-24T22:31:04.182Z"
The HOUR has moved one back (23 -> 22)
Works fine with other dates
Is it a time zone issue ? Why doesn't it happen with all date values ?
Thanks
It's daylight savings time, in a really non-obvious way. :-)
2015-10-24T23:31:04.181Z in Jerusalem is Oct 25 2015 01:31:04 GMT+0200 (Jerusalem Standard Time) on the date/time when DST ends and the clocks go back (reference). Specifically, it's within the Groundhog Hour: There are two 01:31:04s that day, first the one in summer time, then the one an hour later in standard time.
You're using setMilliseconds, which is a local time function. As you probably know, JavaScript's Date is smart about handling rollover between date fields (although there is no rollover in this particular case), and so the logic of setMilliseconds has to handle allowing for possible rollover. This is detailed in the specification, but fundamentally it takes the current time value (milliseconds since The Epoch), makes a local date/time out of it, does the work, and then has to turn that local date/time back into a new time value.
But here's where the problem kicks in: Those two 01:31:04s that day. V8 has to choose one when determining the real date/time. It chooses the one in summer time, which is an hour earlier than your original date/time.
If you use setUTCMilliseconds, this doesn't happen, because there's no round-trip to local time.
Moral of the story: If you're working in UTC, work exclusively in UTC. :-)

Comparing 2 dates with momentJS

I am trying to compare a DAY/TIME e.g. Monday 09:00:00 with the current time to see if I am past that point in the week. e.g. If it is now 05:00:00 on Monday it should return true however it is returning false everytime
var dayTime = Moment("Wednesday 17:00:00", "dddd HH:mm:ss");
var now = Moment(Moment.now(), "dddd HH:mm:ss");
console.log(Moment.utc(dayTime).isBefore(now)); //returns false all the time
I found the following similar questions but it didn't seem to fix the issue after formatting the time.
Comparing two times with Moment JS
When I replace the moment.now() with a string such as "Wednesday 17:00:00" it returns the expected result.
Any idea what I need to do to moment.now() in order for this to work correctly?
Moment.now can be used as an extension point, but it's really not a public API. To get the current time in momentjs you just call moment(). Note that all moment calls use lowercase moment.
To see if your date and time is before the current time, you would just call:
moment('01/01/2016', 'MM/DD/YYYY').isBefore(moment())
You would replace the date and format in question with your own.
I see that you have a date format that includes only day of week and time. Moment will parse this, but be aware that the behavior might not be what you expect. When I parse your date, I get Wednesday December 30, 2015. Exactly what day this lands on will vary by locale. In any case, I doubt that it is what you want. If at all possible, I would get year, month, and day.
If you would like to instead set the moment to Wednesday this week, set the day on the moment using .day(). For instance:
moment().day(3).format()
"2016-06-15T20:19:55-05:00"
For anyone who is interested, the code I posted in my question was changing the day/hour but was setting the year to 2015 which meant that it was always in the past.
To fix I separated out the Day and the Hour and set to moment. Then compared that with now. e.g.
moment().set({"Day": "Friday", "Hour": "17"}).isBefore(moment())

momentjs days difference between two GMT dates

I'm trying to get difference of days between two GMT dates using moment
but I couldn't find it.
I'm on IST(+05:30) and I have some GMT dates(-05:00) in db,
I tried using following command
temp2.diff(temp1, "days")
here is a screenshot of all the commands tried in console
there we can clears see that dates are different and still shows the difference is 0
here is how I'm initializing moment objects of 'America/New_York'
var temp1 = moment.tz(new Date('Mon Jan 25 2016 22:00:00 GMT-0600'), 'America/New_York');
var temp2 = moment.tz(new Date('Tue Jan 26 2016 00:00:00 GMT-0600'), 'America/New_York');
any help appreaciated, thanks.
Well, there is less than 24 hours difference between those dates, so it's correct. The documentation says:
By default, moment#diff will return number rounded down. If you want the floating point number, pass true as the third argument.
> temp2.diff(temp1, "days", true)
0.08333333333333333
If you don't care about the hours at all, set them to 0 before you do the comparison
> temp2.hours(0).diff(temp1.hours(0), "days")
1
A few things:
You say that you are retrieving these values from a database, but then you show us loading them via the Date constructor from a string value. If you are really storing a string in your database, especially in that particular format, then you have much larger problems than the one you asked about! Please show us precisely how you load the values from your database to begin with.
You shouldn't rely on the Date object for parsing, especially when you are already using moment, which has much better parsing routines of its own.
You said these values where in America/New_York, but then you show an offset of -0600. That's never used in that time zone. The offset for the value you showed would be -0500.
You also said "I have some GMT dates(-05:00)" - which doesn't make any sense. GMT is +00:00. GMT-0500 means "5 hours behind GMT". Thus, you no longer have a "GMT date".
Be aware that the JavaScript Date object can only use the time zone of where the code is running. You cannot run it in any other time zone.
While Felix is correct in how you can show decimals with the diff function, you should realize that diff is giving you the actual elapsed time between the two moments in time you asked about. However, you seem to be wanting to know the total number of calendar days separating the two days that the moments fall into within the named time zone. To do that, you'd need to ignore the time portion. Using startOf('day') is an easy way to do that. Consider:
var a = moment.parseZone("2016-01-25T23:00:00-05:00");
var b = moment.parseZone("2016-01-26T01:00:00-05:00");
b.diff(a, 'days', true) // 0.08333333333333333 (not what you want)
b.startOf('day').diff(a.startOf('day'), 'days') // 1 (that's better!)
moment(b).startOf('day').diff(moment(a).startOf('day'),'days') // 1 (best approach)
Note a few things with this code:
The code in the last line is the best approach, as it leaves the original values of a and b alone. Otherwise, they would be modified. (Moments are mutable.)
You seem to already have the correct local time and offset, and thus there's no need to use moment-timezone's tz function. You can just use parseZone. Of course if this was just a side effect of your example, then you could still use moment-timezone, but I'd strongly recommend against using the Date constructor still.

DatePicker Error in Angular JS due to UTC

I have selected the 12th of September 2014 in the UI.
Following is the code
ctrl.$formatters.push(function (modelValue) {
console.log(modelValue);
var dt = new Date(modelValue);
dt.setMinutes(dt.getMinutes() + dt.getTimezoneOffset());
console.log(dt)
return dt;
});
The two console logs i see are the following.
09/11/2014
Wed Sep 10 2014 18:30:00 GMT+0530 (IST)
Am not sure why the conversion from UTC to local is not carried out correctly.
Thanks in advance.
Its not clear what you are trying to do. The input does not have a time. Do you want to add the current time of the day to the arbitrary date? Or do you just want a local representation of the date? I'm geussing the latter.
Instead of dt.setMinutes(...) and the following two lines, replace all three lines with:
return dt.toLocaleDateString();
If you ARE trying to set the time to now on whatever date is input (I don't know why...) but you might try:
dt.setTime( new Date().getTime() );
instead of the setMinutes(...) line.
then you can
return dt.toLocaleString;
All date objects are stored as miliseconds since, like 1972. It is best to use the built in Date object methods to get what you want from it. Here are the docs for reference.

Dealing With Futre and Past Dates and Times with JavaScript Date Object

I am trying to get future and past dates programatically based on the current time. I am not sure if I am just dumb or I am truly doing something wrong. So I have 2 questions
Does Node.js or the V8 engine have getMinutes, getMonth, etc... in it? I ask because when I try them I get a has no method errors for each of them with regards to a Date object?
Second question is: is there a resource I have missed on how to deal with dates in Node/V8 that I have just missed somewhere?
At the end of the day I am trying to get a date object that is from an hour ago and an hour into the future. Also 5 minutes ago and 5 minutes in the future. It doesn't seem like it should be that hard, but I have been spinning my wheels for a couple of hours now.
Also do it without a 3rd party javascript module.
Here is one, of many, attempt with little luck:
var d1 = Date();
console.log(d1);
console.log(d1.getMonth());
error:
TypeError: Object Sun May 13 2012 20:28:01 GMT-0500 (CDT) has no method 'getMonth'
Another example this time from REPL: (Should this not be "march 3 2012 at 3:03:03")?
d1 = new Date(2012,3,3,3,3,3)
> Tue, 03 Apr 2012 08:03:03 GMT
When the Date constructor is called as a function, it returns a string, not a date object. Change your code to:
var d1 = new Date();

Categories