我有一个对象数组,其中包含"年/月"作为字符串值。我将它们作为日期对象进行比较,但问题是如果我比较年份和第一个月它会失败,因为它在代码中:" 2015"和" 2015/1"
const sortYearsMonthsDescending = (items) => items.sort((a, b) => (new Date(a.value) - new Date(b.value)));
const toBeSortedWorking = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}];
const toBeSortedNotWorking = [{value: "1933"}, {value:"1933/11"}, {value: "1933/1"}];
console.log(sortYearsMonthsDescending(toBeSortedWorking));
console.log(sortYearsMonthsDescending(toBeSortedNotWorking));

答案 0 :(得分:0)
let dates = ['2012','2018/1','2018','2014/3','2015','2012/5','2019','2013/7','2011/3','2010/10','2039/3'];
function compareDates(date1, date2) {
for (let i = 0; i < Math.max(date1.length, date2.length); i++) {
if (date1[i] > date2[i]) return 1;
else if (date1[i] < date2[i]) return -1;
else if (!date1[i] && date2[i]) return -1;
else if (date1[i] && !date2[i]) return 1;
}
return 0;
}
console.log(dates.sort(compareDates));
答案 1 :(得分:0)
您可以轻松完成,因为Date
是comparable object
Compare two dates with JavaScript
const a = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}];
const b = [{value: "1932"}, {value:"1933/11"}, {value: "1932/1"}];
function sort(items) {
return items
.sort((a, b) => {
a = a.value.split('/');
b = b.value.split('/');
// months at Index = 1, consider as 0 based
a[1] = a[1] ? (a[1] - 1) : 0;
b[1] = b[1] ? (b[1] - 1) : 0;
/* ASC */ return (new Date(...a)) - (new Date(...b));
/* DESC */ return (new Date(...b)) - (new Date(...a));
})
;
}
console.log('a = ', sort(a));
console.log('b = ', sort(b));
答案 2 :(得分:0)
无法以区分提供月份值的方式初始化日期,因为它为所有人使用默认值以便能够创建有效日期。
在这个特定的用例中,我认为你可以在日期字符串的长度上添加二次计算,如下所示:
const sortYearsMonthsDescending = (items) => items.sort((a, b) =>
(new Date(a.value) - new Date(b.value))) || (a.value.length - b.value.length);
基本上,这是一个边缘情况,"2015"
和"2015/1"
之间存在歧义。我们用语句&#34来解决这种歧义:在较长的字符串之前取较短的字符串&#34;。
答案 3 :(得分:0)
请注意,下面我还列出了可扩展性的日期。如果根本不需要,则可以轻松删除。
解决方案1 - 字符串排序键YYYY-MM-DD-LLLLL
以下解决方案创建了一个不使用Date
对象进行排序的密钥,并且还考虑到应该按升序排序顺序处理没有月份或日期的字符串。
排序键是:YYYY-MM-DD-LLLLL
其中L
是长度。
const ensureDigits = (value, digits) => {
return (Math.pow(10, digits) + value).toString().slice(- digits);
};
const sortDateStrings = (dateStrLst, descending) => {
return dateStrLst
.map(dateStr => {
const parts = dateStr.value.split('/');
const year = parts[0];
const month = ensureDigits(parts[1] || 1, 2);
const day = ensureDigits(parts[2] || 1, 2);
const length = ensureDigits(dateStr.value.length, 5);
return { item: dateStr, sortKey: `${year}-${month}-${day}-${length}` }
})
.sort((model1, model2) =>
model1.sortKey.localeCompare(model2.sortKey) * (descending ? -1 : 1))
.map(model => model.item);
}
const dateStrLst1 = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}];
const dateStrLst2 = [{value: "1932"}, {value:"1933/11"}, {value: "1932/1"}];
console.log(sortDateStrings(dateStrLst1).map(item => item.value));
console.log(sortDateStrings(dateStrLst2).map(item => item.value));
console.log(sortDateStrings(dateStrLst1, true).map(item => item.value));
console.log(sortDateStrings(dateStrLst2, true).map(item => item.value));
&#13;
解决方案2 - 按日期排序,然后按长度排序,使用Lodash
const sortDateStrings = (dateStrLst, descending) => {
const model = dateStrLst
.map(dateStr => {
const parts = dateStr.value.split('/');
const year = parts[0];
const month = (parts[1] - 1) || 0;
const day = parts[2] || 1;
return { item: dateStr, date: new Date(year, month, day), length: dateStr.value.length };
});
const direction = descending ? 'desc' : 'asc';
return _.orderBy(model, ["date", "length"], [direction, direction])
.map(modelItem => modelItem.item);
};
const dateStrLst1 = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}];
const dateStrLst2 = [{value: "1932"}, {value:"1933/11"}, {value: "1932/1"}];
console.log(sortDateStrings(dateStrLst1).map(item => item.value));
console.log(sortDateStrings(dateStrLst2).map(item => item.value));
console.log(sortDateStrings(dateStrLst1, true).map(item => item.value));
console.log(sortDateStrings(dateStrLst2, true).map(item => item.value));
&#13;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.js"></script>
</head>
<body>
</body>
</html>
&#13;
警告:解析日期
// valid ISO 8601 string
const date1 = new Date(Date.parse('1932'));
Fri Jan 01 1932 02:00:00 GMT+0200 (GTB Standard Time)
// not a valid string
const date2 = new Date(Date.parse('1932/1'));
Fri Jan 01 1932 00:00:00 GMT+0200 (GTB Standard Time)
// not a valid string
const date3 = new Date(Date.parse('1932/01'));
Fri Jan 01 1932 00:00:00 GMT+0200 (GTB Standard Time)
date1.getTime() == date2.getTime();
false
也是如此:
// not a valid ISO 8601 string
const date2 = new Date(Date.parse('1932-1'));
Fri Jan 01 1932 00:00:00 GMT+0200 (GTB Standard Time)
但这个是正确的:
// valid ISO 8601 string
const date3 = new Date(Date.parse('1932-01'));
Fri Jan 01 1932 02:00:00 GMT+0200 (GTB Standard Time)
同样的问题也发生在:
// incorrect usage of constructor
new Date(1932);
Thu Jan 01 1970 02:00:01 GMT+0200 (GTB Standard Time)
// correct usage of constructor
new Date(1932, 0);
Fri Jan 01 1932 00:00:00 GMT+0200 (GTB Standard Time)
但最后一个new Date(1932)
不正确,因为构造函数至少允许{+ 1}}中的年份和月份。
请注意,在我使用new Date(year, month[, date[, hours[, minutes[, seconds[, milliseconds]]]]]);
之前,因为:
注意:由于浏览器差异和不一致,强烈建议不要使用Date构造函数(和Date.parse,它们是等效的)解析日期字符串。
new Date(Date.parse(...))
可以解析:
关于这个问题,ISO 8601格式是(注意日期和月份只有两位数字):
Date
关于这个问题,RFC2822格式是:
Year:
YYYY (eg 1997)
Year and month:
YYYY-MM (eg 1997-07)
Complete date:
YYYY-MM-DD (eg 1997-07-16)
因此,我找不到匹配类似date-time = [ day-of-week "," ] date FWS time [CFWS]
date = day month year
的内容的格式,以便在浏览器之间进行一致的解析。
性能方面可能是坚持1932/1
格式,通常是第一个被检查的格式,然后是ISO 8601
。
如果您使用 momentjs ,请检查parsing strings section是否支持您要解析的格式。
<强>结论:强>
始终如一地创建日期对象以获得正确的结果:
RFC2822
new Date(1932, 0)
与Date.parse('1932')
相同 - 请注意月份的两位数 Date.parse('1932-01')
给出UTC日期(仅限日期),因为:
对ISO 8601格式的支持不同之处在于,仅限日期的字符串(例如&#34; 1970-01-01&#34;)被视为UTC,而不是本地。
答案 4 :(得分:0)
您只需要以易于比较的格式获取字符串,无论是字符串还是日期。但是,使用日期会增加一个问题,即如何确保1933年在1932/12和1933/1之间正确排序。
以下通过附加&#34; / 00&#34;作为字符串排序任何只有一年的价值,并将前导零加到单个数字的月份,以便&#34; 2015/3&#34;比较为&#34; 2015/03&#34;。
var values = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}, {value: "1933"}, {value: "1932/12"}, {value:"1933/11"}, {value: "1933/1"}];
console.log(JSON.stringify(values));
values.sort(function(a, b) {
function fixMonth(date) {
var t = date.split('/');
return t[0] + '/' + ('0'+t[1]).slice(-2);
}
a = /\//.test(a.value)? fixMonth(a.value) : a.value + '/00';
b = /\//.test(b.value)? fixMonth(b.value) : b.value + '/00';
return a.localeCompare(b);
})
console.log(JSON.stringify(values));
&#13;
如果需要降序排序,只需反转结果。
另一个版本是:
var values = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}, {value: "1933"}, {value: "1932/12"}, {value:"1933/11"}, {value: "1933/1"}];
values.sort(function(a, b) {
a = /\//.test(a.value) ? a.value.replace(/(\/)(\d)$/, "$10$2") : a.value + '/00';
b = /\//.test(b.value) ? b.value.replace(/(\/)(\d)$/, "$10$2") : b.value + '/00';
return a.localeCompare(b);
})
console.log(JSON.stringify(values));
&#13;
甚至:
var values = [{value: "2015"}, {value:"2015/3"}, {value: "2015/10"}, {value: "1933"}, {value: "1932/12"}, {value:"1933/11"}, {value: "1933/1"}];
values.sort(function(a, b) {
function resolve(s) {
return /\//.test(s) ? s.replace(/(\/)(\d)$/, "$10$2") : s + '/00';
}
return resolve(a.value).localeCompare(resolve(b.value));
})
console.log(JSON.stringify(values));
&#13;