14

How can I get a list of all long month names using the ECMAScript Internationalization API?

For example, if the user's locale is en-US, I'd like to get the following:

["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
mark
  • 4,678
  • 7
  • 36
  • 46

4 Answers4

9

My solution in 2021 with es6 Syntax

/**
 * Return list of months
 *  localeName   : name of local, f.e. en-GB, default es-MX
 *  ✅ monthFormat : short, numeric, long (Default)
 */
function monthsForLocale(localeName = 'es-MX', monthFormat = 'long') {
  const format = new Intl
     .DateTimeFormat(localeName, {month: monthFormat}).format;
  return [...Array(12).keys()]
    .map((m) => format(new Date(Date.UTC(2021, (m+1)%12))));
}


//  Testing:

// ['enero', ..., 'noviembre','diciembre' ]
console.log(monthsForLocale());

// ['1', '2',  '3', '4',  '5', '6',  '7', '8',  '9', '10', '11', '12']
console.log(monthsForLocale('en-GB', 'numeric'));

// ['Jan', 'Feb','Mar', 'Apr', 'May','Jun', 'Jul', 'Aug','Sep', 'Oct', 'Nov','Dec' ]    
console.log(monthsForLocale('en-GB', 'short'));

// ['1月',  '2月', '3月',  '4月',  '5月','6月',  '7月',  '8月','9月',  '10月', '11月', '12月']
console.log(monthsForLocale('ja-JP', 'short'));
fitorec
  • 4,257
  • 2
  • 24
  • 18
6

This should do it:

function getMonthsForLocale(locale) {
    var format = new Intl.DateTimeFormat(locale, { month: 'long' })
    var months = []
    for (var month = 0; month < 12; month++) {
        var testDate = new Date(Date.UTC(2000, month, 1, 0, 0, 0));
        months.push(format.format(testDate))
    }
    return months;
}
aolde
  • 2,287
  • 16
  • 19
John Ellmore
  • 2,209
  • 1
  • 10
  • 22
  • 1
    Creating a date in UTC then using it to create another date in you local timezone might shift the months order in the final array. – Hugo Leao Apr 01 '20 at 23:05
  • This does not work for Safari. The code creates the following result: (Array (12) 0 "January" 1 "February" 2 "March" 3 "March" 4 "April" 5 "May" 6 "June" 7 "July" 8 "August" 9 "September" 10 "October" 11 "December"). Note the duplicate "March" values and the absence of "November" – richsoni Oct 09 '20 at 19:48
  • follow up from the above... safari has a bug in DateTimeFormat https://stackoverflow.com/questions/56242641/dates-in-safari-appear-off-by-one-using-intl-datetimeformat-with-en-us-locale. So this answer 'should' work, but in practice it does not as of now – richsoni Oct 09 '20 at 20:03
  • The problem with this and all similar solutions is that the month format is not required to be supported and will map to an implementation-defined format (as seen on Safari, as year+month or month+day are supported formats that could be chosen instead). Probably using formatToParts and extracting the month value from the month+year format is a way around this. – Remember Monica Jan 27 '22 at 06:19
4

To make this work on Safari as well, we need to offset by an additional day (Dates in Safari appear off by one using Intl.DateTimeFormat with en-US locale). This works in our usecase because we are just getting the month names, so it does not matter if we generate the string from the 1st or the 2nd of the month.

const SAFARI_OFFSET_FIX = 1;
const getMonthsForLocale = (locale = navigator.language) => {
  const format = new Intl.DateTimeFormat(locale, { month: 'long' });
  const months = [];
  for (let month = 0; month < 12; month++) {
    const testDate = new Date(0, month, 1 + SAFARI_OFFSET_FIX, 0, 0, 0);
    months.push(format.format(testDate));
  }
  return months;
};
richsoni
  • 4,188
  • 8
  • 34
  • 47
2

Combining the best of the answers above, plus my own small improvements.

Usually people want a list of months to start with January, not December. Switching from new Date(Date.UTC(2021, m))) to simply new Date(2021, m)) resolves this, as it creates a date in the user's own locale.

/**
 * Get a list of the 12 months of the year as strings, according to specified locale and format
 * @typedef {Object} Options
 * @property {string} [locale=navigator.language] : name of locale, e.g. en-GB, defaults to 
 *   the user's own locale
 * @property {string} [monthFormat="long"] : "short", "numeric", or "long" (default)
 *
 * @param {Options} [options] : input options
 * @return {string[]} : an array of 12 strings, the months of the year in the requested format
 */
function getAllMonths({ locale = navigator.language, format = "long"} = {}) {
  const applyFormat = new Intl.DateTimeFormat(locale, { month: format }).format;
  return [...Array(12).keys()].map((m) => applyFormat(new Date(2021, m)));
}

// Testing in en-US locale
console.log(getAllMonths());
// ["January", "February", ... "December"]
console.log(getAllMonths({ format: "numeric" }));
// ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
console.log(getAllMonths({ format: "short" }));
// ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"]
console.log(getAllMonths({ locale: "es-mx" }));
// ["enero", "febrero", ... "diciembre"]
console.log(getAllMonths({ locale: "ja-JP", format: "short" }));
// ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]
Matthew Souther
  • 876
  • 8
  • 13