Locale and specific date format with Moment.js

2019-01-14 15:47发布

问题:

I am using Moment.js in my project and formatting dates as follows:

var locale = window.navigator.userLanguage || window.navigator.language;
moment.locale(locale);
someDate.format("L");

It works good but sometimes I need show a date without year. I can't use something like someDate.format("MM/DD") because in some languages it should be someDate.format("DD/MM"). I need something think like L,LL,LLL but without year.

What can I do?

LTS : 'h:mm:ss A',
LT : 'h:mm A',
L : 'MM/DD/YYYY',
LL : 'MMMM D, YYYY',
LLL : 'MMMM D, YYYY LT',
LLLL : 'dddd, MMMM D, YYYY LT'

回答1:

Okay. This is a little awful, but you knew it was going to be.

First, you can access the actual format string for (for instance) 'L':

var formatL = moment.localeData().longDateFormat('L');

Next, you can perform some surgery on it with judicious regex replacement:

var formatYearlessL = formatL.replace(/Y/g,'').replace(/^\W|\W$|\W\W/,'');

(Which is to say: Remove YYYY, plus the orphaned separator left by its removal)

Then you can use your new format string in a moment format call:

someDate.format(formatYearlessL);

This necessarily makes some assumptions:

  • The order of the month + day numeric format for a locale matches the order for the year + month + day format for that locale, with the year removed.
  • The short form uses separators only between month and day (no leading / trailing separators).
  • The separator for a short numeric date format is always non-alphanumeric.
  • The format consists of numeric elements and separators, rather than a sentence-form format with articles (see RGPT's comment below about Spanish and Portugese, which will also apply to long formats in some other languages).

On a quick review of locale/*.js, these assumptions hold true for every locale file I examined, but there may be some locales that violate them. (ETA: a comment below points out that a German short date format violates the second assumption)

As an additional important caveat, this is likely to be fragile. It is entirely possible that a future version of moment.js will change the location of the data currently in longDateFormat...



回答2:

As far as I understand, you can change the date format(without year) for specific languages using MomentJS properties https://momentjs.com/docs/#/customization/long-date-formats/

Example:

moment.updateLocale('en', {
  longDateFormat: {
    LLL: "MMMM Do, LT", // Oct 6th, 4:27 PM
  }
});

moment.updateLocale('ru', {
  longDateFormat: {
    LLL : 'D MMMM, HH:mm', // 6 окт., 16:27
  }
});


回答3:

The library doesn't make it easy to add new formats because they are validated against a regex that we cannot override (var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;).

However, we can override the format function in order to transform our new format into tokens that Moment recognizes.

For example, let's add a new custom format called "LMD". First we need to define it for every locale we want to use:

moment.updateLocale('en', {
   longDateFormat: {
       LMD: 'MMMM D'
   }
});

moment.updateLocale('fr', {
    longDateFormat: {
        LMD: 'D MMMM'
    }
});

Then we override the original format function and transform the inputString ("LMD") into the real tokens we previously defined. After that we just call the original function and let Moment do its job as usual:

var originalMomentFormat = moment.prototype.format;
moment.prototype.format = function (inputString) {
    if (inputString === 'LMD') { // check for your custom types here. maybe use constants or whatever
        inputString = moment.localeData().longDateFormat(inputString);
    }
    return originalMomentFormat.apply(this, [inputString]);
};

Example usage:

moment(someDate).format('LMD');