在 javascript 中以自然语言输出日期
Outputting dates in natural language in javascript
我的朋友让我做一个显然很痛苦的事情,即将日期从日期选择器转换为自然语言,首先是英语,然后是法语,因为他是一名公证人,他想要一个工具 copy/paste 将自然日期写入他的文档中,这样他就不会出错。
所需的输出格式为:twenty-fourth day of January two thousand and twenty-two
我已经浏览了大约 8 个现有的库,但 none 似乎用自然语言来计算日历日或年。
这样做的方法是分别转换日期的每个实体。 (答案使用对 Transform numbers to words in lakh / crore system 的引用将年份转换为根据您的用例修改的单词。)
var a = ['','one ','two ','three ','four ', 'five ','six ','seven ','eight ','nine ','ten ','eleven ','twelve ','thirteen ','fourteen ','fifteen ','sixteen ','seventeen ','eighteen ','nineteen '];
var b = ['', '', 'twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];
function yearInWords (num) {
if ((num = num.toString()).length > 9) return 'overflow';
n = ('000000000' + num).substr(-9).match(/^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/);
if (!n) return; var str = '';
str += (n[1] != 0) ? (a[Number(n[1])] || b[n[1][0]] + ' ' + a[n[1][1]]) + 'crore ' : '';
str += (n[2] != 0) ? (a[Number(n[2])] || b[n[2][0]] + ' ' + a[n[2][1]]) + 'lakh ' : '';
str += (n[3] != 0) ? (a[Number(n[3])] || b[n[3][0]] + ' ' + a[n[3][1]]) + 'thousand ' : '';
str += (n[4] != 0) ? (a[Number(n[4])] || b[n[4][0]] + ' ' + a[n[4][1]]) + 'hundred ' : '';
str += (n[5] != 0) ? ((str != '') ? 'and ' : '') + (a[Number(n[5])] || b[n[5][0]] + (a[n[5][1]] ? '-' : '') + a[n[5][1]]) : '';
return str;
}
var days = ['first','second','third','fourth','fifth', 'sixth','seventh','eigth','ninth','tenth','eleventh','twelth','thirteenth','fouteenth','fifteenth','sixteenth','seventeen',
'eighteenth','nineteenth', 'twentieth', 'twenty', 'thirtieth', 'thirty'];
function dayInWords (num) {
if(num > 31) return 'invalid day';
if(num < 21) return days[num-1];
if(num < 30) return days[20] + '-' + days[(num % 10)-1];
if(num == 30) return days[21];
return days[22] + '-' + days[(num % 10)-1];
return str;
}
let date = new Date("01/31/2022");
let day = dayInWords(date.getDate());
let month = date.toLocaleString('default', { month: 'long' });
let year = yearInWords(date.getFullYear());
finalDateInWords = day + ' day of ' + month + ' ' + year;
console.log(finalDateInWords);
是的,做到了,谢谢!。快速 mod 到最后一点,以便我可以从我的主脚本中调用它:
function englisDate(_date){
let date = new Date(_date);
let day = dayInWords(date.getDate());
let month = date.toLocaleString('default', { month: 'long' });
let year = yearInWords(date.getFullYear());
finalDateInWords = day + ' day of ' + month + ' ' + year;
console.log(finalDateInWords);
return(finalDateInWords);
}
如果您只对数字小于 10,000 的日期感兴趣,以下可能适合。
可以压缩数字到名称的映射,但使映射更简单会使逻辑更复杂,对于日期,我看不到增加复杂性的意义。但它可以被清理并变得更简洁。
部分复杂性在于确定是写数字名称还是序数(例如“一”或“第一”),以及是否以及在何处添加“和”(例如“一百零六”或“一千 twenty-six").
function toSpeakableDate(date = new Date()) {
let toWord = (num, ord) => {
let numberMap = {
0: {name: 'zero', ordinal: 'zeroth'},
1: {name: 'one', ordinal: 'first'},
2: {name: 'two', ordinal: 'second'},
3: {name: 'three', ordinal: 'third'},
4: {name: 'four', ordinal: 'fourth'},
5: {name: 'five', ordinal: 'fifth'},
6: {name: 'six', ordinal: 'sixth'},
7: {name: 'seven', ordinal: 'seventh'},
8: {name: 'eight', ordinal: 'eighth'},
9: {name: 'nine', ordinal: 'ninth'},
10: {name: 'ten', ordinal: 'tenth'},
11: {name: 'eleven', ordinal: 'eleventh'},
12: {name: 'twelve', ordinal: 'twelfth'},
13: {name: 'thirteen', ordinal: 'thirteenth'},
14: {name: 'fourteen', ordinal: 'fourteenth'},
15: {name: 'fifteen', ordinal: 'fifteenth'},
16: {name: 'sixteen', ordinal: 'sixteenth'},
17: {name: 'seventeen', ordinal: 'seventeenth'},
18: {name: 'eighteen', ordinal: 'eighteenth'},
19: {name: 'nineteen', ordinal: 'nineteenth'},
20: {name: 'twenty', ordinal: 'twentyth'},
30: {name: 'thirty', ordinal: 'thirtyth'},
40: {name: 'fourty', ordinal: 'fourtyth'},
50: {name: 'fifty', ordinal: 'fiftyth'},
60: {name: 'sixty', ordinal: 'sixtyth'},
70: {name: 'seventy', ordinal: 'sventyth'},
80: {name: 'eighty', ordinal: 'eightyth'},
90: {name: 'ninety', ordinal: 'ninetieth'}
};
let n = String(num);
let text;
if (n < 21) {
text = numberMap[n][ord? 'ordinal' : 'name'];
} else if (n < 1e2) {
let units = n % 10;
let tens = Math.floor(n / 10) * 10;
text = units? `${numberMap[tens].name}-${toWord(units, ord)}` : `${numberMap[tens].ordinal}`;
} else if (n < 1e3) {
let hundreds = Math.floor(n / 1e2);
let remainder = n % 1e2;
text = `${toWord(hundreds)} hundred` +
(remainder? ` and ${toWord(remainder)}` : '');
} else if (n < 1e4) {
let thousands = Math.floor(n / 1e3);
let noHundreds = String(n).slice(-3,-2) == '0';
let remainder = n % 1e3;
text = `${toWord(thousands)} thousand` +
`${noHundreds? ' and' : ''}` +
(remainder? ` ${toWord(remainder)}` : '');
}
return text;
}
let fullDate = '';
let day = toWord(date.getDate(), true);
fullDate += day + ' day of ';
let month = date.toLocaleString('en',{month:'long'});
fullDate += month + ' ';
let year = toWord(date.getFullYear());
fullDate += year;
return fullDate;
}
// Examples
// Simple date formatter
let f = date => date.toLocaleString('en-GB', {
year:'numeric',month:'short',day:'2-digit'});
[new Date(666,0,1),
new Date(1215,4,31),
new Date(),
new Date(2222,5,13)
].forEach(d => console.log(f(d) + '\n' + toSpeakableDate(d)));
我的朋友让我做一个显然很痛苦的事情,即将日期从日期选择器转换为自然语言,首先是英语,然后是法语,因为他是一名公证人,他想要一个工具 copy/paste 将自然日期写入他的文档中,这样他就不会出错。
所需的输出格式为:twenty-fourth day of January two thousand and twenty-two
我已经浏览了大约 8 个现有的库,但 none 似乎用自然语言来计算日历日或年。
这样做的方法是分别转换日期的每个实体。 (答案使用对 Transform numbers to words in lakh / crore system 的引用将年份转换为根据您的用例修改的单词。)
var a = ['','one ','two ','three ','four ', 'five ','six ','seven ','eight ','nine ','ten ','eleven ','twelve ','thirteen ','fourteen ','fifteen ','sixteen ','seventeen ','eighteen ','nineteen '];
var b = ['', '', 'twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];
function yearInWords (num) {
if ((num = num.toString()).length > 9) return 'overflow';
n = ('000000000' + num).substr(-9).match(/^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/);
if (!n) return; var str = '';
str += (n[1] != 0) ? (a[Number(n[1])] || b[n[1][0]] + ' ' + a[n[1][1]]) + 'crore ' : '';
str += (n[2] != 0) ? (a[Number(n[2])] || b[n[2][0]] + ' ' + a[n[2][1]]) + 'lakh ' : '';
str += (n[3] != 0) ? (a[Number(n[3])] || b[n[3][0]] + ' ' + a[n[3][1]]) + 'thousand ' : '';
str += (n[4] != 0) ? (a[Number(n[4])] || b[n[4][0]] + ' ' + a[n[4][1]]) + 'hundred ' : '';
str += (n[5] != 0) ? ((str != '') ? 'and ' : '') + (a[Number(n[5])] || b[n[5][0]] + (a[n[5][1]] ? '-' : '') + a[n[5][1]]) : '';
return str;
}
var days = ['first','second','third','fourth','fifth', 'sixth','seventh','eigth','ninth','tenth','eleventh','twelth','thirteenth','fouteenth','fifteenth','sixteenth','seventeen',
'eighteenth','nineteenth', 'twentieth', 'twenty', 'thirtieth', 'thirty'];
function dayInWords (num) {
if(num > 31) return 'invalid day';
if(num < 21) return days[num-1];
if(num < 30) return days[20] + '-' + days[(num % 10)-1];
if(num == 30) return days[21];
return days[22] + '-' + days[(num % 10)-1];
return str;
}
let date = new Date("01/31/2022");
let day = dayInWords(date.getDate());
let month = date.toLocaleString('default', { month: 'long' });
let year = yearInWords(date.getFullYear());
finalDateInWords = day + ' day of ' + month + ' ' + year;
console.log(finalDateInWords);
是的,做到了,谢谢!。快速 mod 到最后一点,以便我可以从我的主脚本中调用它:
function englisDate(_date){
let date = new Date(_date);
let day = dayInWords(date.getDate());
let month = date.toLocaleString('default', { month: 'long' });
let year = yearInWords(date.getFullYear());
finalDateInWords = day + ' day of ' + month + ' ' + year;
console.log(finalDateInWords);
return(finalDateInWords);
}
如果您只对数字小于 10,000 的日期感兴趣,以下可能适合。
可以压缩数字到名称的映射,但使映射更简单会使逻辑更复杂,对于日期,我看不到增加复杂性的意义。但它可以被清理并变得更简洁。
部分复杂性在于确定是写数字名称还是序数(例如“一”或“第一”),以及是否以及在何处添加“和”(例如“一百零六”或“一千 twenty-six").
function toSpeakableDate(date = new Date()) {
let toWord = (num, ord) => {
let numberMap = {
0: {name: 'zero', ordinal: 'zeroth'},
1: {name: 'one', ordinal: 'first'},
2: {name: 'two', ordinal: 'second'},
3: {name: 'three', ordinal: 'third'},
4: {name: 'four', ordinal: 'fourth'},
5: {name: 'five', ordinal: 'fifth'},
6: {name: 'six', ordinal: 'sixth'},
7: {name: 'seven', ordinal: 'seventh'},
8: {name: 'eight', ordinal: 'eighth'},
9: {name: 'nine', ordinal: 'ninth'},
10: {name: 'ten', ordinal: 'tenth'},
11: {name: 'eleven', ordinal: 'eleventh'},
12: {name: 'twelve', ordinal: 'twelfth'},
13: {name: 'thirteen', ordinal: 'thirteenth'},
14: {name: 'fourteen', ordinal: 'fourteenth'},
15: {name: 'fifteen', ordinal: 'fifteenth'},
16: {name: 'sixteen', ordinal: 'sixteenth'},
17: {name: 'seventeen', ordinal: 'seventeenth'},
18: {name: 'eighteen', ordinal: 'eighteenth'},
19: {name: 'nineteen', ordinal: 'nineteenth'},
20: {name: 'twenty', ordinal: 'twentyth'},
30: {name: 'thirty', ordinal: 'thirtyth'},
40: {name: 'fourty', ordinal: 'fourtyth'},
50: {name: 'fifty', ordinal: 'fiftyth'},
60: {name: 'sixty', ordinal: 'sixtyth'},
70: {name: 'seventy', ordinal: 'sventyth'},
80: {name: 'eighty', ordinal: 'eightyth'},
90: {name: 'ninety', ordinal: 'ninetieth'}
};
let n = String(num);
let text;
if (n < 21) {
text = numberMap[n][ord? 'ordinal' : 'name'];
} else if (n < 1e2) {
let units = n % 10;
let tens = Math.floor(n / 10) * 10;
text = units? `${numberMap[tens].name}-${toWord(units, ord)}` : `${numberMap[tens].ordinal}`;
} else if (n < 1e3) {
let hundreds = Math.floor(n / 1e2);
let remainder = n % 1e2;
text = `${toWord(hundreds)} hundred` +
(remainder? ` and ${toWord(remainder)}` : '');
} else if (n < 1e4) {
let thousands = Math.floor(n / 1e3);
let noHundreds = String(n).slice(-3,-2) == '0';
let remainder = n % 1e3;
text = `${toWord(thousands)} thousand` +
`${noHundreds? ' and' : ''}` +
(remainder? ` ${toWord(remainder)}` : '');
}
return text;
}
let fullDate = '';
let day = toWord(date.getDate(), true);
fullDate += day + ' day of ';
let month = date.toLocaleString('en',{month:'long'});
fullDate += month + ' ';
let year = toWord(date.getFullYear());
fullDate += year;
return fullDate;
}
// Examples
// Simple date formatter
let f = date => date.toLocaleString('en-GB', {
year:'numeric',month:'short',day:'2-digit'});
[new Date(666,0,1),
new Date(1215,4,31),
new Date(),
new Date(2222,5,13)
].forEach(d => console.log(f(d) + '\n' + toSpeakableDate(d)));