Formatting dates with moment.js based on locale - javascript

I'm using moment-with-locales.min.js for date manipulation and I need to format as the user leaves the textboxes. Because locales are an issue, I'm trying to use moment to do the formatting. However, I'm running into a problem and I'm not sure if I'm doing it wrong or what.
If the user types in something like '2/2/12' and I try to do moment('2/2/12', 'l'), using the 'l' for short date based on locale, it formats it into '2/2/0012'. That in itself seems broken.
If I try to format with moment('2/2/12', 'M/d/yyyy'), as seen in the JSFiddle below, it changes it to '2/1/2014'. It always bumps it down to the first day of the month and makes it the current year.
Here's the JSFiddle I was using.
moment.locale('en-US');
var parsed = moment('2/2/12', 'M/d/yyyy');
if (moment(parsed).isValid()) {
var d = new moment(parsed, 'l');
alert('Pass: ' + d.format('l'));
} else {
alert('Fail: ' + parsed);
}
I'd appreciate and help.

You should use "D" ("d" is day of week).
As for the year, according to the docs, «Two digit year parser by default assumes years above 68 to be in the 1900's and below in the 2000's.» so I'm guessing (and experimentation seems to confirm it) that if you use the 4 digit format ("YYYY") it'll assume you are passing in the year 12 and not 2012. If you use "YY" it'll print 2012 correctly.
So, to summarize, the format "M/D/YY" should do what you want.

Related

Moment.js default year is 2001

Description of the Issue and Steps to Reproduce:
Receive user input as 3/3 var response
Parse into a date variable var date = moment(new Date(response))
Doing a console.log of date gives moment("2001-03-03T00:00:00.000")
The year defaults to 2001. Since the user may input the date in their own format, I didn't want to add in a format as I wouldn't know what format they might want to enter.
After looking around, I found some Moment github issues on this (#635, #912) which mentioned that the issue was resolved, but I am still getting the default year of 2001.
I also found a suggestion to set the year as this year if left unspecified:
if (date.year() === 2001) {
date.year() = moment().year();
}
This works, but feels like a dirty solution. Any ideas what I can do instead?
Thanks in advance!
Current Environment
Node.js v8.9.4
Moment.js v2.20.1
VS code v1.19.3
MS Bot SDK v3.14.0
p/s Still pretty new to the stackoverflow/ github issues, and not to sure where I should have posted instead. Please let me know if you need more information!
Use moment with a format string to ensure the format is proper. You might want to force the user to provide the year or use a date picker. The machine can only do so much
console.log(moment('3/3', 'MM/dd').toString());
// or
console.log(moment('3/3', 'dd/MM').toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.js"></script>

Parsing the hour only

I'm using d3 v3 to parse some intraday data that has the following format:
time,value
09:00,1
09:05,2
09:10,3
...
So I set up a parsing variable like so:
var parseTime = d3.time.format("%H:%M").parse;
And I map the data within the scope of the csv call:
d3.csv("my_data.csv", function(error, rawData) {
var data = rawData.map(function(d) {
return {y_value: +d.value, date: parseTime(d.time)}
});
console.log(data)
}
In the console, I get something strange. Instead of only the hour, I get the full-fledged date, day of the week, month, even time zone.
data->
array[79]
0:Object->
date: Mon Jan 01 1900 09:00:00 GMT+0000
y_value: 1
Do dates need to be this complete? I suppose that could explain why I wound up with monday Jan. 1st, seems like a default of sorts. However, according to d3 time documentation, "%H:%M" is used for hours and minutes. And I could have sworn I did that much correct.
I know something is not quite right because my line graph is throwing the error:
error: <path> attribute d: expected number "MNaN"
My best guess is that the date is over-specified and the axis() is expecting an hour format.
My Question is: Why isn't my data being parsed as hour only? Should I change this from the parsing end? If that's not an option, can I have the x domain read a portion of the date (the hour and minute portion)?
Update: Here is a minimal block for further illustration of my plight.
When you say...
why isn't my data being parsed as hour only?
... it becomes evident that there is a basic misunderstanding here. Let's clarify it.
What is a date?
Simply put, a date is a moment in time. It can be now, or two months ago, or the day my son was born, or next Christmas, or the moment Socrates drank the hemlock. It does'n matter. What is important to understand is that all those dates have a century, a decade, a year, a month, a day, an hour, a minute, a second, a millisecond etc... (of course, those names are conventions that can be changed).
Therefore, it makes little sense having a date with just the hour, or just the hour and the minute.
Parsing and formating
When you parse a string, you create a date object. As we explained above, that date object corresponds to a moment in time, and it will have year, month, hour, timezone etc... If the string itself lacks some information, as year for instance, it will default to some value.
Look at this demo, we will parse a string into a date object, using the correct specifier:
var string = "09:00";
var parser = d3.timeParse("%H:%M");
var date = parser(string);
console.log("The date object is: " + date);
<script src="https://d3js.org/d3.v4.min.js"></script>
As you can see, we have a date object now. By the way, you can see that it defaults to a given year (1900), a given month (January), and so on...
However, in your chart, you don't need to show the entire object, that is, all the information regarding that moment in time. You can show just hour and minute, for instance. We will format that date.
Have a look:
var string = "09:00";
var parser = d3.timeParse("%H:%M");
var format = d3.timeFormat("%H:%M");
var date = parser(string);
console.log("The date object is: " + date);
console.log("The formatted date is: " + format(date));
<script src="https://d3js.org/d3.v4.min.js"></script>
That formatted date is useful for creating axes, tooltips, texts etc..., that is, showing the date you have without showing all its details. You can choose what information you want to show to the user (just the year, or just the month, or maybe day-month-year, whatever).
That's the difference between parsing and formatting.
Why using a formatter?
To finalise, you may ask: why am I using a formatter, if I will end up having the same thing I had at the beginning?
The answer is: you don't have the same thing. Now you have a date, not a string. And, using a date with a time scale, you can accomodate daylight savings, leap years, February with only 28 days, that is, a bunch of things that are impossible to do with a simple string.
PS: The demos above use D3 v4.
EDIT: After your update we can easily see the problem with your code: you have to pass an array to range().
var xScale = d3.time.scale().range([0,width]);
Here is the updated bl.ocks: http://bl.ocks.org/anonymous/a05e15339f7792f175d2bcebccf6bbed/7f23db481f1308eb0d5a1834f7cbc0b17d948167

Managing multiple date formats in Javascript

Similar questions has been asked many times but I couldn't find a more concrete solution. The things I'm doing are:
I have a <input type="date"> inside my HTML which when clicked opens a calender with date in dd/mm/yyyy format.
I change the html5 date to timestamp to send to my db by Date.parse(html5Date) and in the server I modify the date and send it back to my Angular app.
I now convert the timestamp back to Date object by new Date(timestamp).To print the date in a human-friendly format inside a table I do [date.getDate(), date.getMonth() + 1, date.getFullYear()].join('/').
On edit (PUT request), I again capture the date from HTML, convert it to timestamp, send it to server and process the returning date back to html date.
Other than these, I also do a ton of functionalities like date comparison, adding hours to the dates, show time of the day etc inside the HTML:
Just these simple operations are over 120 lines of code which I think is ridiculous and error prone. I've looked into Angular Datepicker but it's a bit confusing. Also sometimes the HTML date is of type Object and sometimes it's String so Date.parse() gives error.
Are there any developer friendly methods that does : copy HTML5 date (from datepicker) --> change to timestamp (for angular&server) --> format timestamp back to string/object (for html)? Thank You :)
Note: Angular throws a lot of annoying error in console saying dateformat is wrong (being html date type) but doesn't stop code from running
Sounds like you are doing waaay to many conversions. I would argue that there should only be one way dates are represented: as Date objects in the programming language. There are only a few conversions that need to happen:
Date <=> Integer milliseconds since the epoch to pass to server
Date <=> String human-readable format to display to user
Any thing beyond this is asking for trouble. Comparisons can be made by casting to int date.getTime(), comparing, and casting back to Date. Ditto for additions. Note that Date.parse is implementation dependent in what it will accept, although all of them will accept ISO 8601 formatted date strings anything else is guesswork. Which means you will have to deal with converting strings by hand, something like the following:
var toDate = str => {
var splitter = str.indexOf("/") === -1 ? "-" : "/";
var [mon, day, year] = str.split(splitter);
return new Date(year, mon - 1, day);
};
var toDateString = date => {
return "" + date.getFullYear() + (date.getMonth() + 1) +...
};
Note that there's no validation, that's left as an exercise to the reader.
A WORD ABOUT MOMENT.JS
moment.js is awesome. Its also huge, its a kitchen-sink API with a heft to match. You're already loading angular, so think carefully before bulking the size of your payload with another huge library.
Moment.js is a powerful date formatting and manipulation library. A lot of things you can do in Moment.js are a single line of code, which makes life a lot easier. I agree, without using a library like this date formatting and handling can be a pain.
http://momentjs.com/
EDIT: fyi, I use this with my Angular app and find it extremely useful!

Having troubles with converting time in iso using java

I use the below code to format date time in iso format using java (I'm reducing 1 min from current time) and get the output as this "2016-03-17T11:38:21.xxxZ" < x represent some numbers> i want this to compare with the time which have mentioned in the DB.
Person who build that data insert query, he used javascript to get the time and format it in iso.
Date inside the DB is looks like this "2016-03-17T06:09:21.530Z" and its actual time is "11:39:21 GMT+0530 (India Standard Time)" which is similar to my current time but I'm comparing these two dates as string. and get 1min early data from DB.In that case i can't get an out put because as strings these two aren't match. can anybody recomand a solusion ?
I use OrientDB
Java Code
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Calendar date = Calendar.getInstance();
long t = date.getTimeInMillis();
date.setTimeInMillis(t);
date.set(Calendar.MINUTE, date.get(Calendar.MINUTE) - 1);
String time1minEarly = df.format(date.getTime());
Using Calendar.set() and Calendar.get() does not modify the date in a way you intend:
This will modify the minutes field in your case. So subtracting "1" will reduce the minute but not give a viable date for cases where minute initially is zero.
You may just subtract a minutes of milliseconds from your "t" variable to get a true minute offset.
And for ease of use you might also consider following advise from #Prashant and using LocalDateTime class from joda library.
Thanks Everybody for your support.
I figure out How to do this. it's pretty easy. Both #rpy and #Prashant are correct. Calendar is not suitable for solve my issue. Also LocalDateTime too. but it did help me to figure out the correct way.
#rpy and #Prashant they both did miss one thing that the javascript time represent the UTC time. that's the issue. (it's 5.5 hours behind compared to my location) so, I figure out this below code. it did what i wanted to do.
It's pretty easy. all you have to do is provide your zone id.
(You can get Zone id using this code : go to the link - http://www.javadb.com/list-possible-timezones-or-zoneids-in-java/)
Also you can choose so many formats by changing "DateTimeFormatter" value.
ZoneId UTCzoneId = ZoneId.of("UTC");
ZonedDateTime time1minEarly = ZonedDateTime.now(UTCzoneId).minusMinutes(1);
String UTCtime1minerly = time1minEarly.format(DateTimeFormatter.ISO_INSTANT);
Out put is similar to this : "2016-03-17T10:39:21.530Z"
(- UTC time at that time : 2016-03-17T10:40:21.530Z)

Regex for testing date formatting

I found a very useful regular expression for testing format and content of a date field in a regex example site
BUT I get a validation when I put in dates older than 2000 and since this is a field for inputting date of birth you can see why it would be a problem. I am sure it is an easy fix but regular expressions intimidate me.
$('#txtDOB').blur(function() {
//$('span.error-keyup-5').remove();
var inputVal = $(this).val();
var dateReg = /^[0,1]?\d{1}\/(([0-2]?\d{1})|([3][0,1]{1}))\/(([1]{1}[9]{1}[9]{1}\d{1})|([2-9]{1}\d{3}))$/;
if(!dateReg.test(inputVal)) {
alert('invalid date format: ' + inputVal);
}
I am not married to this solution so if you can suggest a better way please comment away.
Instead of testing if a string matches one or more formats that you think might be good dates, I would suggest instead asking JavaScript if it thinks it is a valid date:
function isValidDate(str){
return !isNaN(new Date(str));
}
This assumes that you're going to accept what the user gives you in any of a variety of formats (e.g. the horrid US MM/DD/YYYY or the more sane ISO8601 YYYY-MM-DD). If instead you have a specific format you will only accept, then parse your string based on that, pull out the year/month/date, and then ask JavaScript if this is a valid date:
function isValidDate(year, month, date) {
var d = new Date(year*=1, month-=1, date*=1, 12); // noon to skip DST issues
return d.getFullYear()==year && d.getMonth()==month; // wrong date->wrong month
}
You need to check that the year/month/date all match because new Date(2011,11,32) is accepted and interpreted as 2012-1-1.
See also: Javascript method to ensure that a date is valid
There's a whole lot of mess there. First, eliminate all the {1}'s. That just means one instance, which is totally redundant. Also, a character class with one value is the same as the character itself. So, [1] becomes 1.
So, that leaves us with:
/^[01]?\d\/(([0-2]?\d)|([3][01]))\/((199\d)|([2-9]\d{3}))$/
This is MM/DD/YYYY presumably. but the YYYY is just 199[0-9] and any year > 2000 and < 9999. Wow, that's a date range!
As a basic, try:
/^[01]?\d\/(([0-2]?\d)|([3][01]))\/([12]\d{3}))$/
This gives a year range of 1000 - 2999. But as Tim said above, if you want really valid dates, you should use a specific date validator.
If you need to parse date strings into dates then I would check out this library:
DateJS

Categories