JavaScript新日期序数(st,nd,rd,th)

94

如果可能的话,不使用JavaScript库或大量笨重的代码,我正在寻找格式化距今两周的日期的最简单方法,格式如下:

2013年3月13日

我正在使用以下代码:

var newdate = new Date(+new Date + 12096e5);
document.body.innerHTML = newdate;

该函数返回两周后的日期和时间,格式如下:

Wed Mar 27 2013 21:50:29 GMT+0000 (GMT Standard Time)

这是在jsFiddle上的代码。

希望能得到任何帮助!


除了缺少一个“of”之外,我对那个日期没有任何问题。 - mplungjan
试一下这个:https://dev59.com/z3NA5IYBdhLWcg3wL6yx - ebram khalil
我在想如何做完全相反的事情?我不想开启新线程,所以如果有人有链接,我会很感激。 - v0d1ch
1
这超出了原问题的范围,但我不确定是否有人处理过其他语言中的序数词?例如,我知道法语的序数词有些不同。 - MrBoJangles
23个回答

153
请注意,这适用于从1到31的日期数字。

const nth = (d) => {
  if (d > 3 && d < 21) return 'th';
  switch (d % 10) {
    case 1:  return "st";
    case 2:  return "nd";
    case 3:  return "rd";
    default: return "th";
  }
};

// test code

const fortnightAway = new Date(+new Date + 12096e5);
const date = fortnightAway.getDate();
const month = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][fortnightAway.getMonth()];

document.getElementById("date").innerHTML = `In two weeks it will be the ${date}<sup>${nth(date)}</sup> of ${month} ${fortnightAway.getFullYear()}`;

// test
const dates = [...Array(32).keys()].slice(1).map(i => `${i}${nth(i)}`)
console.log(dates.join(", "))
sup {
  font-size: x-small
}
<span id="date"></span>

这是一个适用于任何数字的版本。

const nth = (d) => {
  const dString = String(d);
  const last = +dString.slice(-2);
  if (last > 3 && last < 21) return 'th';
  switch (last % 10) {
    case 1:  return "st";
    case 2:  return "nd";
    case 3:  return "rd";
    default: return "th";
  }
};

// test
const numbers = [...Array(1225).keys()].map(i => `${i}${nth(i)}`)
console.log(numbers.join(", "))

在评论中提到的一句话建议

const nth = n => n>3&&n<21?"th":n%10==1?"st":n%10==2?"nd":n%10==3?"rd":"th";

// to call: nth(i)

// test
document.getElementById("nums").innerHTML =  [...Array(1225).keys()].map(i => `<pre>${String(i).padStart(3," ")}<sup>${nth(i)}</sup></pre>`).join(" ");
pre { display:inline-block; margin:2px; }
<div id="nums"></div>

如果你不喜欢开关,这个同样有效

const nth = (d) => {
  const last = +String(d).slice(-2);
  if (last > 3 && last < 21) return 'th';
  const remainder = last % 10;
  if (remainder === 1) return "st";
  if (remainder === 2) return "nd";
  if (remainder === 3) return "rd";
  return "th";
};

// test
const numbers = [...Array(1225).keys()].map(i => `${i}${nth(i)}`)
console.log(numbers.join(", "))


完美运作... +1 对于 d>3 && d<21 - Temüjin
为了清晰起见,我可能会将异常编码为以下之一:如果(n == 11 || n == 12 || n == 13)返回“th”; 或者:如果(n >= 11 && n <= 13)返回“th”。 - krick
缺少21、22、23。 - mplungjan
1
序数函数(压缩版):function nth(n){return n>3&&n<21?"th":n%10==2?"nd":n%10==2?"nd":n%10==3?"rd":"th"} - ashleedawg
1
在上面的函数中有一个小错误,这样应该可以解决:function nth(n){return n>3&&n<21?"th":n%10==1?"st":n%10==2?"nd":n%10==3?"rd":"th"} - Sam Tolton

37

以下是受其他答案启发的一行代码。经过测试,它可以接受0和负数。

function getOrdinalNum(n) {
  return n + (n > 0 ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] : '');
}

2020年6月23日更新。以下是上述函数更易读的答案:

const getOrdinalNum = (number) => {
  let selector;

  if (number <= 0) {
    selector = 4;
  } else if ((number > 3 && number < 21) || number % 10 > 3) {
    selector = 0;
  } else {
    selector = number % 10;
  }

  return number + ['th', 'st', 'nd', 'rd', ''][selector];
};



1
这段代码对于111、112、113、211等不起作用。但它对于所有情况可能有效。["th", "st", "nd", "rd"][n % 100 > 10 && n % 100 < 14) || n % 10 > 3 ? 0 : n % 10]但是,这段代码并不适用于日期的情况。如果有人需要将其用于任何正整数,则可以使用该代码。 - Oğuz K

10

我也用这种方法来处理日期,但因为每月的日期只能在1到31之间,所以最终采用了一种简化的解决方案。

function dateOrdinal(dom) {
    if (dom == 31 || dom == 21 || dom == 1) return dom + "st";
    else if (dom == 22 || dom == 2) return dom + "nd";
    else if (dom == 23 || dom == 3) return dom + "rd";
    else return dom + "th";
};

或使用条件运算符的简洁版本

function dateOrdinal(d) {
    return d+(31==d||21==d||1==d?"st":22==d||2==d?"nd":23==d||3==d?"rd":"th")
};

http://jsben.ch/#/DrBpl


10
如果您是moment.js的粉丝,那么您可以使用format("Do")进行格式化。
示例:
var newdate = new Date();
moment(newdate).format("Do MMMM YYYY")
//Returns 1st January 2020

moment("01/01/2020", "MM/DD/YYYY").format("Do")
//Returns 1st

moment("01/01/2020", "MM/DD/YYYY").format("Do MMM YYYY")
//Returns 1st Jan 2020

6

这是一个适用于任何数字的简单函数:

function getOrdinal(n) {
    let ord = ["st", "nd", "rd"]
    let exceptions = [11, 12, 13]
    let nth = 
    ord[(n % 10) - 1] == undefined || exceptions.includes(n % 100) ? "th" : ord[(n % 10) - 1]
    return n + nth
}

可以接受数字或字符串形式的数字。例如:
getOrdinal(28)        //Outputs: 28th
getOrdinal('108')     //Outputs: 108th

5

这里已经有很多好的答案了,不过有一个使用Intl.PluralRules的答案可以标准化各种语言环境下序数词的分类,可能仍然有用。

以下是一些适用于en-GB的实现。

jsfiddle

  • a one liner:

    console.log({one:'st',two:'nd',few:'rd',other:'th'}[new Intl.PluralRules('en-GB', { type: 'ordinal' }).select(new Date().getDate())])
    
  • a verbose example:

    const suffixMap = {
      one: 'st',
      two: 'nd',
      few: 'rd',
      other: 'th',
    };
    const locale = 'en-GB';
    const moment = new Date();
    const dayOfMonth = moment.getDate();
    const pluralRuleOptions = {
      type: 'ordinal',
    };
    const pluralRule = new Intl.PluralRules(locale, pluralRuleOptions);
    const ordinal = pluralRule.select(dayOfMonth);
    console.log(suffixMap[ordinal])
    

const suffix = {
  one: 'st',
  two: 'nd',
  few: 'rd',
  other: 'th',
};

document.getElementById("tomorrow-month").innerHTML = new Intl.DateTimeFormat('en-GB', { month: 'long' }).format(new Date(Date.now() + 86400000));
document.getElementById("tomorrow-day").innerHTML = new Intl.DateTimeFormat('en-GB', { day: 'numeric' }).format(new Date(Date.now() + 86400000));
document.getElementById("tomorrow-ordinal").innerHTML = suffix[new Intl.PluralRules('en-GB', { type: 'ordinal' }).select(new Date(Date.now() + 86400000).getDate())];

document.getElementById("yesterday-month").innerHTML = new Intl.DateTimeFormat('en-GB', { month: 'long' }).format(new Date(Date.now() - 86400000));
document.getElementById("yesterday-day").innerHTML = new Intl.DateTimeFormat('en-GB', { day: 'numeric' }).format(new Date(Date.now() - 86400000));
document.getElementById("yesterday-ordinal").innerHTML = suffix[new Intl.PluralRules('en-GB', { type: 'ordinal' }).select(new Date(Date.now() - 86400000).getDate())];
Tomorrow, on <span id="tomorrow-month"></span> <span id="tomorrow-day"></span><sup id="tomorrow-ordinal"></sup>, I ordered a time machine.
It arrived yesterday on <span id="yesterday-month"></span> <span id="yesterday-day"></span><sup id="yesterday-ordinal"></sup>.


有没有关于支持多种语言的后缀映射的最佳实践? - Greg
我发现了这个 https://dev59.com/Qajja4cB1Zd3GeqP8Ur7,它建议为所有日期构建一个表格,而不是尝试计算序数。 - Greg

5

在众多解决方案中又多了一个选择。

let suffix = (day >= 4 &&  day <= 20) || (day >= 24 && day <= 30)
    ? "th"
    : ["st", "nd", "rd"][day % 10 - 1];

1
我阅读了所有相对简短的内容,这篇在简洁和清晰方面都给我留下了深刻印象。 - David Carboni

4
如果你是 dayjs 的粉丝,现在它已经比 moment 更受欢迎了,这里有一个例子: 你只需要使用 dayjs(date).format('Do') 就可以了,但我会提供一个示例来展示如何使用任何你想要的格式。 请注意,Dayjs 高级格式提供了日期序数。
var advancedFormat = require('dayjs/plugin/advancedFormat')
dayjs.extend(advancedFormat)

// date variable - your date to format eg:- 2022-04-01T21:27:00
dayjs(date).format('dddd, MMMM Do [at] h:mma')

上述示例的输出(2022-04-01T21:27:00)如下所示:

输入图像描述


4

这里有很多格式化的答案,我只关注于任意整数的第n个-

Number.prototype.nth= function(){
    if(this%1) return this;
    var s= this%100;
    if(s>3 && s<21) return this+'th';
    switch(s%10){
        case 1: return this+'st';
        case 2: return this+'nd';
        case 3: return this+'rd';
        default: return this+'th';
    }
}

1
if语句是用于teenager的,因此13是“13th”,而不是“13rd”。 - kennebec
为什么要使用this%1?因为模1的结果总是0,所以该语句将始终失败,不是吗? - Forage

2
许多答案,这里有另一个:

function addOrd(n) {
  var ords = [, 'st', 'nd', 'rd'];
  var ord, m = n % 100;
  return n + ((m > 10 && m < 14) ? 'th' : ords[m % 10] || 'th');
}

// Return date string two weeks from now (14 days) in 
// format 13th March 2013
function formatDatePlusTwoWeeks(d) {
  var months = ['January', 'February', 'March', 'April', 'May', 'June',
    'July', 'August', 'September', 'October', 'November', 'December'
  ];

  // Copy date object so don't modify original
  var e = new Date(d);

  // Add two weeks (14 days)
  e.setDate(e.getDate() + 14);
  return addOrd(e.getDate()) + ' ' + months[e.getMonth()] + ' ' + e.getFullYear();
}

console.log(formatDatePlusTwoWeeks(new Date()));

// Alternative using Intl.DateTimeFormat
function datePlusTwoWeeks(date = new Date()) {
  let d = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 14);
  let parts = new Intl.DateTimeFormat('en',{
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }).formatToParts(d).reduce((acc, part) => {
    acc[part.type] = part.value;
    return acc;
  }, Object.create(null));
  return `${addOrd(parts.day)} ${parts.month} ${parts.year}`;
}

console.log(datePlusTwoWeeks())


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接