0
votes

I have an ISO date string in a javascript variable, and I want to format it for display. Simply enough, you might think. For instance:

new Date(iso).toDateString()

However, ISO dates might only represent a year ("yyyy"), or a year and month ("yyyy-mm"); they're not always "yyyy-mm-dd". Under these circumstances, the parse method fills in defaults for the missing fields, which I do not want to see.

In other words, I want to only format the date fields defined in the ISO string, but no others. If the ISO string was "2017-12" then I may want it formatted as one of 12/2012, Dec 2017, December 2017, décembre 2017, depending on my locale and level of detail; I would not want a day number. Similarly, if the ISO string was only "2017" then I would not want a day or month indication.

This question is primarily related to the elided ISO forms, and is therefore not a duplicate.

Is there a simple method of formatting such ISO dates properly -- preferably in a locale-aware fashion -- or do I have to do it all long-hand?

2
You have two options: use moment or roll your own.Jared Smith
I don't think moment.js does this. Yes, it can load a year, or year+month, into a date, but it will still fill in defaults. It's possible I've missed something but that's my reading.ACProctor
You need to specify what you're trying to do. If you want to preserve the original timestamp, then do that. There is no provision for the built–in Date object to store the value originally provided to the constructor.RobG
I've improved the question to indicate that this is not a duplicate. The Date object adds information that wasn't provided to the constructor, but that could be eliminated at the formatting stage. I cannot post my solution until the duplicate flags are removed.ACProctor

2 Answers

3
votes

If you are using JavaScript's native Date type at any point of the processing, then you're stuck; that object type can only store an instant in time, represented internally as a timestamp (absolute count of milliseconds since the UNIX epoch, not counting leap seconds). The various get* methods just calculate values based on the stored timestamp, and the set* methods calculate a new timestamp based on the requested adjustment. If you set anything to NaN or undefined, then the timestamp itself becomes NaN and all the get* methods will likewise return NaN.

If you're dealing with dates and times with uncertain or un(der)specified components you might be best off steering clear of Date entirely; just use a generic Object with only the fields that have defined values, and write your own parser and formatter to match. If you can extract the relevant part of the string, you might still be able to use the native Date methods and objects in passing to handle the tricky bits like translating possibly-abbreviated month names to numbers in a locale-sensitive fashion.

0
votes

This solution, which builds on some comments by Mark Reed, is the one I eventually adopted.

There is no default support for the elided ISO forms (yyyy-mm or yyyy). The requirement has to use a Date object in order to determine other output fields, e.g. a day of the week (if a day is specified in the ISO string) such as "Sunday". However, the Date object stores a timestamp, and so missing fields must be defaulted when the elided ISO string is parsed. Also, it also needs to use a locale-aware library, such as moment.js.

Although missing fields, such as day or month, would have been defaulted during the parsing, they can be eliminated again at the formatting stage, and a relevant formatting string can be selected based upon the length of the original elided ISO string.

The solution should build upon moment.js by defining new localised formatting strings (similar to L, LL, LLL, etc.) for the elided forms, e.g. LYM/lym to handle the YYYY-MM ISO case. For instance:

var LY = "YYYY";        // e.g. 2017
var ly = "YY";
var LYM = "MMMM YYYY";      // e.g. December 2017
var lym = "MMM YYYY";
var LYMD = "dddd MMMM D, YYYY";
var lymd = "ddd MMM D, YYYY";   // e.g. Tuesday December 19, 2017

These formatting strings would effectively ignore any defaulted fields that were added when the ISO string was parsed.