isSame meridiem with moment.js? - javascript

Is there a way to check if two dates have the same meridiem (am/pm) with moment.js?
In the docs the isSame function provides examples of testing for day, month, etc., but not for meridiem.

Nothing built in to do that exact comparison, but you could just format both moments as just the meridiem token (a) and compare the result.
moment().format('a') === moment('2016-01-01T11:00').format('a')
This has the advantage of actually working with any locale. In some locales, they have more Meridiem indicators than just AM/PM. Take for example Azerbaijani:
moment.locale('az')
moment('2016-01-01T02:00:00').format('hh a')
"02 gecə"
moment('2016-01-01T05:00:00').format('hh a')
"05 səhər"
moment('2016-01-01T13:00:00').format('hh a')
"01 gündüz"
moment('2016-01-01T18:00:00').format('hh a')
"06 axşam"
Looking in the source code, I also see this for Belarusian, Bengali, Tibetan, and the list goes on and on.
If you want a full list, go to the locales folder in Moment's source:
https://github.com/moment/moment/tree/develop/src/locale
Within every locale, you will see a meridiem function. This defines the behavior you get for that token.
If you don't want this behavior, and you want your code to always just run as 'before noon' or 'after noon', you can always just quick flip a clone of the moment back into the default locale:
moment('2016-01-01T18:00:00').clone().locale('en').format('a')

It doesn't seem to exist in moment.js indeed. Shouldn't be that hard though:
Math.floor(time1.hour()/12) == Math.floor(time2.hour()/12);
If you are planning to use this a lot and want to make things easier on yourself, you could even add it to Moment yourself (I'll probably receive some strong arguments against extending third party libraries, but it is just so convenient...)
Something like this:
moment.prototype.isSameMeredian = function(compareWith) {
if (! moment.isMoment(compareWith)) {
return false; // or throw an error or something
}
return Math.floor(this.hour()/12) == Math.floor(compareWith.hour()/12)
}
and you could use it like this:
var time1 = moment();
var time2 = moment().subtract(12, 'hours');
var time3 = moment().add(5, 'minutes');
console.log(time1.isSameMeredian(time2), time1.isSameMeredian(time3));
This should log false true, except between 11:55 and 12:00, where the second outcome should be false as well for obvious reasons.

Related

Changing Date time zone in Javascript?

I have a date in UTC format `2020-06-19T03:55:12.000Z. Now i am converting into date of US timezone as
let syncDate = moment(date, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
.subtract(7, 'hours')
.format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
This gives me a date 7 hours behind which is date of US. But i want a date in below format
2020-06-18T21:00:24.523-07:00
Here if we can see the hours are defined as -7 so please guide how can we achieve the same ?
You can't extract a timezone out of your date because there is no timezone information in it. You said "I am converting into a date of US timezone as" But you didn't. You just reduced it for 7 hours. The timezone is still UTC.
You should use moment-timezone (not handling things the hard way and manually as #GetSet said). Here the solution:
const moment = require('moment');
const tz = require('moment-timezone');
let date = moment('2020-06-19T03:55:12.000Z');
let syncDate = date.tz('America/Los_Angeles')
console.log(syncDate.format());
But, I suggest you use Day.js. The code will be:
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const dDate = dayjs('2020-06-19T03:55:12.000Z');
console.log(dDate.utcOffset(-7*60).format()); //2020-06-18T20:55:12-07:00
I used moment.js in the past. I tried Date-fnd for 24 hours. And finally, I moved to Day.js. It's new (start in late 2018) but it's growing so quick (take a look at this link and put the duration on 5 years). The great thing about it is that "IT ALWAYS DOES WHAT IT SAYS". Moment and Date-fns don't. (not always). It uses a wrapper and so you never work with the Date object directly. It solves difficulties and problems. It's immutable and always returns a new object and you can chain functions. Day.js has the smallest size (2kB).The documentation is awesome and you can up and running very fast. (It's more understandable that the way other libraries work.)
Here I have to say that Dayjs performance is not is good as Moment in calculations but is way better (than especially moment) in parsing and formating.
I strongly suggest you read this article: Why you shouldn't use Moment.js
Edit(1): As #GetSet mentioned in comments for OP that may need a solution in Moment.js I added it to the answer.
Edit(2): Adding the reason why you can't achieve your result the way OP solving it.
new Date() depends on local computer date setup - if any user has wrong date on his local computer - your system will take wrong dates from those users.
If you working with dates on background (storing in database or any other manipulations) - generate it on background (php, java etc.) and than send it to you html/javascript files.
you can use Date().toLocalString() method
// example:
var d = new Date().toLocalString("en-US", {
month: "long",
day: "2-digit",
year: "numeric",
});
for more information see:
https://www.w3schools.com/jsref/jsref_tolocalestring.asp
There are a couple of things it is vitally important to point out here.
There is no one US timezone, there are quite a few, for example America/Los_Angeles, America/Denver, America/Chicago, America/New_York, see the IANA Timezone list for all of them.
Please don't convert from one timezone to another using a fixed offset, this is really fragile. You wouldn't believe how many bugs I've seen in my career (from others, and yes, from myself!) due to this one mistake. Many timezones use Daylight Saving Time, so the UTC offset of the timezone varies by the date. For example, the Pacific Timezone currently varies between UTC-08:00 and UTC-07:00.
I would suggest using Moment Timezone to convert from one timezone to another.
For example:
const dateString = `2020-06-19T03:55:12.000Z`;
const timezones = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles"];
console.log(`Time in UTC:`, moment(dateString).toISOString());
// Show the time in each timezone
timezones.forEach(timezone => {
let timeLocal = moment.tz(dateString, timezone);
console.log(`Time in ${timezone}:`, timeLocal.format('YYYY-MM-DD[T]HH:mm:ss.SSSZ'))
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js">
</script>

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.

Is there a way to parse a relative date using Moment.js?

Moment.js is a very usefull JavaScript library which provides many functions to manipulate date formatting.
In order to create a Moment object, it is possible to parse a string simply moment("1995-12-25"); or by providing format moment("12-25-1995", "MM-DD-YYYY");.
Another feature allows us to use relative dates : moment("1995-12-25").fromNow() // 19 years ago.
However, I can not find a way to parse such a relative date. When I try moment("19 years ago") it just returns Invalid date, and it does not exist any token to properly format the date.
Is there an easy way to do this? Or is it a missing feature that should be suggested on Github?
Just found chrono wile looking to see if NLP had already been implemented in momentjs. It looks like it handles parsing NLP to a date, which can be used to create a momentjs date.
Simply pass a string to function chrono.parseDate or chrono.parse.
> var chrono = require('chrono-node')
> chrono.parseDate('An appointment on Sep 12-13')
Fri Sep 12 2014 12:00:00 GMT-0500 (CDT)
And a quick example showing how that would work
Code
const moment = require('moment')
const chrono = require('chrono-node')
let now = moment()
console.log(now)
let yrsAgo = chrono.parseDate("19 years ago")
console.log(yrsAgo)
let yrsAgoMoment = moment(yrsAgo)
console.log(yrsAgoMoment)
Output
$node test.js
moment("2017-06-30T08:29:20.938")
1998-06-30T17:00:00.000Z
moment("1998-06-30T12:00:00.000")
The only way of doing this is moment().sub(19, 'years');
What you are asking imply a Natural language processing which is whole computer science field.
There is a plugin which very recently appeared on github, which is a plugin to moment to allow this sort of parsing: https://github.com/cmaurer/relative.time.parser
I have not personally tried it, but I will shortly (found both it and this question while searching for the same thing).
What about :
moment.fn.parse = function(_relative, _format){
var _modulo = moment.normalizeUnits(_format);
return this.add(_relative, _modulo);
}
moment("30/08/2015", "DD/MM/YYYY").parse(-20, "years").format('DD/MM/YYYY'); // 30/08/1995
moment("30/08/2015", "DD/MM/YYYY").parse(-2, "week").format('DD/MM/YYYY'); // 16/08/2015
moment("30/08/2015", "DD/MM/YYYY").parse(-2, "d").format('DD/MM/YYYY'); // 28/08/2015
I wrote the plugin relative.time.parser. The original intent was to parse relative time from graphite from/until, so I was only going for the 'reverse' in time.
I will take a look at adding the 'NLP' use cases as well.
Thanks,
Chris
You can do it easily using moment plus little logic. Here it is working perfectly
function parseSincUntilDate(dateStr, now = new Date()) {
// inputs: 20 minutes ago, 7 hours from now, now, '', or UTC string
if (moment(dateStr).isValid()) return moment(dateStr).toDate();
const tokens = dateStr.split(' ');
if (dateStr.includes('ago')) {
return moment(now).subtract(tokens[0], tokens[1]).toDate();
} else if (dateStr.includes('from now')) {
return moment(now).add(tokens[0], tokens[1]).toDate();
} else if (dateStr === 'now' || dateStr === '') {
return new Date(now);
}
return moment(dateStr).toDate();
}
// to change relative date, pass it in second parameter
As of Moment.js 1.0.0 (October 2011) to current:
moment().add(7, 'days');
moment().subtract(1, 'seconds');
Works with years, quarters, months, weeks, days, hours, minutes, seconds, and milliseconds.
https://momentjs.com/docs/#/manipulating/add/
https://momentjs.com/docs/#/manipulating/subtract/

Moment.js Convert Local time to UTC time does work

I would like to use Moment.js to convert a local time to UTC equivalent. I believe that I have the correct method in place, but it does not alter the time.
I'm in Sydney Australian +11 and expect the UTC time to be 11 hours earlier.
Internally on the moment object the isUTC flag changes from false to true, but the time does NOT shift, am I meant to use a different technique for this.
How do I actually get the current UTC date out of this object
Before Conversion
var val = '18/03/2015';
var selectedDate = moment(val, 'DD/MM/YYYY');
After Conversion
var a = selectedDate.utc()
I just tried this code and it seems like I get the correct UTC time. I guess I just want to confirm that what I am doing is correct way to access the UTC time from moment.js
a.format("YYYY-MM-DD HH:mm:ssZ")
I found that my usage pattern of in my application was incorrect
selectedDate.utc().format(fullFormat)
It should have been
moment.utc(selectedDate).format(fullFormat)
This works
moment(date_to_convert).utc().format("YYYY-MM-DD HH:mm:ss");
The question is old, but I also faced it. It may be useful to someone:
Using the method of utcOffset() to calculate the UTC time:
selectedDate = (moment(selectedDate).add(-(moment().utcOffset()), 'm'));
And explicitly specify UTC:
selectedDate = moment.parseZone(selectedDate).utc().format();
This is how you do it using moment-timezone
moment.tz(localDate, localTimeZone).utc()
This worked for me !!
selectedDate = moment(selectedDate).add(moment(selectedDate).utcOffset(), 'm').utc().format()
Create a local moment object from you local time and convert it to UTC then format it, then create a new UTC moment from that formatted UTC string
var localDateString = '24/04/2019';
var localDateStringFormat = 'DD/MM/YYYY';
var utcMoment = moment.utc(moment(localDateString, localDateStringFormat ).utc().format('YYYY-MM-DD HH:mm:ssZ'))
console.log(utcMoment);
<script src="https://momentjs.com/downloads/moment.js"></script>
After few frustrating hours, I found what was the problem
Short Answer: To convert time to utc, we need to use format()
Long Answer: Take the example
moment.utc(1559586600000).format('LLL')
.utc sets the isUTC flag to true.
When logging the date, the d key always shows the time in local timezone. (Which makes us believe its not working properly - as shown in your screenshot)
But we need to use .format to get the date/time in UTC format.
The above code returns June 3, 2019 6:30 PM which is the correct UTC time.
const moment = require('moment-timezone');
const dateTime='2020-12-21'
const timezone='America/Anchorage'
const dateTimeInUtc = moment(dateTime).tz(timezone).utc().format();
console.log('dateTimeInUtc',dateTimeInUtc);
const moment = require('moment-timezone');
const dateTime='2020-12-21'
const timezone='America/Anchorage'
const dateTimeInUtc = moment(dateTime).tz(timezone).utc().format();
console.log('dateTimeInUtc',dateTimeInUtc);
After few frustrating hours, I found what was the problem
Short Answer: To convert time to utc, we need to use format()
Long Answer: Take the example
moment.utc(1559586600000).format('LLL')
.utc sets the isUTC flag to true.
When logging the date, the d key always shows the time in local timezone. (Which makes us believe its not working properly - as shown in your screenshot)
But we need to use .format to get the date/time in UTC format.
The above code returns June 3, 2019 6:30 PM which is the correct UTC time.

Javascript parsing Times without Date

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

Categories