Получить текущую неделю, используя JavaScript без дополнительных библиотек?[ТАК примеры сломаны] - PullRequest
0 голосов
/ 20 октября 2018

enter image description here

Я создал элемент управления календаря и добавлял номера недель в качестве последнего штриха, и столкнулся с проблемой в каждом примере сценария, который я мог найти на SO и внеТАК (большая часть из которых скопирована с другой).

Проблема в том, что, когда даты попадают в неполные месяцы, подсчет недели, кажется, не работает, и либо продолжаются счета, когда в новоймесяц, или он думает, что последняя полная неделя в предыдущем месяце совпадает с номером первой полной новой недели в следующем месяце.

Ниже приведена визуальная демонстрация одной из библиотек (все они имеют своинеточности, так как они обычно основывают свои расчеты недели на фиксированном числе и строят оттуда):

enter image description here

Вы можете посмотреть кодовый блок здесь поскольку проект довольно сложный, у меня есть функция Date.prototype.getWeek в начале, чтобы поиграть с этим проще.Не стесняйтесь обмениваться любым кодом из примеров, найденных здесь, на SO, так как все они в конечном итоге выходят из строя в течение нескольких месяцев.

Некоторые из используемых расчетов:

При запуске самого последнего примера (2017) из "Получить неделю года в JavaScript, как в PHP", неделя, возвращаемая сейчас, равна 42. Когда вы смотрите в моем календаре, неделя в октябре сейчас отображается как 42, что является правильным согласно здесь https://www.epochconverter.com/weeks/2018.

Учитывая пример, целые недели разделяют один и тот же номер недели, поэтому я не понимаю, насколько точным может быть 42.

Date.prototype.getWeek = function (dowOffset) {
/*getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.epoch-calendar.com */

    dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; //default dowOffset to zero
    var newYear = new Date(this.getFullYear(),0,1);
    var day = newYear.getDay() - dowOffset; //the day of week the year begins on
    day = (day >= 0 ? day : day + 7);
    var daynum = Math.floor((this.getTime() - newYear.getTime() - 
    (this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
    var weeknum;
    //if the year starts before the middle of a week
    if(day < 4) {
        weeknum = Math.floor((daynum+day-1)/7) + 1;
        if(weeknum > 52) {
            nYear = new Date(this.getFullYear() + 1,0,1);
            nday = nYear.getDay() - dowOffset;
            nday = nday >= 0 ? nday : nday + 7;
            /*if the next year starts before the middle of
              the week, it is week #1 of that year*/
            weeknum = nday < 4 ? 1 : 53;
        }
    }
    else {
        weeknum = Math.floor((daynum+day-1)/7);
    }
    return weeknum;
};

Вот некоторый код (также пробовал это), это специфично для воскресенья (см. Внизу).Я также вставляю соответствующий фрагмент здесь:

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

1 Ответ

0 голосов
/ 20 октября 2018

Алгоритм заключается в использовании номера недели следующей субботы.Так что получите следующую субботу, а затем используйте ее год для 1 января. Если это не воскресенье, перейдите в предыдущее воскресенье.Затем получите количество недель оттуда.Это может показаться немного запутанным, но это всего лишь несколько строк кода.Большинство из следующих помощников для игры.

Надеюсь, комментариев достаточно, getWeekNumber возвращает массив [year, weekNumber].Протестировано с Календарем Mac OS X, который, кажется, использует ту же самую нумерацию недели.Пожалуйста, тщательно проверьте, особенно при переходе на летнее время.

/* Get week number in year based on:
 *  - week starts on Sunday
 *  - week number and year is that of the next Saturday,
 *    or current date if it's Saturday
 *    1st week of 2011 starts on Sunday 26 December, 2010
 *    1st week of 2017 starts on Sunday 1 January, 2017
 *
 * Calculations use UTC to avoid daylight saving issues.
 *
 * @param {Date} date - date to get week number of
 * @returns {number[]} year and week number
 */
function getWeekNumber(date) {
  // Copy date as UTC to avoid DST
  var d =  new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
  // Shift to the following Saturday to get the year
  d.setUTCDate(d.getUTCDate() + 6 - d.getUTCDay());
  // Get the first day of the year
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  yearStart.setUTCDate(yearStart.getUTCDate() - yearStart.getUTCDay());
  // Get difference between yearStart and d in milliseconds
  // Reduce to whole weeks
  return [d.getUTCFullYear(), (Math.ceil((d - yearStart) / 6.048e8))];
}

// Helper to format dates
function fDate(d) {
  var opts = {weekday:'short',month:'short',day:'numeric',year:'numeric'};
  return d.toLocaleString(undefined, opts);
}
// Parse yyyy-mm-dd as local
function pDate(s){
  var b = (s+'').split(/\D/);
  var d = new Date(b[0],b[1]-1,b[2]);
  return d.getMonth() == b[1]-1? d : new Date(NaN);
}
// Handle button click
function doButtonClick(){
  var d = pDate(document.getElementById('inp0').value);
  var span = document.getElementById('weekNumber');
  if (isNaN(d)) {
    span.textContent = 'Invalid date';
  } else {
    let [y,w] = getWeekNumber(d);
    span.textContent = `${fDate(d)} is in week ${w} of ${y}`;
  }
}
Date:<input id="inp0" placeholder="yyyy-mm-dd">
<button type="button" onclick="doButtonClick()">Get week number</button><br>
<span id="weekNumber"></span>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...