dayjs跨年周数问题:自定义插件尝试

607 阅读2分钟

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 格式化时,本质上就是用的这两个

三、解决

问题很简单,

  1. 需要前后端统一,每一周的开始是周一
  2. 如果本年第一天是周一,则不做处理
  3. 如果不是周一,则默认从这天到下一周的开始为第一周,其他事件,周数加一

以下为代码(写成格式化的插件了)

// 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;