【问题标题】:Locale and specific date format with Moment.jsMoment.js 的语言环境和特定日期格式
【发布时间】:2015-02-06 05:35:28
【问题描述】:

我在我的项目中使用 Moment.js 并将日期格式化如下:

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

效果很好,但有时我需要显示一个没有年份的日期。我不能使用像someDate.format("MM/DD") 这样的东西,因为在某些语言中它应该是someDate.format("DD/MM")。我需要类似L,LL,LLL 但没有年份的东西。

我能做什么?

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'

【问题讨论】:

    标签: javascript localization locale momentjs


    【解决方案1】:

    好的。这有点可怕,但你知道它会是这样。

    首先,您可以访问(例如)'L' 的实际格式字符串:

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

    接下来,您可以通过明智的正则表达式替换对其进行一些手术:

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

    (也就是说:删除YYYY,加上删除后留下的孤立分隔符)

    然后您可以在瞬间格式调用中使用您的新格式字符串:

    someDate.format(formatYearlessL);
    

    这必然做出一些假设:

    • 区域设置的月 + 日数字格式的顺序与该区域设置的年 + 月 + 日格式的顺序匹配,但删除了年份。
    • 短格式仅在月和日之间使用分隔符(无前导/尾随分隔符)。
    • 短数字日期格式的分隔符始终为非字母数字。
    • 格式由数字元素和分隔符组成,而不是带有冠词的句子格式(请参阅下面 RGPT 关于西班牙语和葡萄牙语的评论,这也适用于其他一些语言的长格式)。

    快速查看locale/*.js,这些假设适用于我检查的每个语言环境文件,但可能有一些语言环境违反了它们。 (ETA:下面的评论指出德国短日期格式违反了第二个假设)

    另外一个重要的警告是,这很可能是脆弱的。完全有可能moment.js的未来版本会改变longDateFormat中当前数据的位置...

    【讨论】:

    • 这在多种文化中都行不通。让我们以葡萄牙语为例:完整日期将是:“14 de Fevereiro de 2016”。如果您只删除年份,在本例中为“2016”,您将得到:“14 de Fevereiro de”,这是错误的。正确的结果应该是“14 de Fevereiro”。至少西班牙语也有同样的问题(所以对于这两个,我们已经在谈论超过 6.5 亿可能受此错误影响的用户)。我看到其他语言也会有同样的问题。
    • RGPT - 好点,编辑了帖子以将其添加到警告中。一般来说,这种方法只适用于使用可预测的分隔符更改简短的数字日期格式。
    • 此过程不适用于德国日期。长格式是 DD.MM.YYYY,但短格式仍然需要尾随点 (DD.MM.) — 它被第二个 replace(…) 剥离。
    • 已编辑以明确假设短格式没有前导/尾随分隔符,并指出了这种失败的情况。谢谢!
    • 考虑到世界各地分隔符的超不规则use,这个答案还远远不够。我很惊讶 MomentJs 没有涵盖这一点。
    【解决方案2】:

    据我了解,您可以使用 MomentJS 属性 https://momentjs.com/docs/#/customization/long-date-formats/ 更改特定语言的日期格式(不含年份)

    例子:

    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】:

      该库无法轻松添加新格式,因为它们是针对我们无法覆盖 (var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;) 的正则表达式进行验证的。

      但是,我们可以重写 format 函数,以便将我们的新格式转换为 Moment 可识别的标记。

      例如,让我们添加一个名为“LMD”的新自定义格式。 首先,我们需要为我们想要使用的每个语言环境定义它:

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

      然后我们重写原始格式函数并将inputString(“LMD”)转换为我们之前定义的真实标记。 之后,我们只需调用原始函数并让 Moment 照常工作:

      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]);
      };
      

      示例用法:

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

      【讨论】:

        【解决方案4】:

        一种选择可能是使用CLDR data 并获取公历数据并查找main.{locale}.dates.calendars.gregorian.dateTimeFormats.availableFormats。你可能想要的是Md

        我可能会建议您使用Globalize 库来简化这一切。您会注意到,如果您将所需的日期格式设置为 skeleton,则该库可以为您完成所有本地化。

        例如:

        .dateFormatter({ skeleton: "GyMMMd" })( new Date() )
        // > "Nov 30, 2010 AD"
        

        【讨论】:

          猜你喜欢
          • 2020-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-27
          • 1970-01-01
          • 2010-11-23
          • 1970-01-01
          相关资源
          最近更新 更多