JavaScript: номер недели и дня в году, чётная/нечётная недели и другое
Сделал в спешке по практической необходимости, может, ещё кому пригодится. Скрипт позволяет не только вывести корректный номер недели по ИСО, но и скажет, сколько дней осталось до Нового года или определит номер недели в учебном заведении. Для последней цели его, конечно, может понадобиться изменить. Ясно также, что, как любой Javascript, скрипт время берёт с часов компьютера, они должны идти правильно.
В отличие от решения на PHP, где есть готовый формат, или в Excel, умеющем складывать дату и дни, в Яваскрипте возможности по операциям над датами существенно более ограничены.
Правда, в инете можно часто встретить мифический код вроде
var today = new Date(); var weekNumber = today.toLocaleFormat("%U"); alert (weekNumber);
Но такого метода как toLocaleFormat
нет в распространённом стандарте Javascript. К примеру,
под IE8, Chrome и Opera toLocaleFormat
вообще отсутствует.
Тем более, даже если метод есть (в Firefox), то
он локализует строку даты согласно настройкам операционной системы,
которые могут не совпадать с региональными настройками браузера
и приводить к непредсказуемым результатам.
Так что напишем всё "ручками".
Из приведённого ниже листинга имеет смысл обратить внимание на следующие функции:
delta (year)
- разница в днях текущей даты с новым годом для года year. Для 1 января даст значение 365 или 366, для 31 декабря - 1 день, т.к. округляет разницу меток времени вниз. Считая "рассстояние" от минувшего нового года и прибавляя к ответу 1, функцией можно выводить номер дня в году.getWeekNum (day,month,year)
- корректно, то есть, по стандарту ИСО определяет номер недели в году из диапазона 01-52 (описано тут; учтите, что 1 января вполне может быть 52-й неделей предыдущего года, это правильно).weekInfo ()
- после вывода информации о номере недели по ИСО пытается определять номер недели в учебном заведении, возможно, эта часть нуждается в переписывании, так как в неё заложены конкретные правила: изменены! см. ниже- нечётная/чётная (первая/вторая) неделя определяется номером недели в году по ИСО, то есть, первая по порядку неделя семестра может быть и "второй" (чётной) в смысле расписания;
- осенний семестр начинается 1 сентября, если это не Сб или Вс, тогда со следующего Пн;
- весенний семестр начинается через 20 недель после осеннего (15 недель учёбы + 3 сессии + 2 новогодних каникул).
Всё это можно поменять, почитав комментарии в теле функции.
Вот скрипт в работе и листинг:
В некоторые дни выводятся не все 4 строки, а только 2 или 3 (например, когда "осталось 0 дней" или не идёт никакой семестр).
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=Windows-1251"> <title>Номер недели</title> </head><body> <script type="text/javascript"> function goodwordform(k,w,o1,o2,o5) { //Корректное склонение окончания слова if ( (k%100>10 && k%100<20) || k%10>4 || k%10==0) w+=o5; else if (k%10==1) w+=o1; else w+=o2; return w; } function delta (year) { //Разница в днях текущей даты с новым годом для года year var date = new Date(); var newYear = new Date(year, 0, 1); return (Math.floor((date.getTime() - newYear.getTime())/1000/60/60/24)); } function newYearDays () { //Выводим инфо о ближайших Новых годах var date = new Date(); var Y = date.getFullYear(); var delta1 = delta (Y); document.getElementById('info').innerHTML = ''; if (delta1>0) document.getElementById('info').innerHTML += 'С Нового года '+goodwordform(delta1,'прош','ёл','ло','ло')+ ' '+delta1+' '+ goodwordform(delta1,'д','ень','ня','ней')+'<br>'+"\n"; var delta2 = Math.abs(delta (Y+1)); document.getElementById('info').innerHTML += 'До следующего Нового года '+goodwordform(delta2,'остал','ся','ось','ось')+ ' '+delta2+' '+ goodwordform(delta2,'д','ень','ня','ней')+'<br>'+"\n"; } var calStartDOW = 1; //С чего начинать неделю, в США день 0 (Вс), в мире день 1 (Пн) function getWeekNum (day,month,year) { //Корректно определяем номер недели в году if (calStartDOW == 0) day++; //Чтоб работало и для САЩ :) month++; //в JS месяцы нумеруются с нуля! var a = Math.floor((14-month) / 12); var y = year + 4800 - a; var m = month + 12 * a - 3; var J = day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400) - 32045; d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461; var L = Math.floor(d4 / 1460); var d1 = ((d4 - L) % 365) + L; var week = Math.floor(d1/7) + 1; if (week<10) week='0'+week; //Лидирующий ноль для недель 1-9 return week; } function numWeekSep (Y) { //Найти номер недели начала учебного года для года Y var date1 = new Date(Y,9-1,1); var wd1=date1.getDay(); var nw1=getWeekNum(1,9-1,Y); if (wd1==0 || wd1==6) nw1++; //Если 1 сент. - Сб или Вс, начнём со след. Пн return nw1; } function weekInfo () { //Выводим инфо о номере недели в году и семестре var date = new Date(); var Y = date.getFullYear(); var M = date.getMonth(); var D=date.getDate(); var NW=getWeekNum(D,M,Y); document.getElementById('info').innerHTML += 'Номер недели в году по стандарту ИСО: '+NW+'<br>'+"\n"; //Ниже - "неуниверсальная" часть функции //Определяем неделю начала учебного года и номер недели в осеннем семестре if (M>8-1) { //осенний семестр - с 1 сентября, если оно не Сб или Вс, тогда со след. Пн var nw1 = numWeekSep (Y); var num=NW-nw1+1; //номер недели семестра if (num>0 && num<16) { //Показываем не дольше 15 недель document.getElementById('info').innerHTML += 'Номер недели в осеннем семестре: '+num; if (NW%2==0) document.getElementById('info').innerHTML += ' (нижняя)'; //Верхняя/нижняя (нечетная/четная) else document.getElementById('info').innerHTML += ' (верхняя)'; //определяется номером недели по ISO document.getElementById('info').innerHTML += '<br>'+"\n"; //так что 1-я по порядку неделя может быть и "нижней" } } else if (M<7-1) { //весенний семестр - NED недель спустя, но не раньше января и кончится не позже июля var NED=20; var nw1 = numWeekSep (Y-1); //Ищем, когда прошло NED недель с начала учебного года (следующий Пн): var nw2=getWeekNum(28,12-1,Y-1); //28 дек. гарантированно относится к прошлому году var w28 = nw2-nw1+1; var date2 = new Date(Y-1,12-1,28); var wd28 = date2.getDay(); var t28 = date2.getTime(); while (!(wd28==1 && w28==NED)) { //ищем Пн, наступивший NED недель спустся после начала осеннего семестра t28+=1000*60*60*24; //прибавить сутки date2.setTime(t28); wd28 = date2.getDay(); if (wd28 == 1) w28++; } //Это будет начало весеннего семестра: var date3 = new Date(); date3.setTime(t28); var y2 = date3.getFullYear(); var m2 = date3.getMonth(); var d2 = date3.getDate(); var nw2=getWeekNum(d2,m2,y2); var num=NW-nw2+1; //номер недели семестра if (num>0 && num<21) { //Показываем не дольше 20 недель document.getElementById('info').innerHTML += 'Номер недели в весеннем семестре: '+num; if (NW%2==0) document.getElementById('info').innerHTML += ' (нижняя)'; else document.getElementById('info').innerHTML += ' (верхняя)'; document.getElementById('info').innerHTML += '<br>'+"\n"; } } } function main () { newYearDays (); weekInfo (); window.setTimeout('main()',60000); //Обновлять раз в минуту } document.writeln ('<p><small><span id="info"></span></small></p>'); main(); </script> <noscript>Извините, для работы приложения требуется включённый Javascript</noscript> </body></html>
P.S. Когда семестры стали опять 17(18) и 16(17) недель, поменялось только следующее и только в функции weekInfo
:
***** было if (num>0 && num<16) { //Показываем не дольше 15 недель ***** стало if (num>0 && num<18) { //Показываем не дольше 17 недель ***** ***** было var NED=20; ***** стало var NED=23; ***** ***** было if (num>0 && num<21) { //Показываем не дольше 20 недель ***** стало if (num>0 && num<18) { //Показываем не дольше 17 недель *****
P.P.S. Вот совсем короткий вариант кода, где мы для получения номера учебной недели отнимаем от номера недели в году стартовый номер недели по ISO (в нашем случае значение startWeek
) и пишем вывод в текстовый элемент HTML (у нас с id="weekinfo"
). Скрипт будет работать weeks
недель, эти 2 настройки приведены в начале кода.
<span id="weekinfo" style="font-size: 80%;"></span> <script> let startWeek = 4; let weeks = 17; Date.prototype.getWeek = function(year, month, day) { //Номер недели по ISO let date = new Date(year, month, day, 0, 0, 0, 0); date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); let week1 = new Date(date.getFullYear(), 0, 4); return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); } let date = new Date(); let year = date.getFullYear(); let mon = date.getMonth(); let day = date.getDate(); let wday = date.getDay(); let wdays = ['Вс','Пн','Вт','Ср','Чт','Пт','Сб']; let wnum = date.getWeek(year, mon, day) - startWeek + 1; if (wnum > 0 && wnum <= weeks) { document.getElementById('weekinfo').innerText = 'Сегодня ' + wdays[wday] + ', ' + day.toString().padStart(2,'0') + '.' + (mon+1).toString().padStart(2,'0') + '.' + year.toString() + ', '+ wnum + ' неделя'; } </script>
02.10.2013, 10:37 [19854 просмотра]