【问题标题】:Set Date by day of week, week & year按星期、星期和年份设置日期
【发布时间】:2020-01-09 14:23:50
【问题描述】:

我正在制作日历。我的日历上的事件每年在一周的同一天重复。

例如:

  • eventOne,星期日 (0),第 3 周

  • eventTwo,星期二 (2),第 12 周

EventOne 应该有一个日期对象,该对象始终是当年第 3 周的星期日。

EventTwo 应该有一个日期对象,该对象始终是当年第 12 周的星期二。

function getDateOfISOWeek(w, y) {
  var simple = new Date(y, 0, 1 + (w - 1) * 7)
  var dow = simple.getDay()
  var ISOweekStart = simple
  if (dow <= 4)
    ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1)
  else
    ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay())
  return ISOweekStart
}

const date = getDateOfISOWeek(3, 2020)
console.log(date)

上述函数将为我提供我请求的一周的第一天,但​​没有实现一周中的某一天,我一直在努力寻找一个 Date 函数来执行此操作。

如果有任何方便的功能可以提供帮助,我很乐意使用 moment 或 date-fns,但如果我可以使用原生 javascript 解决方案,我会更喜欢。

【问题讨论】:

  • 您的日期是时区规定的一周开始。我看到了 1 月 12 日星期日 23:00 - 你到底有什么问题?
  • 顺便说一句,1 月 12 日是第二个星期日,而不是您正在寻找的第三个星期日
  • 所以“1 月第 3 周的星期日”是固定的,或者您希望能够更改它?
  • 如果第三周是固定的,那么为什么要将周参数传递给 getDateISOWeek?
  • 好吧,我希望日期始终在第 3 周,星期三,没有考虑到我想调整到的星期几。

标签: javascript date


【解决方案1】:

getDateOfISOWeek 工作正常,虽然有点笨拙。您只需添加所需的天数即可获得所需的特定日期。

ISO 周从星期一开始,因此只需获取星期的开始并将天数加减 1。星期日可以是 0 或 7,因此 ECMAScript 或 ISO 编号都可以。

/* Return date for start of ISO week in given year
** @param {number|string} week: required ISO week number
** @param {number|string} year: required year
** @returns {Date} date of Monday at start of week
*/
function getDateOfISOWeek(week, year) {
  // Get date for 1 Jan in given year
  let d = new Date(year, 0, 1);
  let dow = d.getDay();

  // Shift to start of ISO week 1
  d.setDate((dow <= 4? 2 : 9) - d.getDay());
  
  // Add required number of weeks
  d.setDate(d.getDate() + (week - 1)*7);
  
  return d;
}

/* Return date for a day in given ISO week in given year
** @param {number|string} day: day number, Mon=1, Tue=2, ... Sun=0 or 7
** @param {number|string} week: required ISO week number
** @param {number|string} year: required year
** @returns {Date} date of required day
*/
function getDayOfISOWeek(day, week, year) {
  let d = getDateOfISOWeek(week, year);
  d.setDate(d.getDate() + (+day || 7) - 1);
  return d;
}

// Options for formatting dates
let opts =  {weekday:'short', day:'numeric', month:'short', year:'numeric'};

// Examples
[[1, 3,2020], // Mon, week 3, 2020
 [0, 1,2020], // Sun, week 1, 2020
 [7, 1,2020], // Sun, week 1, 2020
 [5,10,2020], // Fri, week 10, 2020
 [6,27,2022], // Sat, week 27, 2022
 [2,12,2020], // Tue, week 12, 2020
 [2,12,2021], // Tue, week 12, 2021
 [2,12,2022]  // Tue, week 12, 2022
].forEach(args => console.log(
  args + ': ' + getDayOfISOWeek(...args).toLocaleString(void 0, opts)
));

附言。您确实应该为块和分号添加大括号来终止语句,否则您可能会遇到一些非常难以发现的错误。

【讨论】:

  • 只是想评论一下我不同意分号,但感谢您的反馈。
【解决方案2】:

我不确定,但如果我理解正确,您可以简单地使用 date-fns:

var startOfYear = require('date-fns/start_of_year')
var getDay = require('date-fns/get_day')
var addDays = require('date-fns/add_days')
var addWeeks = require('date-fns/add_weeks')    

let getDateOfISOWeek = (w, y, d) => {
  let startDayOfYear = startOfYear(new Date(y,0,1));
  let diff = d - getDay(startDayOfYear);
  let firstAppearanceOfYear = addDays(startDayOfYear, diff < 0 ? 7 + diff : diff);
  return addWeeks(firstAppearanceOfYear, w - 1);
}

let result = getDateOfISOWeek(3, 2020, 0); //Sun Jan 19 2020
let result2 = getDateOfISOWeek(3, 2021, 0); // Sun Jan 17 2021

前两个参数 - 周和年,第三个 - 您要查找的日期索引(0 - 星期日,6 - 星期六)

【讨论】:

  • 谢谢,这正是我想要实现的目标!非常感谢谢谢。我对 let 到 const 并通过添加 year 做了一些小的修改; const year = new Date(y, 1, 1, 1, 1, 1)
  • 这会返回不正确的结果。 ISO 2020 年第 3 周开始于 2020 年 1 月 13 日星期一。ECMAScript 第 3 天是星期三,因此 2020 年第 3 周第 3 天的结果应该是 1 月 15 日星期三,而不是 2021 年 1 月 19 日星期日,3 应该是 1 月 20 日星期三,不是太阳 17。
  • @RobG 对不起,代码正常工作,我只是写错了回复
  • 第二个结果还是错误的。 ISO 2021 年第 3 周的星期日是 1 月 24 日,而不是 1 月 17 日(第一周从 2021 年 1 月 4 日星期一开始)。答案不应该需要 OP 中未提及或未标记的库。 OP 的 getDateOfISOWeek 工作正常,不需要库。
  • @RobG 你能检查一下stackoverflow.com/a/59667261/295783,因为我不能 100% 确定它在边缘日期有效
【解决方案3】:

您可以简单地实现这样的功能,方法是从周乘以 7 中减去偏移量;并根据 1 月 4 日计算偏移量(因为那一天是 always in the 1st week)

注意事项:

  • 如果您将星期日视为一周的第一天,请将 0 传递为 weekDay,而如果您将星期日视为一周的最后一天,则应传递 7。
  • week 是从 1 开始的,传递 1 可能会生成具有上一年值的日期(例如,createDate(2020, 1, 1) 将返回 2019 年 12 月 30 日。

function createDate(year, week, weekDay){
  const date = new Date(year, 0, 4)
  const offset = (date.getDay() || 7) - weekDay
  date.setDate(week * 7 - offset - 3)
  return date
}

console.log(createDate(2020,3,7).toDateString())
console.log(createDate(2021,3,7).toDateString())
console.log(createDate(2020,12,4).toDateString())
console.log(createDate(2021,12,4).toDateString())
console.log(createDate(2015,1,4).toDateString())

【讨论】:

  • 我认为您的代码有效。但事实并非如此。 2021 年第 3 周的星期日不是第 10 周
  • 这不是在回答问题。无论如何,您 2020 年的结果与 2021 年的结果不同
  • 1 月 19 日是 2020 年的第 4 周,而 2021 年 1 月 17 日是正确的第 3 周
  • @mplungjan 我的简单解决方案终于回来了,它现在可以工作了(通过日历验证)!我觉得我必须弄清楚我做错了什么。感谢您指出问题!
  • console.log(createDate(2020,1,7).toDateString()) - 这是你所期望的吗?
猜你喜欢
  • 2012-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
相关资源
最近更新 更多