像 PHP 一样使用 JavaScript 获取每年的周数

我如何得到当前的周数的一年,像 PHP 的 date('W')

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

284014 次浏览

你应该能够在这里得到你想要的: Http://www.merlyn.demon.co.uk/js-date6.htm#ywd

同一个站点上的一个更好的链接是: < 罢工 > 工作周

剪辑

下面是一些基于 Dommer 提供的链接和之前发布的链接的代码。它已经在 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:
*
*    THIS PAGE (DOMAIN EVEN) DOESN'T EXIST ANYMORE UNFORTUNATELY
*    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 相同的周数(从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>

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

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

对于仅仅一个星期的时间来说,这可能有点夸张,但是它确实支持 PHP 样式格式化,如果您要做很多这样的工作,那么它非常方便。

很好 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);
};


let d = new Date(2020,11,30);
for (let i=0; i<14; i++) {
console.log(`${d.toDateString()} is week ${d.getWeek()}`);
d.setDate(d.getDate() + 1);
}

不是 ISO-8601星期号码,但如果搜索引擎指出你在这里无论如何。

如上所述,但没有类:

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


console.log(week);

这将“ getWeek”方法添加到 Date.model 中,该方法返回从年初开始的星期数。参数定义了一周中的哪一天考虑第一天。如果没有参数通过,则假定第一天为星期日。

/**
* 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);
};
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工作

获取任意给定日期的工作日号

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

你也可以使用 Momentjs 库:

moment().format('W')

如果你已经在一个角度的项目,你可以使用 $filter('date')

例如:

var myDate = new Date();
var myWeek = $filter('date')(myDate, 'ww');

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

/**
* 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);
}

图片来源: http://techblog.procurios.nl/k/news/view/33796/14863/Calcul- iso-8601-week-and-year-in-javascript.html”rel = “ noReferrer”> 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

这个星期的数字真是让人头疼。网上的大多数脚本都不适合我。他们大部分时间都在工作,但是他们都在某些时候停止了工作,特别是当年份改变,一年中的最后一周突然变成了明年的第一周等等。甚至 Angular 的日期过滤器也显示出不正确的数据(它是明年的第一周,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);
};

我已经测试了这个,它似乎工作得很好,但如果你注意到一个缺陷,请让我知道。

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

下面是我用 JavaScript 计算星期数的实现。夏季和冬季时间偏移也进行了修正。 我使用了本文中的周的定义: < a href = “ https://en.wikipedia.org/wiki/ISO _ 8601”rel = “ nofollow noReferrer”> ISO 8601

星期是从星期一到星期天,而一月四日总是在一年的第一个星期。

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

我尝试了很多,以获得最短的代码,以获得周数 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()以节省代码长度,并且我使用了一个指数数字来代替单个元素的乘法或者一个有五个零的数字。this是日期或毫秒数,返回值是 String,例如“49/2017”。

下面的代码片段对我来说非常有用:

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是我想要当前星期号的日期。
+将日期转换为数字(使用 TypeScript)。

与 Luxon (https://github.com/moment/luxon)合作:

import { DateTime } from 'luxon';
const week: number = DateTime.fromJSDate(new Date()).weekNumber;

另一个基于库的选项: 使用 d3-time-format:

const formatter = d3.timeFormat('%U');
const weekNum = formatter(new Date());

Angular2 + 日期管道的最短解决方案,根据 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 = (dateInput.getDay() == 0) ? falseWeekNumber-1 : falseWeekNumber;
}

这里稍微改编了一下 Typecript,它也会返回一周开始和周末的日期。我认为在用户界面中显示这些数字是很常见的,因为人们通常不会记住周数。

function getWeekNumber(d: Date) {
// 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
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
// Calculate full weeks to nearest Thursday
const weekNo = Math.ceil(
((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7
);


const weekStartDate = new Date(d.getTime());
weekStartDate.setUTCDate(weekStartDate.getUTCDate() - 3);


const weekEndDate = new Date(d.getTime());
weekEndDate.setUTCDate(weekEndDate.getUTCDate() + 3);


return [d.getUTCFullYear(), weekNo, weekStartDate, weekEndDate] as const;
}

灵感来自 RobG 的回答

我想要的是给定日期的星期几。所以我的答案只是基于星期天的星期几。但你可以选择其他日子(即星期一、星期二...) ;

首先我找到给定日期中的星期天,然后计算星期。

function getStartWeekDate(d = null) {
const now = d || new Date();
now.setHours(0, 0, 0, 0);
const sunday = new Date(now);
sunday.setDate(sunday.getDate() - sunday.getDay());
return sunday;
}


function getWeek(date) {
const sunday = getStartWeekDate(date);
const yearStart = new Date(Date.UTC(2021, 0, 1));
const weekNo = Math.ceil((((sunday - yearStart) / 86400000) + 1) / 7);
return weekNo;
}
// tests
for (let i = 0; i < 7; i++)  {
let m = 14 + i;
let x = getWeek(new Date(2021, 2, m));
console.log('week num: ' + x, x + ' == ' + 11, x == 11, m);
}


for (let i = 0; i < 7; i++)  {
let m = 21 + i;
let x = getWeek(new Date(2021, 2, m));
console.log('week num: ' + x, x + ' == ' + 12, x == 12, 'date day: ' +  m);
}
for (let i = 0; i < 4; i++)  {
let m = 28 + i;
let x = getWeek(new Date(2021, 2, m));
console.log('week num: ' + x, x + ' == ' + 13, x == 13, 'date day: ' + m);
}
for (let i = 0; i < 3; i++)  {
let m = 1 + i;
let x = getWeek(new Date(2021, 3, m));
console.log('week num: ' + x, x + ' == ' + 13, x == 13, 'date day: ' +  m);
}


for (let i = 0; i < 7; i++)  {
let m = 4 + i;
let x = getWeek(new Date(2021, 3, m));
console.log('week num: ' + x, x + ' == ' + 14, x == 14, 'date day: ' +  m);
}

function getWeek(param) {
let onejan = new Date(param.getFullYear(), 0, 1);
return Math.ceil((((param.getTime() - onejan.getTime()) / 86400000) + onejan.getDay()) / 7);
}

这是我的打印脚本实现,我测试了一些日期。这个实现允许您将一周的第一天设置为任何一天。

//sunday = 0, monday = 1, ...
static getWeekNumber(date: Date, firstDay = 1): number {
const d = new Date(date.getTime());
d.setHours(0, 0, 0, 0);


//Set to first day of the week since it is the same weeknumber
while(d.getDay() != firstDay){
d.setDate(d.getDate() - 1);
}


const dayOfYear = this.getDayOfYear(d);
let weken = Math.floor(dayOfYear/7);


// add an extra week if 4 or more days are in this year.
const daysBefore = ((dayOfYear % 7) - 1);
if(daysBefore >= 4){
weken += 1;
}


//if the last 3 days onf the year,it is the first week
const t = new Date(d.getTime());
t.setDate(t.getDate() + 3);
if(t.getFullYear() > d.getFullYear()){
return 1;
}
weken += 1;


return weken;
}


private static getDayOfYear(date: Date){
const start = new Date(date.getFullYear(), 0, 0);
const diff = (date.getTime() - start.getTime()) + ((start.getTimezoneOffset() - date.getTimezoneOffset()) * 60 * 1000);
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
return day;
}

测试:

describe('getWeeknumber', () => {
it('should be ok for 0 sunday', () => {
expect(DateUtils.getWeekNumber(new Date(2015, 0, 4), 0)).toBe(1);


expect(DateUtils.getWeekNumber(new Date(2017, 0, 1), 0)).toBe(1);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 2), 0)).toBe(1);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 8), 0)).toBe(2);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 9), 0)).toBe(2);


expect(DateUtils.getWeekNumber(new Date(2020, 11, 28), 0)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 29), 0)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 30), 0)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 31), 0)).toBe(53);


expect(DateUtils.getWeekNumber(new Date(2022, 0, 3), 0)).toBe(1);
});


it('should be ok for monday 1 default', () => {
expect(DateUtils.getWeekNumber(new Date(2015, 0, 4), 1)).toBe(1);


expect(DateUtils.getWeekNumber(new Date(2017, 0, 1), 1)).toBe(52);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 2), 1)).toBe(1);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 8), 1)).toBe(1);
expect(DateUtils.getWeekNumber(new Date(2017, 0, 9), 1)).toBe(2);


expect(DateUtils.getWeekNumber(new Date(2020, 11, 28), 1)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 29), 1)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 30), 1)).toBe(53);
expect(DateUtils.getWeekNumber(new Date(2020, 11, 31), 1)).toBe(53);


expect(DateUtils.getWeekNumber(new Date(2022, 0, 3), 1)).toBe(1);
});
});