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

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/

Related

How can I get timezone name from date string in javascript in node environment? [duplicate]

I know how to get the timezone offset, but what I need is the ability to detect something like "America/New York." Is that even possible from JavaScript or is that something I am going to have to guestimate based on the offset?
The Internationalization API supports getting the user timezone, and is supported in all current browsers.
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)
Keep in mind that on some older browser versions that support the Internationalization API, the timeZone property is set to undefined rather than the user’s timezone string. As best as I can tell, at the time of writing (July 2017) all current browsers except for IE11 will return the user timezone as a string.
Most upvoted answer is probably the best way to get the timezone, however, Intl.DateTimeFormat().resolvedOptions().timeZone returns IANA timezone name by definition, which is in English.
If you want the timezone's name in current user's language, you can parse it from Date's string representation like so:
function getTimezoneName() {
const today = new Date();
const short = today.toLocaleDateString(undefined);
const full = today.toLocaleDateString(undefined, { timeZoneName: 'long' });
// Trying to remove date from the string in a locale-agnostic way
const shortIndex = full.indexOf(short);
if (shortIndex >= 0) {
const trimmed = full.substring(0, shortIndex) + full.substring(shortIndex + short.length);
// by this time `trimmed` should be the timezone's name with some punctuation -
// trim it from both sides
return trimmed.replace(/^[\s,.\-:;]+|[\s,.\-:;]+$/g, '');
} else {
// in some magic case when short representation of date is not present in the long one, just return the long one as a fallback, since it should contain the timezone's name
return full;
}
}
console.log(getTimezoneName());
Tested in Chrome and Firefox.
Ofcourse, this will not work as intended in some of the environments. For example, node.js returns a GMT offset (e.g. GMT+07:00) instead of a name. But I think it's still readable as a fallback.
P.S. Won't work in IE11, just as the Intl... solution.
A short possibility for a result in current user's language:
console.log(new Date().toLocaleDateString(undefined, {day:'2-digit',timeZoneName: 'long' }).substring(4));
If you're already using Moment.js you can guess the timezone name:
moment.tz.guess(); // eg. "America/New York"
You can use this script.
http://pellepim.bitbucket.org/jstz/
Fork or clone repository here.
https://bitbucket.org/pellepim/jstimezonedetect
Once you include the script, you can get the list of timezones in - jstz.olson.timezones variable.
And following code is used to determine client browser's timezone.
var tz = jstz.determine();
tz.name();
Enjoy jstz!
You can simply write your own code by using the mapping table here:
http://www.timeanddate.com/time/zones/
or, use moment-timezone library:
http://momentjs.com/timezone/docs/
See zone.name; // America/Los_Angeles
or, this library:
https://github.com/Canop/tzdetect.js
console.log(new Date().toLocaleDateString(undefined, {day:'2-digit',timeZoneName: 'long' }).substring(4).match(/\b(\w)/g).join(''))
To detect something like "America/New York.", you can use the new LocalZone() from the Luxon library.
import { LocalZone } from 'luxon';
const zoneName = new LocalZone().name;
This gets the timezone code (e.g., GMT) in older javascript (I'm using google app script with old engine):
function getTimezoneName() {
return new Date().toString().get(/\((.+)\)/);
}
I'm just putting this here in case someone needs it.
In javascript , the Date.getTimezoneOffset() method returns the time-zone offset from UTC, in minutes, for the current locale.
var x = new Date();
var currentTimeZoneOffsetInHours = x.getTimezoneOffset() / 60;
Moment'timezone will be a useful tool.
http://momentjs.com/timezone/
Convert Dates Between Timezones
var newYork = moment.tz("2014-06-01 12:00", "America/New_York");
var losAngeles = newYork.clone().tz("America/Los_Angeles");
var london = newYork.clone().tz("Europe/London");
newYork.format(); // 2014-06-01T12:00:00-04:00
losAngeles.format(); // 2014-06-01T09:00:00-07:00
london.format(); // 2014-06-01T17:00:00+01:00

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

How to format date in correct format in JavaScript

I'm working on JavaScript and stuck in a small issue.
I am receiving this date in JSON response 1322919399447-0500
and I want to format this like: 6:50 PM, Dec 3rd 2011.
I'm not sure if this is the best way (I'm sure it's not, actually), but essentially you can make that datestring into a js Date object, then pull out the pieces to manipulate as you see fit:
var dateThing = new Date(1322919399447-0500);
dateThing.getFullYear(); // 2011
dateThing.getDay(); // 6
dateThing.getDate(); // 3
dateThing.getMonth(); // 11
dateThing.getHours(); // 8 (test for anything over 12, that indicates PM)
dateThing.getMinutes(); // 36
Then you can concatenate those pieces into your own format. Like I said, there's probably a better way, but this works in a pinch.
I used this handy little date format addon and it worked very well for me. Even took care of the pesky internet explorer quirks with the month.
This is a similar date format function I created that uses the same flags that PHP's date function uses.
PHP date function in Javascript
Here is the snippet with your example input. It is using script linked by Zoidberg.
This code returns formatted UTC date. If you want your local date then remove UTC: from the return statement.
function convertTime(dateString) {
// get ms part from the string
var milis = +dateString.substring(0, 13);
// get timezone part as "# of hours from UTC", e.g. "-0500" -> -5
var offset = +dateString.substring(13, 16);
// move the time for "offset" number of hours (to UTC time)
var date = new Date(milis - offset * 3600000);
// using http://stevenlevithan.com/assets/misc/date.format.js
return date.format("UTC:h:MM TT, mmm dS yyyy");
}
EDIT: Changed + offset * to - offset * as we want to normalize to UTC.

Is there a natural language parser for date/times in javascript?

Is there a natural language parser for date/times in javascript?
I made Chrono a small library for parsing dates in JavaScript. I added a date range parsing feature (such as '12 Nov - 13 Dec 2012') .
SugarJS supports some natural language parsing of dates and times.
You can jump to the live example here: http://sugarjs.com/dates
For example, it supports the following inputs:
the day after tomorrow
2 weeks from monday
May 25th of next year
You can then covert the result into different date formats or use the API to further manipulate the date.
Does Date.js satisfy your needs? Or are you looking for something else?
Chrono v2 is the only library I've found that also parses timezones.
Unfortunately, the only documented way of using it is via NPM (npm i chrono-node) or as ES6 Module (import * as chrono from 'chrono-node'), but I found a way to use the library with the traditional script tag approach for those interested.
Non-NPM / non-module usage:
Include this script: https://www.unpkg.com/chrono-node/dist/bundle.js
Use the global variable chrono in your script (available methods here)
E.g. chrono.parseDate('Tomorrow at 4 PM PST')
⚠ Note: I have not tested this extensively, so don't expect it to work flawlessly
For node, I've found chrono to work well
Chrono supports most date and time formats, such as :
Today, Tomorrow, Yesterday, Last Friday, etc
17 August 2013 - 19 August 2013
This Friday from 13:00 - 16.00
5 days ago
2 weeks from now
Sat Aug 17 2013 18:40:39 GMT+0900 (JST)
2014-11-30T08:15:30-05:30
Sherlock is a great one.
var Sherlock = require('sherlockjs');
var sherlocked = Sherlock.parse('Homework 5 due next monday at 3pm');
// Basic properties
var title = sherlocked.eventTitle; // 'Homework 5 due'
var startDate = sherlocked.startDate; // Date object pointing to next monday at 3pm
var endDate = sherlocked.endDate; // null in this case, since no duration was given
var isAllDay = sherlocked.isAllDay; // false, since a time is included with the event
// Example of an additional custom property added by Watson
var validated = sherlocked.validated; // true
You can use the jQuery datepicker translation, get the day and month number and select the day from datepicker days.
You can add values to this object, and you can download up to 60 languages I think. (The object below is not complete, I removed some code to simplify it).
$.datepicker.regional['sv'] = {
monthNames:['Januari','Februari','Mars','April','Maj','Juni','Juli','Augusti','September','Oktober','November','December'],
monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun','Jul','Aug','Sep','Okt','Nov','Dec'],
dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'],
dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'],
dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö']
};
Now get the day and month number
var dateObject = new Date();
var day = dateObject.getDay();
var month = dateObject.getMonth();
var monthText = $.datepicker.regional['sv']['monthNames'][month];
var dayText = $.datepicker.regional['sv']['dayNames'][day];

Categories