dayjs的跨年周数问题
一、起因
最近在项目里使用 dayjs
的过程中,遇见一个问题,就是在每年的第一天,此时会被dayjs
认为是上一年的最后一周,这与我们的认识不符,前后端也要统一,所以需要解决这个问题,简单思考了下。
首先需要指定,每周的开始是周一(dayjs
默认是周日)所以需要使用isoWeek
二、验证
// 以2022年为例,2022年1月1日是周六
dayjs('2022-12-31').week() // 53
dayjs('2022-01-01').week() // 1
dayjs('2022-01-02').week() // 2
dayjs('2022-12-31').isoWeek() // 52
dayjs('2022-01-01').isoWeek() // 52
dayjs('2022-01-02').isoWeek() // 52
可以很明显看见,对于判断跨年周时,无法满足我们的需求 注:使用 format 格式化时,本质上就是用的这两个
三、解决
问题很简单,
- 需要前后端统一,每一周的开始是周一
- 如果本年第一天是周一,则不做处理
- 如果不是周一,则默认从这天到下一周的开始为第一周,其他事件,周数加一
以下为代码(写成格式化的插件了)
// weekFormat.ts
import { PluginFunc } from 'dayjs';
import dayjs, { Dayjs } from 'dayjs';
declare module 'dayjs' {
interface Dayjs {
weekFormat(formatStr: string): string;
}
}
const padStart = (string: string | number, length: number, pad: string) => {
const s = String(string);
if (!s || s.length >= length) return string;
return `${Array(length + 1 - s.length).join(pad)}${string}`;
};
export const weekFormat: PluginFunc = (option, dayjsClass, dayjsFactory) => {
const proto = dayjsClass.prototype;
proto.weekFormat = function (formatStr: string) {
if (!formatStr.toLowerCase().includes('w')) return this.format(formatStr);
const monday = 1;
const start = this.startOf('year');
const end = start.add(7 - start.day(), 'day');
let week = this.isoWeek(); // isoWeek
if (start.day() !== monday) {
// 本年第一天不是周一,在第一周区间内
if (this.isBetween(start, end, 'day', '[]')) {
week = 1; // 第一周
} else {
// 本年第一天不是周一,其他周需要加一
week += 1; // 加一周
}
return this.format(formatStr).replace(/\[([^\]]+)]|ww|w|WW|W|S/g, (match: string) => {
return padStart(week, match === 'w' || match === 'W' ? 1 : 2, '0');
});
} else {
return this.format(formatStr);
}
};
};
export default weekFormat;