像在PHP中一样,用JavaScript获得一年中的一周时间


140

我如何获得年度的当前星期数,例如PHP的星期数date('W')

它应该是ISO-8601的星期数,从星期一开始的星期数。


1
在<a href=" javascript.about.com/library/blweekyear.htm "> <b>此处</ b> </a>中查找,这是我在搜索“一年中的javascript星期”时给出的第一个链接。
皮特·威尔逊

+1哈哈!那是我从自己那里获得的摘录的地方,但是我记不清来源,因为我是前一段时间才得到的。
汤姆·钱特勒

@Pete:该代码在当前星期变为22。虽然应该是21
PeeHaa

@Pete::D Nopez一个简单的-1不会解决问题:P那将无法获得ISO-8601周数。ISO-8601中的一周从星期一开始。第一周是一年中的第一个星期四。en.wikipedia.org/wiki/ISO-8601。PS不是我对你的不满。
PeeHaa 2011年

Answers:


276

您应该可以在这里获得所需的信息:http : //www.merlyn.demon.co.uk/js-date6.htm#YWD

在同一站点上,更好的链接是:使用几周

编辑

这是一些代码,这些代码基于提供的链接以及Dommer在Eariler上发布的链接。已针对http://www.merlyn.demon.co.uk/js-date6.htm#YWD上的结果进行了轻微测试。请彻底测试,不提供任何保证。

编辑2017

在观察到的夏时制和1月1日是星期五的年份中,日期存在问题。通过使用所有UTC方法进行修复。以下代码将相同的结果返回给Moment.js。

/* For a given date, get the ISO week number
 *
 * Based on information at:
 *
 *    http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
 *
 * Algorithm is to find nearest thursday, it's year
 * is the year of the week number. Then get weeks
 * between that date and the first day of that year.
 *
 * Note that dates in one year can be weeks of previous
 * or next year, overlap is up to 3 days.
 *
 * e.g. 2014/12/29 is Monday in week  1 of 2015
 *      2012/1/1   is Sunday in week 52 of 2011
 */
function getWeekNumber(d) {
    // Copy date so don't modify original
    d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
    // Set to nearest Thursday: current date + 4 - current day number
    // Make Sunday's day number 7
    d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
    // Get first day of year
    var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
    // Calculate full weeks to nearest Thursday
    var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
    // Return array of year and week number
    return [d.getUTCFullYear(), weekNo];
}

var result = getWeekNumber(new Date());
document.write('It\'s currently week ' + result[1] + ' of ' + result[0]);

创建“ UTC”日期时,小时为零。

最小化的原型版本(仅返回星期数):

Date.prototype.getWeekNumber = function(){
  var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
  var dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
  return Math.ceil((((d - yearStart) / 86400000) + 1)/7)
};

document.write('The current ISO week number is ' + new Date().getWeekNumber());

测试部分

在本部分中,您可以输入YYYY-MM-DD格式的任何日期,并检查该代码是否具有与Moment.js ISO周号相同的周号(在2000年至2050年的50年中进行了测试)。

Date.prototype.getWeekNumber = function(){
  var d = new Date(Date.UTC(this.getFullYear(), this.getMonth(), this.getDate()));
  var dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
  return Math.ceil((((d - yearStart) / 86400000) + 1)/7)
};

function checkWeek() {
  var s = document.getElementById('dString').value;
  var m = moment(s, 'YYYY-MM-DD');
  document.getElementById('momentWeek').value = m.format('W');
  document.getElementById('answerWeek').value = m.toDate().getWeekNumber();      
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>

Enter date  YYYY-MM-DD: <input id="dString" value="2021-02-22">
<button onclick="checkWeek(this)">Check week number</button><br>
Moment: <input id="momentWeek" readonly><br>
Answer: <input id="answerWeek" readonly>


8
此代码将2011年1月2日计算为2010年的第53周,应将其计算为第52周。这在原始代码中正确运行,但在您的改编中无效。
Alasdair

4
你救了我的屁股。谢谢。如果您想为开源做贡献,我建议您为jQuery UI方法创建一个补丁:$ .datepicker.iso8601Week(date),因为它只返回weekNo,但是没有年份。
基督教徒

18
今天,2016年1月4日,我注意到也有必要添加d.setMilliseconds(0)-根据我使用的是新Date()还是新Date(“ 1/4/2016”),它继续显示同一日期的不同星期数。对于可能会遇到相同情况的其他人,请注意。
Jacob Lauritzen

2
提供的代码不遵循ISO 8601,这是关闭的一个
埃里克·格兰奇

2
糟糕,我的错字应该是有效的'2015-12-30'。
Ally


25

如上所述,但没有课程:

let now = new Date();
let onejan = new Date(now.getFullYear(), 0, 1);
week = Math.ceil( (((now - onejan) / 86400000) + onejan.getDay() + 1) / 7 );

4
一简堂!*《忍者
大战》

2
这是即使在一年的第一周也能获取正确的星期数的唯一答案。
PrasadW

注意要做(now.getTime() - onejan.getTime())避免生成问题。
Swoox

4
这个问题要求ISO 8601,而忽略。作为对这个问题的答案,这是完全错误的
havlock '18

23

正确http://javascript.about.com/library/blweekyear.htm

Date.prototype.getWeek = function() {
    var onejan = new Date(this.getFullYear(),0,1);
    var millisecsInDay = 86400000;
    return Math.ceil((((this - onejan) /millisecsInDay) + onejan.getDay()+1)/7);
};

1
简洁,但将星期日视为一周的第一天,因此2015年12月27日星期日是第53周的第一天,而不是第52周的最后一天。
RobG

3
我认为,既然将其添加到原型中,这就是您期望的,因为Date将星期日视为第一天。
Ed Sykes

在“夏令时”那天不会有问题吗?我认为它不会在夏天凌晨1点之前推进。
Hafthor

另外,从技术上讲,这不是将星期提前到0:00:00.001吗?更好地使用Math.floor吗?
Hafthor

11

Jacob Wright的Date.format()库以PHP date()函数的样式实现日期格式,并支持ISO-8601周号:

new Date().format('W');

仅仅一个星期的时间,这可能有点矫kill过正,但是它确实支持PHP样式格式,并且如果您要进行很多此类操作,将非常方便。


快速汇总在一起的脚本的好方法:)
SteenSchütt15年

6
getWeekOfYear: function(date) {
        var target = new Date(date.valueOf()),
            dayNumber = (date.getUTCDay() + 6) % 7,
            firstThursday;

        target.setUTCDate(target.getUTCDate() - dayNumber + 3);
        firstThursday = target.valueOf();
        target.setUTCMonth(0, 1);

        if (target.getUTCDay() !== 4) {
            target.setUTCMonth(0, 1 + ((4 - target.getUTCDay()) + 7) % 7);
        }

        return Math.ceil((firstThursday - target) /  (7 * 24 * 3600 * 1000)) + 1;
    }

以下代码与时区无关(使用UTC日期),并且根据https://en.wikipedia.org/wiki/ISO_8601运行


4

我发现在Oracle规范中描述了Java SE的SimpleDateFormat类很有用:http : //goo.gl/7MbCh5。就我而言,在Google Apps脚本中,它的工作方式如下:

function getWeekNumber() {
  var weekNum = parseInt(Utilities.formatDate(new Date(), "GMT", "w"));
  Logger.log(weekNum);
}

例如,在电子表格宏中,您可以检索文件的实际时区:

function getWeekNumber() {
  var weekNum = parseInt(Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "w"));
  Logger.log(weekNum);
}

4

这会将“ getWeek”方法添加到Date.prototype,该方法返回从年初开始的星期数。该参数定义一周中的哪一天要考虑第一天。如果未传递任何参数,则假定第一天为星期日。

/**
 * Get week number in the year.
 * @param  {Integer} [weekStart=0]  First day of the week. 0-based. 0 for Sunday, 6 for Saturday.
 * @return {Integer}                0-based number of week.
 */
Date.prototype.getWeek = function(weekStart) {
    var januaryFirst = new Date(this.getFullYear(), 0, 1);
    if(weekStart !== undefined && (typeof weekStart !== 'number' || weekStart % 1 !== 0 || weekStart < 0 || weekStart > 6)) {
      throw new Error('Wrong argument. Must be an integer between 0 and 6.');
    }
    weekStart = weekStart || 0;
    return Math.floor((((this - januaryFirst) / 86400000) + januaryFirst.getDay() - weekStart) / 7);
};

1
2016年的第一个日历周从1月4日在德国开始,但是您的函数从1月1日起从0开始重新计数。尽管已经是2019年第一个日历周,但它在年底还​​返回了错误的数字,例如2018-11-31(第53周)为52 :( new Date(Date.UTC(2018,11, 31)).getWeek(1)+1星期一是德国的一周的第一天)。
CodeManX

这就是它的预期目的,我认为这是最可能的用例。否则,2016年的前三天将会失败。该月的第一天被认为是该月的第一周,没有问题,并且有多少天。如果您需要该功能以其他方式工作,则可以根据需要对其进行调整。同样,如果一个星期落入给定年份和下一年,则可以称为该年的最后一周,也可以称为第二年的第一周(根据当前逻辑)。
提格伦2015年

谢谢(你的)信息。我最终使用了RobG的解决方案,该解决方案正确地实现了ISO8601周日期(12月的最后几天和1月的第一天可能属于第52、53或1周: en.m.wikipedia.org/wiki/ISO_week_date
CodeManX

4

获取任何给定日期的星期数

function week(year,month,day) {
    function serial(days) { return 86400000*days; }
    function dateserial(year,month,day) { return (new Date(year,month-1,day).valueOf()); }
    function weekday(date) { return (new Date(date)).getDay()+1; }
    function yearserial(date) { return (new Date(date)).getFullYear(); }
    var date = year instanceof Date ? year.valueOf() : typeof year === "string" ? new Date(year).valueOf() : dateserial(year,month,day), 
        date2 = dateserial(yearserial(date - serial(weekday(date-serial(1))) + serial(4)),1,3);
    return ~~((date - date2 + serial(weekday(date2) + 5))/ serial(7));
}

console.log(
    week(2016, 06, 11),//23
    week(2015, 9, 26),//39
    week(2016, 1, 1),//53
    week(2016, 1, 4),//1
    week(new Date(2016, 0, 4)),//1
    week("11 january 2016")//2
);

1
我不敢相信,但是这个功能是唯一一直有效的功能!接受的答案在超过夏令时时开始播放,其他人则将“ 0”作为某些年份的星期数。-某些依赖于UTC函数,该函数有时会在前一天返回,因此将其指定为“ 53”或“ 54”。不幸的是,我需要从星期日开始的一周,并且这段代码很难理解...
Melissa Zachariadis

@MelissaZachariadis说I need the week to begin on a Sunday; 我认为唯一需要做的更改是将功能weekday().getDay()+1更改为.getDay()
Rafa

4

下面的代码计算正确的ISO 8601周数。它date("W")在1970年1月1日到1/1/2100之间每周匹配PHP 。

/**
 * Get the ISO week date week number
 */
Date.prototype.getWeek = function () {
  // Create a copy of this date object
  var target = new Date(this.valueOf());

  // ISO week date weeks start on Monday, so correct the day number
  var dayNr = (this.getDay() + 6) % 7;

  // ISO 8601 states that week 1 is the week with the first Thursday of that year
  // Set the target date to the Thursday in the target week
  target.setDate(target.getDate() - dayNr + 3);

  // Store the millisecond value of the target date
  var firstThursday = target.valueOf();

  // Set the target to the first Thursday of the year
  // First, set the target to January 1st
  target.setMonth(0, 1);

  // Not a Thursday? Correct the date to the next Thursday
  if (target.getDay() !== 4) {
    target.setMonth(0, 1 + ((4 - target.getDay()) + 7) % 7);
  }

  // The week number is the number of weeks between the first Thursday of the year
  // and the Thursday in the target week (604800000 = 7 * 24 * 3600 * 1000)
  return 1 + Math.ceil((firstThursday - target) / 604800000);
}

资料来源: Taco van den Broek


如果您不打算扩展原型,请使用以下函数:

function getWeek(date) {
  if (!(date instanceof Date)) date = new Date();

  // ISO week date weeks start on Monday, so correct the day number
  var nDay = (date.getDay() + 6) % 7;

  // ISO 8601 states that week 1 is the week with the first Thursday of that year
  // Set the target date to the Thursday in the target week
  date.setDate(date.getDate() - nDay + 3);

  // Store the millisecond value of the target date
  var n1stThursday = date.valueOf();

  // Set the target to the first Thursday of the year
  // First, set the target to January 1st
  date.setMonth(0, 1);

  // Not a Thursday? Correct the date to the next Thursday
  if (date.getDay() !== 4) {
    date.setMonth(0, 1 + ((4 - date.getDay()) + 7) % 7);
  }

  // The week number is the number of weeks between the first Thursday of the year
  // and the Thursday in the target week (604800000 = 7 * 24 * 3600 * 1000)
  return 1 + Math.ceil((n1stThursday - date) / 604800000);
}

用法示例:

getWeek(); // Returns 37 (or whatever the current week is)
getWeek(new Date('Jan 2, 2011')); // Returns 52
getWeek(new Date('Jan 1, 2016')); // Returns 53
getWeek(new Date('Jan 4, 2016')); // Returns 1

我喜欢这个功能,但是我有一个问题。如果我想把它放回星期日怎么办?我不知道那+6 ) % 7部分是做什么的。感谢磨砂膏!
NoobishPro

1
@Babydead ISO周从星期一开始,但是JavaScript getDay()从星期日开始,因此,如果您希望它从星期日开始,则可以删除更正:var nDay = date.getDay();
thdoan

我已经尝试了8种不同的JS实现来获取周数。这是唯一有效的函数,但是仅当我将所有getter和setter分别更改为getUTC ..和setUTC ..时才知道。我正在对此进行测试:2017-07-17T00:00:00.000Z(第29周)2017-07-23T23:59:59.000Z(第29周)2021-01-04T00:00:00.000Z(第1周)
心理brm


2

对我来说效果很好的代码段是这个:

var yearStart = +new Date(d.getFullYear(), 0, 1);
var today = +new Date(d.getFullYear(),d.getMonth(),d.getDate());
var dayOfYear = ((today - yearStart + 1) / 86400000);
return Math.ceil(dayOfYear / 7).toString();

注意:
d是我想要当前星期几的日期。
+该日期转换成数字(以打字稿工作)。


1

这是我在JavaScript中计算周数的实现。还要校正夏季和冬季的时间偏移量。我使用了本文中一周的定义:ISO 8601

星期从星期一到星期天,1月4日总是在每年的第一周。

// add get week prototype functions
// weeks always start from monday to sunday
// january 4th is always in the first week of the year
Date.prototype.getWeek = function () {
    year = this.getFullYear();
    var currentDotw = this.getWeekDay();
    if (this.getMonth() == 11 && this.getDate() - currentDotw > 28) {
        // if true, the week is part of next year 
        return this.getWeekForYear(year + 1);
    }
    if (this.getMonth() == 0 && this.getDate() + 6 - currentDotw < 4) {
        // if true, the week is part of previous year
        return this.getWeekForYear(year - 1);
    }
    return this.getWeekForYear(year);
}

// returns a zero based day, where monday = 0
// all weeks start with monday
Date.prototype.getWeekDay = function () {
    return  (this.getDay() + 6) % 7;
}

// corrected for summer/winter time
Date.prototype.getWeekForYear = function (year) {
    var currentDotw = this.getWeekDay();
    var fourjan = new Date(year, 0, 4);
    var firstDotw = fourjan.getWeekDay();
    var dayTotal = this.getDaysDifferenceCorrected(fourjan) // the difference in days between the two dates.
    // correct for the days of the week
    dayTotal += firstDotw; // the difference between the current date and the first monday of the first week, 
    dayTotal -= currentDotw; // the difference between the first monday and the current week's monday
    // day total should be a multiple of 7 now
    var weeknumber = dayTotal / 7 + 1; // add one since it gives a zero based week number.
    return weeknumber;
}

// corrected for timezones and offset
Date.prototype.getDaysDifferenceCorrected = function (other) {
    var millisecondsDifference = (this - other);
    // correct for offset difference. offsets are in minutes, the difference is in milliseconds
    millisecondsDifference += (other.getTimezoneOffset()- this.getTimezoneOffset()) * 60000;
    // return day total. 1 day is 86400000 milliseconds, floor the value to return only full days
    return Math.floor(millisecondsDifference / 86400000);
}

为了进行测试,我在Qunit中使用了以下JavaScript测试

var runweekcompare = function(result, expected) {
    equal(result, expected,'Week nr expected value: ' + expected + ' Actual value: ' + result);
}

test('first week number test', function () {
    expect(5);
    var temp = new Date(2016, 0, 4); // is the monday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 4, 23, 50); // is the monday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 10, 23, 50); // is the sunday of the first week of the year
    runweekcompare(temp.getWeek(), 1);
    var temp = new Date(2016, 0, 11, 23, 50); // is the second week of the year
    runweekcompare(temp.getWeek(), 2);
    var temp = new Date(2016, 1, 29, 23, 50); // is the 9th week of the year
    runweekcompare(temp.getWeek(), 9);
});

test('first day is part of last years last week', function () {
    expect(2);
    var temp = new Date(2016, 0, 1, 23, 50); // is the first last week of the previous year
    runweekcompare(temp.getWeek(), 53);
    var temp = new Date(2011, 0, 2, 23, 50); // is the first last week of the previous year
    runweekcompare(temp.getWeek(), 52);
});

test('last  day is part of next years first week', function () {
    var temp = new Date(2013, 11, 30); // is part of the first week of 2014
    runweekcompare(temp.getWeek(), 1);
});

test('summer winter time change', function () {
    expect(2);
    var temp = new Date(2000, 2, 26); 
    runweekcompare(temp.getWeek(), 12);
    var temp = new Date(2000, 2, 27); 
    runweekcompare(temp.getWeek(), 13);
});

test('full 20 year test', function () {
    //expect(20 * 12 * 28 * 2);
    for (i = 2000; i < 2020; i++) {
        for (month = 0; month < 12; month++) {
            for (day = 1; day < 29 ; day++) {
                var temp = new Date(i, month, day);
                var expectedweek = temp.getWeek();
                var temp2 = new Date(i, month, day, 23, 50);
                var resultweek = temp.getWeek();
                equal(expectedweek, Math.round(expectedweek), 'week number whole number expected ' + Math.round(expectedweek) + ' resulted week nr ' + expectedweek);
                equal(resultweek, expectedweek, 'Week nr expected value: ' + expectedweek + ' Actual value: ' + resultweek + ' for year ' + i + ' month ' + month + ' day ' + day);
            }
        }
    }
});

0

这周的事情真是让人难以忍受。网络上的大多数脚本都不适合我。他们大部分时间都在工作,但是所有人都在某个时间点中断了,尤其是当年份更改并且一年的最后一周突然是明年的第一周等时。甚至Angular的日期过滤器也显示了错误的数据(那是明年的第一周,第53周)。

注意:示例旨在与欧洲周(周一至周一)一起使用!

getWeek()

Date.prototype.getWeek = function(){

    // current week's Thursday
    var curWeek = new Date(this.getTime());
        curWeek.setDay(4);

    // Get year's first week's Thursday
    var firstWeek = new Date(curWeek.getFullYear(), 0, 4);
        firstWeek.setDay(4);

    return (curWeek.getDayIndex() - firstWeek.getDayIndex()) / 7 + 1;
};

setDay()

/**
* Make a setDay() prototype for Date
* Sets week day for the date
*/
Date.prototype.setDay = function(day){

    // Get day and make Sunday to 7
    var weekDay = this.getDay() || 7;
    var distance = day - weekDay;
    this.setDate(this.getDate() + distance);

    return this;
}

getDayIndex()

/*
* Returns index of given date (from Jan 1st)
*/

Date.prototype.getDayIndex = function(){
    var start = new Date(this.getFullYear(), 0, 0);
    var diff = this - start;
    var oneDay = 86400000;

    return Math.floor(diff / oneDay);
};

我已经对此进行了测试,并且看起来效果很好,但是如果您发现其中存在缺陷,请告诉我。


0

我做了很多尝试,以获取最短的代码来获得符合ISO的周数。

Date.prototype.getWeek=function(){
    var date=new Date(this);
    date.setHours(0,0,0,0);
    return Math.round(((date.setDate(this.getDate()+2-(this.getDay()||7))-date.setMonth(0,4))/8.64e7+3+(date.getDay()||7))/7)+"/"+date.getFullYear();}

date为避免更改原始变量,该变量是必需的this。我用返回值的setDate()setMonth(),以分配与getTime()到保存码长和我用于一天而不是单个元素的乘法或具有五个零的若干毫秒的expontial数。this是日期或毫秒数,返回值String例如是“ 49/2017”。




0

Angular2 + DatePipe的最短解决方法,针对ISO-8601进行了调整:

import {DatePipe} from "@angular/common";

public rightWeekNum: number = 0;
  
constructor(private datePipe: DatePipe) { }
    
calcWeekOfTheYear(dateInput: Date) {
  let falseWeekNum = parseInt(this.datePipe.transform(dateInput, 'ww'));
  this.rightWeekNum = falseWeekNum ? falseWeekNum : falseWeekNum-1;
}

-1
now = new Date();
today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
firstOfYear = new Date(now.getFullYear(), 0, 1);
numOfWeek = Math.ceil((((today - firstOfYear) / 86400000)-1)/7);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.